From f8b3a85b79b8eb74c37c839079ecbf8266a6f4ed Mon Sep 17 00:00:00 2001 From: msweet Date: Thu, 25 Feb 2010 00:52:27 +0000 Subject: [PATCH] Merge changes from CUPS 1.5svn-r9000. git-svn-id: svn+ssh://src.apple.com/svn/cups/easysw/current@1912 a1ca3aef-8c08-0410-bb20-df032aa958be --- CHANGES-1.4.txt | 17 +- CHANGES.txt | 6 +- Makedefs.in | 5 +- Makefile | 10 +- backend/Dependencies | 8 +- backend/Makefile | 33 +- backend/ieee1284.c | 5 +- backend/scsi-irix.c | 241 -- backend/scsi-linux.c | 260 -- backend/scsi.c | 231 -- backend/socket.c | 10 +- backend/usb-libusb.c | 3 +- cgi-bin/Dependencies | 1 + cgi-bin/Makefile | 26 +- cgi-bin/admin.c | 59 +- cgi-bin/cgi.h | 9 +- cgi-bin/libcupscgi.exp | 2 + cgi-bin/template.c | 25 +- cgi-bin/var.c | 273 +- conf/mime.convs.in | 3 +- conf/mime.types | 10 +- config-scripts/cups-common.m4 | 8 +- config-scripts/cups-defaults.m4 | 9 + config-scripts/cups-launchd.m4 | 5 +- config-scripts/cups-sharedlibs.m4 | 37 +- config-scripts/cups-ssl.m4 | 19 +- configure.in | 4 +- cups/Makefile | 98 +- cups/attr.c | 93 +- cups/debug.c | 2 +- cups/globals.c | 46 + cups/globals.h | 2 + cups/http.c | 56 +- cups/i18n.h | 8 +- cups/ipp-support.c | 2 +- cups/ipp.c | 37 +- cups/libcups.exp | 356 -- cups/libcups2.def | 8 +- cups/libcups_s.exp | 2 +- cups/options.c | 100 +- cups/page.c | 18 +- cups/ppd-private.h | 6 +- cups/tempfile.c | 4 +- data/HPGLprolog | 27 - data/Makefile | 3 +- doc/help/ref-cupsd-conf.html.in | 19 - doc/help/ref-page_log.html | 4 +- doc/help/spec-cmp.html | 77 +- driver/Dependencies | 2 +- driver/Makefile | 12 +- filter/Dependencies | 156 +- filter/Makefile | 32 +- filter/form-main.c | 53 - filter/form-ps.c | 40 - filter/form-tree.c | 615 ---- filter/form.h | 168 - filter/hpgl-attr.c | 479 --- filter/hpgl-char.c | 631 ---- filter/hpgl-config.c | 636 ---- filter/hpgl-input.c | 272 -- filter/hpgl-main.c | 269 -- filter/hpgl-polygon.c | 385 -- filter/hpgl-prolog.c | 369 -- filter/hpgl-vector.c | 773 ---- filter/hpgltops.h | 240 -- man/Makefile | 4 +- man/cupsd.conf.man.in | 8 +- man/ipp.test.man | 450 +++ man/ipptest.man | 89 + packaging/cups.list.in | 69 +- packaging/cups.spec.in | 9 +- ppdc/Makefile | 20 +- scheduler/Dependencies | 3 +- scheduler/Makefile | 35 +- scheduler/cert.c | 19 +- scheduler/classes.c | 16 +- scheduler/classes.h | 6 +- scheduler/client.c | 15 +- scheduler/conf.c | 9 +- scheduler/conf.h | 7 +- scheduler/cups-driverd.cxx | 3 +- scheduler/ipp.c | 66 +- scheduler/job.c | 8 +- scheduler/listen.c | 3 +- scheduler/main.c | 2 +- scheduler/printers.c | 31 +- scheduler/printers.h | 2 +- standards/Makefile | 8 +- standards/rfc2046.txt | 2467 +++++++++++++ standards/rfc3282.txt | 451 +++ standards/rfc4646.txt | 3307 +++++++++++++++++ systemv/Dependencies | 19 +- systemv/Makefile | 8 +- systemv/lppasswd.c | 31 +- systemv/lpstat.c | 24 +- templates/add-class.tmpl | 1 + templates/add-printer.tmpl | 1 + templates/add-rss-subscription.tmpl | 1 + templates/admin.tmpl | 13 +- templates/choose-device.tmpl | 1 + templates/choose-make.tmpl | 1 + templates/choose-model.tmpl | 1 + templates/choose-serial.tmpl | 1 + templates/choose-uri.tmpl | 1 + templates/class-confirm.tmpl | 2 +- templates/class.tmpl | 2 + templates/de/add-class.tmpl | 1 + templates/de/add-printer.tmpl | 1 + templates/de/add-rss-subscription.tmpl | 1 + templates/de/admin.tmpl | 15 +- templates/de/choose-device.tmpl | 1 + templates/de/choose-make.tmpl | 1 + templates/de/choose-model.tmpl | 3 +- templates/de/choose-serial.tmpl | 1 + templates/de/choose-uri.tmpl | 1 + templates/de/class-confirm.tmpl | 2 +- templates/de/class.tmpl | 2 + templates/de/edit-config.tmpl | 2 +- templates/de/job-move.tmpl | 1 + templates/de/jobs.tmpl | 10 +- templates/de/list-available-printers.tmpl | 2 +- templates/de/modify-class.tmpl | 1 + templates/de/modify-printer.tmpl | 1 + templates/de/printer-confirm.tmpl | 2 +- templates/de/printer.tmpl | 2 + templates/de/samba-export.tmpl | 1 + templates/de/set-printer-options-header.tmpl | 1 + templates/de/users.tmpl | 1 + templates/edit-config.tmpl | 2 +- templates/es/add-class.tmpl | 1 + templates/es/add-printer.tmpl | 1 + templates/es/add-rss-subscription.tmpl | 1 + templates/es/admin.tmpl | 15 +- templates/es/choose-device.tmpl | 1 + templates/es/choose-make.tmpl | 1 + templates/es/choose-model.tmpl | 1 + templates/es/choose-serial.tmpl | 1 + templates/es/choose-uri.tmpl | 1 + templates/es/class-confirm.tmpl | 2 +- templates/es/class.tmpl | 2 + templates/es/edit-config.tmpl | 2 +- templates/es/job-move.tmpl | 1 + templates/es/jobs.tmpl | 10 +- templates/es/list-available-printers.tmpl | 2 +- templates/es/modify-class.tmpl | 1 + templates/es/modify-printer.tmpl | 1 + templates/es/printer-confirm.tmpl | 2 +- templates/es/printer.tmpl | 2 + templates/es/samba-export.tmpl | 1 + templates/es/set-printer-options-header.tmpl | 1 + templates/es/users.tmpl | 1 + templates/eu/add-class.tmpl | 1 + templates/eu/add-printer.tmpl | 1 + templates/eu/add-rss-subscription.tmpl | 1 + templates/eu/admin.tmpl | 15 +- templates/eu/choose-device.tmpl | 1 + templates/eu/choose-make.tmpl | 1 + templates/eu/choose-model.tmpl | 1 + templates/eu/choose-serial.tmpl | 1 + templates/eu/choose-uri.tmpl | 1 + templates/eu/class-confirm.tmpl | 2 +- templates/eu/class.tmpl | 2 + templates/eu/edit-config.tmpl | 2 +- templates/eu/job-move.tmpl | 1 + templates/eu/jobs.tmpl | 10 +- templates/eu/list-available-printers.tmpl | 2 +- templates/eu/modify-class.tmpl | 1 + templates/eu/modify-printer.tmpl | 1 + templates/eu/printer-confirm.tmpl | 2 +- templates/eu/printer.tmpl | 2 + templates/eu/samba-export.tmpl | 1 + templates/eu/set-printer-options-header.tmpl | 1 + templates/eu/users.tmpl | 1 + templates/id/add-class.tmpl | 1 + templates/id/add-printer.tmpl | 1 + templates/id/add-rss-subscription.tmpl | 1 + templates/id/admin.tmpl | 15 +- templates/id/choose-device.tmpl | 1 + templates/id/choose-make.tmpl | 1 + templates/id/choose-model.tmpl | 1 + templates/id/choose-serial.tmpl | 1 + templates/id/choose-uri.tmpl | 1 + templates/id/class-confirm.tmpl | 2 +- templates/id/class.tmpl | 2 + templates/id/edit-config.tmpl | 2 +- templates/id/job-move.tmpl | 1 + templates/id/jobs.tmpl | 11 +- templates/id/list-available-printers.tmpl | 2 +- templates/id/modify-class.tmpl | 1 + templates/id/modify-printer.tmpl | 1 + templates/id/printer-confirm.tmpl | 2 +- templates/id/printer.tmpl | 2 + templates/id/samba-export.tmpl | 1 + templates/id/set-printer-options-header.tmpl | 1 + templates/id/users.tmpl | 1 + templates/it/add-class.tmpl | 1 + templates/it/add-printer.tmpl | 1 + templates/it/add-rss-subscription.tmpl | 1 + templates/it/admin.tmpl | 15 +- templates/it/choose-device.tmpl | 1 + templates/it/choose-make.tmpl | 1 + templates/it/choose-model.tmpl | 1 + templates/it/choose-serial.tmpl | 1 + templates/it/choose-uri.tmpl | 1 + templates/it/class-confirm.tmpl | 2 +- templates/it/class.tmpl | 2 + templates/it/edit-config.tmpl | 2 +- templates/it/job-move.tmpl | 1 + templates/it/jobs.tmpl | 10 +- templates/it/list-available-printers.tmpl | 2 +- templates/it/modify-class.tmpl | 1 + templates/it/modify-printer.tmpl | 1 + templates/it/printer-confirm.tmpl | 2 +- templates/it/printer.tmpl | 2 + templates/it/samba-export.tmpl | 1 + templates/it/set-printer-options-header.tmpl | 1 + templates/it/users.tmpl | 1 + templates/ja/add-class.tmpl | 1 + templates/ja/add-printer.tmpl | 1 + templates/ja/add-rss-subscription.tmpl | 1 + templates/ja/admin.tmpl | 15 +- templates/ja/choose-device.tmpl | 1 + templates/ja/choose-make.tmpl | 1 + templates/ja/choose-model.tmpl | 1 + templates/ja/choose-serial.tmpl | 1 + templates/ja/choose-uri.tmpl | 1 + templates/ja/class-confirm.tmpl | 2 +- templates/ja/class.tmpl | 2 + templates/ja/edit-config.tmpl | 2 +- templates/ja/job-move.tmpl | 1 + templates/ja/jobs.tmpl | 10 +- templates/ja/list-available-printers.tmpl | 2 +- templates/ja/modify-class.tmpl | 1 + templates/ja/modify-printer.tmpl | 1 + templates/ja/printer-confirm.tmpl | 2 +- templates/ja/printer.tmpl | 2 + templates/ja/samba-export.tmpl | 1 + templates/ja/set-printer-options-header.tmpl | 1 + templates/ja/users.tmpl | 1 + templates/job-move.tmpl | 1 + templates/jobs.tmpl | 11 +- templates/list-available-printers.tmpl | 2 +- templates/modify-class.tmpl | 1 + templates/modify-printer.tmpl | 1 + templates/pl/add-class.tmpl | 1 + templates/pl/add-printer.tmpl | 1 + templates/pl/add-rss-subscription.tmpl | 1 + templates/pl/admin.tmpl | 15 +- templates/pl/choose-device.tmpl | 1 + templates/pl/choose-make.tmpl | 1 + templates/pl/choose-model.tmpl | 1 + templates/pl/choose-serial.tmpl | 1 + templates/pl/choose-uri.tmpl | 1 + templates/pl/class-confirm.tmpl | 2 +- templates/pl/class.tmpl | 2 + templates/pl/edit-config.tmpl | 2 +- templates/pl/job-move.tmpl | 1 + templates/pl/jobs.tmpl | 10 +- templates/pl/list-available-printers.tmpl | 2 +- templates/pl/modify-class.tmpl | 1 + templates/pl/modify-printer.tmpl | 1 + templates/pl/printer-confirm.tmpl | 2 +- templates/pl/printer.tmpl | 2 + templates/pl/samba-export.tmpl | 1 + templates/pl/set-printer-options-header.tmpl | 1 + templates/pl/users.tmpl | 1 + templates/printer-confirm.tmpl | 2 +- templates/printer.tmpl | 2 + templates/ru/add-class.tmpl | 1 + templates/ru/add-printer.tmpl | 1 + templates/ru/add-rss-subscription.tmpl | 1 + templates/ru/admin.tmpl | 15 +- templates/ru/choose-device.tmpl | 1 + templates/ru/choose-make.tmpl | 1 + templates/ru/choose-model.tmpl | 1 + templates/ru/choose-serial.tmpl | 1 + templates/ru/choose-uri.tmpl | 1 + templates/ru/class-confirm.tmpl | 2 +- templates/ru/class.tmpl | 2 + templates/ru/edit-config.tmpl | 2 +- templates/ru/job-move.tmpl | 1 + templates/ru/jobs.tmpl | 10 +- templates/ru/list-available-printers.tmpl | 2 +- templates/ru/modify-class.tmpl | 1 + templates/ru/modify-printer.tmpl | 1 + templates/ru/printer-confirm.tmpl | 2 +- templates/ru/printer.tmpl | 2 + templates/ru/samba-export.tmpl | 1 + templates/ru/set-printer-options-header.tmpl | 1 + templates/ru/users.tmpl | 1 + templates/samba-export.tmpl | 1 + templates/set-printer-options-header.tmpl | 1 + templates/users.tmpl | 1 + test/Dependencies | 9 +- test/Makefile | 47 +- test/ipp-1.1.test | 742 ++++ test/ipp-2.0.test | 107 + test/ipp-2.1.test | 105 + test/ipptest.c | 3409 +++++++++++++++--- test/print-job-media-col.test | 39 + test/str-header.html | 13 +- vc2005/ipptest.vcproj | 199 + vcnet/config.h | 29 +- vcnet/cups.sln | 27 +- vcnet/ipptest.vcproj | 230 ++ vcnet/regex/COPYRIGHT | 20 + vcnet/regex/Makefile | 130 + vcnet/regex/README | 32 + vcnet/regex/WHATSNEW | 108 + vcnet/regex/cclass.h | 31 + vcnet/regex/cname.h | 102 + vcnet/regex/debug.c | 242 ++ vcnet/regex/debug.ih | 14 + vcnet/regex/engine.c | 1019 ++++++ vcnet/regex/engine.ih | 35 + vcnet/regex/main.c | 510 +++ vcnet/regex/main.ih | 19 + vcnet/regex/mkh | 76 + vcnet/regex/regcomp.c | 1603 ++++++++ vcnet/regex/regcomp.ih | 51 + vcnet/regex/regerror.c | 126 + vcnet/regex/regerror.ih | 12 + vcnet/regex/regex.3 | 509 +++ vcnet/regex/regex.7 | 235 ++ vcnet/regex/regex.h | 74 + vcnet/regex/regex2.h | 134 + vcnet/regex/regexec.c | 138 + vcnet/regex/regfree.c | 37 + vcnet/regex/split.c | 316 ++ vcnet/regex/tests | 477 +++ vcnet/regex/utils.h | 22 + 331 files changed, 18681 insertions(+), 7416 deletions(-) delete mode 100644 backend/scsi-irix.c delete mode 100644 backend/scsi-linux.c delete mode 100644 backend/scsi.c delete mode 100644 data/HPGLprolog delete mode 100644 filter/form-main.c delete mode 100644 filter/form-ps.c delete mode 100644 filter/form-tree.c delete mode 100644 filter/form.h delete mode 100644 filter/hpgl-attr.c delete mode 100644 filter/hpgl-char.c delete mode 100644 filter/hpgl-config.c delete mode 100644 filter/hpgl-input.c delete mode 100644 filter/hpgl-main.c delete mode 100644 filter/hpgl-polygon.c delete mode 100644 filter/hpgl-prolog.c delete mode 100644 filter/hpgl-vector.c delete mode 100644 filter/hpgltops.h create mode 100644 man/ipp.test.man create mode 100644 man/ipptest.man create mode 100644 standards/rfc2046.txt create mode 100644 standards/rfc3282.txt create mode 100644 standards/rfc4646.txt create mode 100644 test/ipp-1.1.test create mode 100644 test/ipp-2.0.test create mode 100644 test/ipp-2.1.test create mode 100644 test/print-job-media-col.test create mode 100644 vc2005/ipptest.vcproj create mode 100644 vcnet/ipptest.vcproj create mode 100644 vcnet/regex/COPYRIGHT create mode 100644 vcnet/regex/Makefile create mode 100644 vcnet/regex/README create mode 100644 vcnet/regex/WHATSNEW create mode 100644 vcnet/regex/cclass.h create mode 100644 vcnet/regex/cname.h create mode 100644 vcnet/regex/debug.c create mode 100644 vcnet/regex/debug.ih create mode 100644 vcnet/regex/engine.c create mode 100644 vcnet/regex/engine.ih create mode 100644 vcnet/regex/main.c create mode 100644 vcnet/regex/main.ih create mode 100644 vcnet/regex/mkh create mode 100644 vcnet/regex/regcomp.c create mode 100644 vcnet/regex/regcomp.ih create mode 100644 vcnet/regex/regerror.c create mode 100644 vcnet/regex/regerror.ih create mode 100644 vcnet/regex/regex.3 create mode 100644 vcnet/regex/regex.7 create mode 100644 vcnet/regex/regex.h create mode 100644 vcnet/regex/regex2.h create mode 100644 vcnet/regex/regexec.c create mode 100644 vcnet/regex/regfree.c create mode 100644 vcnet/regex/split.c create mode 100644 vcnet/regex/tests create mode 100644 vcnet/regex/utils.h diff --git a/CHANGES-1.4.txt b/CHANGES-1.4.txt index 2cdd32e73..ba74e6465 100644 --- a/CHANGES-1.4.txt +++ b/CHANGES-1.4.txt @@ -1,13 +1,26 @@ CHANGES-1.4.txt --------------- +CHANGES IN CUPS V1.4.4 + + - 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) - Localization updates (STR #3352, STR #3409, STR #3422, STR #3452, - STR #3473) - - Documentation update (STR #3451) + 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 diff --git a/CHANGES.txt b/CHANGES.txt index b8f215201..ee9680d74 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,8 +1,10 @@ -CHANGES.txt - 2009-11-19 +CHANGES.txt - 2010-02-12 ------------------------ CHANGES IN CUPS V1.5b1 + - 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. @@ -10,3 +12,5 @@ CHANGES IN CUPS V1.5b1 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/Makedefs.in b/Makedefs.in index e557871d2..d173cb7be 100644 --- a/Makedefs.in +++ b/Makedefs.in @@ -1,9 +1,9 @@ # # "$Id: Makedefs.in 7900 2008-09-03 13:47:57Z mike $" # -# Common makefile definitions for the Common UNIX Printing System (CUPS). +# Common makefile definitions for CUPS. # -# Copyright 2007-2009 by Apple Inc. +# 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 @@ -83,6 +83,7 @@ LIBCUPSDRIVER = @LIBCUPSDRIVER@ LIBCUPSIMAGE = @LIBCUPSIMAGE@ LIBCUPSMIME = @LIBCUPSMIME@ LIBCUPSPPDC = @LIBCUPSPPDC@ +LIBCUPSSTATIC = @LIBCUPSSTATIC@ LIBJPEG = @LIBJPEG@ LIBLDAP = @LIBLDAP@ LIBMALLOC = @LIBMALLOC@ diff --git a/Makefile b/Makefile index 9ccc12992..82c29d66c 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,9 @@ # # "$Id: Makefile 7961 2008-09-17 19:52:46Z mike $" # -# Top-level Makefile for the Common UNIX Printing System (CUPS). +# Top-level Makefile for CUPS. # -# Copyright 2007-2009 by Apple Inc. +# 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 @@ -142,10 +142,12 @@ depend: # (at least checker-231 is required for scan-build to work this way) # -.PHONY: clang +.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 # @@ -282,7 +284,7 @@ docset: apihelp # -# Make software distributions using EPM (http://www.easysw.com/epm/)... +# Make software distributions using EPM (http://www.epmhome.org/)... # EPMFLAGS = -v --output-dir dist $(EPMARCH) diff --git a/backend/Dependencies b/backend/Dependencies index 9051be05c..429398ab1 100644 --- a/backend/Dependencies +++ b/backend/Dependencies @@ -28,10 +28,6 @@ parallel.o: ../cups/ipp.h ../cups/http.h ../cups/ppd.h ../cups/array.h parallel.o: ../cups/file.h ../cups/language.h ../cups/debug.h ../cups/i18n.h parallel.o: ../cups/transcode.h ../cups/snmp-private.h ../cups/string.h parallel.o: ../config.h -scsi.o: ../cups/backend.h ../cups/versioning.h ../cups/cups.h ../cups/ipp.h -scsi.o: ../cups/http.h ../cups/ppd.h ../cups/array.h ../cups/file.h -scsi.o: ../cups/language.h ../cups/i18n.h ../cups/transcode.h -scsi.o: ../cups/string.h ../config.h serial.o: backend-private.h ../cups/backend.h ../cups/versioning.h serial.o: ../cups/sidechannel.h ../cups/ppd-private.h ../cups/cups.h serial.o: ../cups/ipp.h ../cups/http.h ../cups/ppd.h ../cups/array.h @@ -57,7 +53,9 @@ test1284.o: ../cups/backend.h ../cups/versioning.h ../cups/sidechannel.h test1284.o: ../cups/ppd-private.h ../cups/cups.h ../cups/ipp.h ../cups/http.h test1284.o: ../cups/ppd.h ../cups/array.h ../cups/file.h ../cups/language.h test1284.o: ../cups/debug.h ../cups/i18n.h ../cups/transcode.h -test1284.o: ../cups/snmp-private.h +test1284.o: ../cups/snmp-private.h ../cups/globals.h ../cups/string.h +test1284.o: ../cups/http-private.h ../cups/md5.h ../cups/ipp-private.h +test1284.o: ../cups/i18n.h testbackend.o: ../cups/string.h ../config.h ../cups/cups.h ../cups/ipp.h testbackend.o: ../cups/http.h ../cups/versioning.h ../cups/ppd.h testbackend.o: ../cups/array.h ../cups/file.h ../cups/language.h diff --git a/backend/Makefile b/backend/Makefile index 807b4c4e6..6b217462f 100644 --- a/backend/Makefile +++ b/backend/Makefile @@ -1,9 +1,9 @@ # # "$Id: Makefile 7924 2008-09-10 17:36:13Z mike $" # -# Backend makefile for the Common UNIX Printing System (CUPS). +# Backend makefile for CUPS. # -# Copyright 2007-2009 by Apple Inc. +# 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 @@ -17,12 +17,16 @@ include ../Makedefs +# +# Object files... +# + RBACKENDS = ipp lpd $(DNSSD_BACKEND) UBACKENDS = $(PAP) $(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 pap.o parallel.o scsi.o serial.o snmp.o \ +OBJS = ipp.o lpd.o dnssd.o pap.o parallel.o serial.o snmp.o \ socket.o test1284.o testbackend.o testsupplies.o usb.o @@ -134,9 +138,9 @@ uninstall: # test1284 # -test1284: test1284.o ../cups/libcups.a +test1284: test1284.o ../cups/$(LIBCUPSSTATIC) echo Linking $@... - $(CC) $(LDFLAGS) -o test1284 test1284.o ../cups/libcups.a \ + $(CC) $(LDFLAGS) -o test1284 test1284.o ../cups/$(LIBCUPSSTATIC) \ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) @@ -144,9 +148,9 @@ test1284: test1284.o ../cups/libcups.a # testbackend # -testbackend: testbackend.o ../cups/libcups.a +testbackend: testbackend.o ../cups/$(LIBCUPSSTATIC) echo Linking $@... - $(CC) $(LDFLAGS) -o testbackend testbackend.o ../cups/libcups.a \ + $(CC) $(LDFLAGS) -o testbackend testbackend.o ../cups/$(LIBCUPSSTATIC) \ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) @@ -154,10 +158,10 @@ testbackend: testbackend.o ../cups/libcups.a # testsupplies # -testsupplies: testsupplies.o libbackend.a ../cups/libcups.a +testsupplies: testsupplies.o libbackend.a ../cups/$(LIBCUPSSTATIC) echo Linking $@... $(CC) $(LDFLAGS) -o testsupplies testsupplies.o libbackend.a \ - ../cups/libcups.a $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) \ + ../cups/$(LIBCUPSSTATIC) $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) \ $(COMMONLIBS) $(LIBZ) @@ -221,17 +225,6 @@ parallel: parallel.o ../cups/$(LIBCUPS) libbackend.a $(CC) $(LDFLAGS) -o parallel parallel.o libbackend.a $(LIBS) -# -# scsi -# - -scsi: scsi.o ../cups/$(LIBCUPS) - echo Linking $@... - $(CC) $(LDFLAGS) -o scsi scsi.o $(LIBS) - -scsi.o: scsi.c scsi-irix.c scsi-linux.c - - # # serial # diff --git a/backend/ieee1284.c b/backend/ieee1284.c index 6b2d010f0..434db8739 100644 --- a/backend/ieee1284.c +++ b/backend/ieee1284.c @@ -26,6 +26,7 @@ */ #include "backend-private.h" +#include /* @@ -264,7 +265,7 @@ backendGetDeviceID( * Get the make, model, and serial numbers... */ - num_values = _ppdGet1284Values(device_id, &values); + num_values = _cupsGet1284Values(device_id, &values); if ((sern = cupsGetOption("SERIALNUMBER", num_values, values)) == NULL) if ((sern = cupsGetOption("SERN", num_values, values)) == NULL) @@ -354,7 +355,7 @@ backendGetMakeModel( * Look for the description field... */ - num_values = _ppdGet1284Values(device_id, &values); + num_values = _cupsGet1284Values(device_id, &values); if ((mdl = cupsGetOption("MODEL", num_values, values)) == NULL) mdl = cupsGetOption("MDL", num_values, values); diff --git a/backend/scsi-irix.c b/backend/scsi-irix.c deleted file mode 100644 index f4a60101c..000000000 --- a/backend/scsi-irix.c +++ /dev/null @@ -1,241 +0,0 @@ -/* - * "$Id: scsi-irix.c 6834 2007-08-22 18:29:25Z mike $" - * - * IRIX SCSI printer support for the Common UNIX Printing System (CUPS). - * - * Copyright 2007-2009 by Apple Inc. - * Copyright 2003-2005 by Easy Software Products, all rights reserved. - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the - * following conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 2. Redistributions in binary form must reproduce the - * above copyright notice, this list of conditions and - * the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * 3. All advertising materials mentioning features or use - * of this software must display the following - * acknowledgement: - * - * This product includes software developed by Easy - * Software Products. - * - * 4. The name of Easy Software Products may not be used to - * endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * Contents: - * - * list_devices() - List the available SCSI printer devices. - * print_device() - Print a file to a SCSI device. - */ - -/* - * Include necessary headers. - */ - -#include /* memcpy() and friends */ -#include /* SCSI interface stuff */ - - -/* - * 'list_devices()' - List the available SCSI printer devices. - */ - -void -list_devices(void) -{ - printf("direct scsi \"Unknown\" \"%s\"\n", - _cupsLangString(cupsLangDefault(), _("SCSI Printer"))); -} - - -/* - * 'print_device()' - Print a file to a SCSI device. - */ - -int /* O - Print status */ -print_device(const char *resource, /* I - SCSI device */ - int fd, /* I - File to print */ - int copies) /* I - Number of copies to print */ -{ - int scsi_fd; /* SCSI file descriptor */ - char buffer[8192]; /* Data buffer */ - int bytes; /* Number of bytes */ - int try; /* Current try */ - dsreq_t scsi_req; /* SCSI request */ - char scsi_cmd[6]; /* SCSI command data */ -#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) - struct sigaction action; /* Actions for POSIX signals */ -#endif /* HAVE_SIGACTION && !HAVE_SIGSET */ - - - /* - * Make sure we have a valid resource name... - */ - - if (strncmp(resource, "/dev/scsi/", 10) != 0) - { - _cupsLangPrintf(stderr, _("ERROR: Bad SCSI device file \"%s\"\n"), - resource); - return (CUPS_BACKEND_STOP); - } - - /* - * Open the SCSI device file... - */ - - fputs("STATE: +connecting-to-device\n", stderr); - - do - { - if ((scsi_fd = open(resource, O_RDWR | O_EXCL)) == -1) - { - if (getenv("CLASS") != NULL) - { - /* - * If the CLASS environment variable is set, the job was submitted - * to a class and not to a specific queue. In this case, we want - * to abort immediately so that the job can be requeued on the next - * available printer in the class. - */ - - _cupsLangPuts(stderr, - _("INFO: Unable to contact printer, queuing on next " - "printer in class...\n")); - - /* - * Sleep 5 seconds to keep the job from requeuing too rapidly... - */ - - sleep(5); - - return (1); - } - - if (errno != EAGAIN && errno != EBUSY) - { - _cupsLangPrintf(stderr, - _("ERROR: Unable to open device file \"%s\": %s\n"), - resource, strerror(errno)); - return (CUPS_BACKEND_FAILED); - } - else - { - _cupsLangPuts(stderr, - _("INFO: Printer busy; will retry in 30 seconds...\n")); - sleep(30); - } - } - } - while (scsi_fd == -1); - - 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 (fd != 0) - { -#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */ - sigset(SIGTERM, SIG_IGN); -#elif defined(HAVE_SIGACTION) - memset(&action, 0, sizeof(action)); - - sigemptyset(&action.sa_mask); - action.sa_handler = SIG_IGN; - sigaction(SIGTERM, &action, NULL); -#else - signal(SIGTERM, SIG_IGN); -#endif /* HAVE_SIGSET */ - } - - /* - * Copy the print file to the device... - */ - - while (copies > 0) - { - if (fd != 0) - lseek(fd, 0, SEEK_SET); - - while ((bytes = read(fd, buffer, sizeof(buffer))) > 0) - { - memset(&scsi_req, 0, sizeof(scsi_req)); - - scsi_req.ds_flags = DSRQ_WRITE; - scsi_req.ds_time = 60 * 1000; - scsi_req.ds_cmdbuf = scsi_cmd; - scsi_req.ds_cmdlen = 6; - scsi_req.ds_databuf = buffer; - scsi_req.ds_datalen = bytes; - - scsi_cmd[0] = 0x0a; /* Group 0 print command */ - scsi_cmd[1] = 0x00; - scsi_cmd[2] = bytes / 65536; - scsi_cmd[3] = bytes / 256; - scsi_cmd[4] = bytes; - scsi_cmd[5] = 0x00; - - for (try = 0; try < 10; try ++) - if (ioctl(scsi_fd, DS_ENTER, &scsi_req) < 0 || - scsi_req.ds_status != 0) - { - _cupsLangPrintf(stderr, - _("WARNING: SCSI command timed out (%d); " - "retrying...\n"), scsi_req.ds_status); - sleep(try + 1); - } - else - break; - - if (try >= 10) - { - _cupsLangPrintf(stderr, _("ERROR: Unable to send print data (%d)\n"), - scsi_req.ds_status); - close(scsi_fd); - return (CUPS_BACKEND_FAILED); - } - } - - copies --; - } - - /* - * Close the device and return... - */ - - close(fd); - - return (CUPS_BACKEND_OK); -} - - -/* - * End of "$Id: scsi-irix.c 6834 2007-08-22 18:29:25Z mike $". - */ diff --git a/backend/scsi-linux.c b/backend/scsi-linux.c deleted file mode 100644 index 934a626ec..000000000 --- a/backend/scsi-linux.c +++ /dev/null @@ -1,260 +0,0 @@ -/* - * "$Id: scsi-linux.c 6834 2007-08-22 18:29:25Z mike $" - * - * Linux SCSI printer support for the Common UNIX Printing System (CUPS). - * - * Copyright 2007-2009 by Apple Inc. - * Copyright 2003-2005 by Easy Software Products, all rights reserved. - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the - * following conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 2. Redistributions in binary form must reproduce the - * above copyright notice, this list of conditions and - * the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * 3. All advertising materials mentioning features or use - * of this software must display the following - * acknowledgement: - * - * This product includes software developed by Easy - * Software Products. - * - * 4. The name of Easy Software Products may not be used to - * endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * Contents: - * - * list_devices() - List the available SCSI printer devices. - * print_device() - Print a file to a SCSI device. - */ - -/* - * Include necessary headers. - */ - -#include -#include - - -/* - * We currently only support the Linux 2.4 generic SCSI interface. - */ - -#ifndef SG_DXFER_TO_DEV -/* - * Dummy functions that do nothing on unsupported platforms... - */ -void list_devices(void) {} -int print_device(const char *resource, int fd, int copies) { return (1); } -#else - - -/* - * 'list_devices()' - List the available SCSI printer devices. - */ - -void -list_devices(void) -{ - printf("direct scsi \"Unknown\" \"%s\"\n", - _cupsLangString(cupsLangDefault(), _("SCSI Printer"))); -} - - -/* - * 'print_device()' - Print a file to a SCSI device. - */ - -int /* O - Print status */ -print_device(const char *resource, /* I - SCSI device */ - int fd, /* I - File to print */ - int copies) /* I - Number of copies to print */ -{ - int scsi_fd; /* SCSI file descriptor */ - char buffer[8192]; /* Data buffer */ - int bytes; /* Number of bytes */ - int try; /* Current try */ - sg_io_hdr_t scsi_req; /* SCSI request */ - unsigned char scsi_cmd[6], /* SCSI command data */ - scsi_sense[32]; /* SCSI sense data */ -# if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) - struct sigaction action; /* Actions for POSIX signals */ -# endif /* HAVE_SIGACTION && !HAVE_SIGSET */ - - - /* - * Make sure we have a valid resource name... - */ - - if (strncmp(resource, "/dev/sg", 7) != 0) - { - _cupsLangPrintf(stderr, _("ERROR: Bad SCSI device file \"%s\"\n"), - resource); - return (CUPS_BACKEND_STOP); - } - - /* - * Open the SCSI device file... - */ - - fputs("STATE: +connecting-to-device\n", stderr); - - do - { - if ((scsi_fd = open(resource, O_RDWR | O_EXCL)) == -1) - { - if (getenv("CLASS") != NULL) - { - /* - * If the CLASS environment variable is set, the job was submitted - * to a class and not to a specific queue. In this case, we want - * to abort immediately so that the job can be requeued on the next - * available printer in the class. - */ - - _cupsLangPuts(stderr, - _("INFO: Unable to contact printer, queuing on next " - "printer in class...\n")); - - /* - * Sleep 5 seconds to keep the job from requeuing too rapidly... - */ - - sleep(5); - - return (CUPS_BACKEND_FAILED); - } - - if (errno != EAGAIN && errno != EBUSY) - { - _cupsLangPrintf(stderr, - _("ERROR: Unable to open device file \"%s\": %s\n"), - resource, strerror(errno)); - return (CUPS_BACKEND_FAILED); - } - else - { - _cupsLangPuts(stderr, - _("INFO: Printer busy; will retry in 30 seconds...\n")); - sleep(30); - } - } - } - while (scsi_fd == -1); - - 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 (fd != 0) - { -# ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */ - sigset(SIGTERM, SIG_IGN); -# elif defined(HAVE_SIGACTION) - memset(&action, 0, sizeof(action)); - - sigemptyset(&action.sa_mask); - action.sa_handler = SIG_IGN; - sigaction(SIGTERM, &action, NULL); -# else - signal(SIGTERM, SIG_IGN); -# endif /* HAVE_SIGSET */ - } - - /* - * Copy the print file to the device... - */ - - while (copies > 0) - { - if (fd != 0) - lseek(fd, 0, SEEK_SET); - - while ((bytes = read(fd, buffer, sizeof(buffer))) > 0) - { - memset(&scsi_req, 0, sizeof(scsi_req)); - - scsi_req.interface_id = 'S'; - scsi_req.dxfer_direction = SG_DXFER_TO_DEV; - scsi_req.cmd_len = 6; - scsi_req.mx_sb_len = sizeof(scsi_sense); - scsi_req.iovec_count = 0; - scsi_req.dxfer_len = bytes; - scsi_req.dxferp = buffer; - scsi_req.cmdp = scsi_cmd; - scsi_req.sbp = scsi_sense; - scsi_req.timeout = 60 * 1000; - - scsi_cmd[0] = 0x0a; /* Group 0 print command */ - scsi_cmd[1] = 0x00; - scsi_cmd[2] = bytes / 65536; - scsi_cmd[3] = bytes / 256; - scsi_cmd[4] = bytes; - scsi_cmd[5] = 0x00; - - for (try = 0; try < 10; try ++) - if (ioctl(scsi_fd, SG_IO, &scsi_req) < 0 || - scsi_req.status != 0) - { - _cupsLangPrintf(stderr, - _("WARNING: SCSI command timed out (%d); " - "retrying...\n"), scsi_req.status); - sleep(try + 1); - } - else - break; - - if (try >= 10) - { - _cupsLangPrintf(stderr, _("ERROR: Unable to send print data (%d)\n"), - scsi_req.status); - close(scsi_fd); - return (CUPS_BACKEND_FAILED); - } - } - - copies --; - } - - /* - * Close the device and return... - */ - - close(fd); - - return (CUPS_BACKEND_OK); -} -#endif /* !SG_DXFER_TO_DEV */ - - -/* - * End of "$Id: scsi-linux.c 6834 2007-08-22 18:29:25Z mike $". - */ diff --git a/backend/scsi.c b/backend/scsi.c deleted file mode 100644 index 7040d4bda..000000000 --- a/backend/scsi.c +++ /dev/null @@ -1,231 +0,0 @@ -/* - * "$Id: scsi.c 7193 2008-01-07 23:01:40Z mike $" - * - * SCSI printer backend for the Common UNIX Printing System (CUPS). - * - * Copyright 2007 by Apple Inc. - * Copyright 2003-2006 by Easy Software Products, all rights reserved. - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the - * following conditions are met: - * - * 1. Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * - * 2. Redistributions in binary form must reproduce the - * above copyright notice, this list of conditions and - * the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * 3. All advertising materials mentioning features or use - * of this software must display the following - * acknowledgement: - * - * This product includes software developed by Easy - * Software Products. - * - * 4. The name of Easy Software Products may not be used to - * endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * Contents: - * - * main() - Send a file to the specified SCSI printer. - */ - -/* - * Include necessary headers. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef WIN32 -# include -#else -# include -# include -# ifdef HAVE_SYS_IOCTL_H -# include -# endif /* HAVE_SYS_IOCTL_H */ -#endif /* WIN32 */ - - -/* - * Local functions... - */ - -void list_devices(void); -int print_device(const char *resource, int fd, int copies); - - -#if defined(__linux__) && defined(HAVE_SCSI_SG_H) -# include "scsi-linux.c" -#elif defined(__sgi) -# include "scsi-irix.c" -#else -/* - * Dummy functions that do nothing on unsupported platforms... - */ -void list_devices(void) {} -int print_device(const char *resource, int fd, int copies) { return (CUPS_BACKEND_FAILED); } -#endif /* __linux && HAVE_SCSI_SG_H */ - - -/* - * 'main()' - Send a file to the specified SCSI printer. - * - * Usage: - * - * printer-uri job-id user title copies options [file] - */ - -int /* O - Exit status */ -main(int argc, /* I - Number of command-line arguments (6 or 7) */ - char *argv[]) /* I - Command-line arguments */ -{ - char method[255], /* Method in URI */ - hostname[1024], /* Hostname */ - username[255], /* Username info (not used) */ - resource[1024], /* Resource info (device and options) */ - *options; /* Pointer to options */ - int port; /* Port number (not used) */ - int fp; /* Print file */ - int copies; /* Number of copies to print */ - int status; /* Exit status */ -#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) - struct sigaction action; /* Actions for POSIX signals */ -#endif /* HAVE_SIGACTION && !HAVE_SIGSET */ - - - /* - * Make sure status messages are not buffered... - */ - - setbuf(stderr, NULL); - - /* - * Ignore SIGPIPE signals... - */ - -#ifdef HAVE_SIGSET - sigset(SIGPIPE, SIG_IGN); -#elif defined(HAVE_SIGACTION) - memset(&action, 0, sizeof(action)); - action.sa_handler = SIG_IGN; - sigaction(SIGPIPE, &action, NULL); -#else - signal(SIGPIPE, SIG_IGN); -#endif /* HAVE_SIGSET */ - - /* - * Check command-line... - */ - - if (argc == 1) - { - list_devices(); - return (CUPS_BACKEND_OK); - } - else if (argc < 6 || argc > 7) - { - _cupsLangPrintf(stderr, - _("Usage: %s job-id user title copies options [file]\n"), - argv[0]); - return (CUPS_BACKEND_FAILED); - } - - /* - * If we have 7 arguments, print the file named on the command-line. - * Otherwise, send stdin instead... - */ - - if (argc == 6) - { - fp = 0; - copies = 1; - } - else - { - /* - * Try to open the print file... - */ - - if ((fp = open(argv[6], O_RDONLY)) < 0) - { - _cupsLangPrintf(stderr, - _("ERROR: Unable to open print file \"%s\": %s\n"), - argv[6], strerror(errno)); - 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'; - } - - /* - * Finally, send the print file... - */ - - status = print_device(resource, fp, copies); - - /* - * Close input file and return... - */ - - if (fp != 0) - close(fp); - - return (status); -} - - -/* - * End of "$Id: scsi.c 7193 2008-01-07 23:01:40Z mike $". - */ diff --git a/backend/socket.c b/backend/socket.c index 46d7f5eda..53f8dc0b5 100644 --- a/backend/socket.c +++ b/backend/socket.c @@ -3,7 +3,7 @@ * * AppSocket backend for the Common UNIX Printing System (CUPS). * - * Copyright 2007-2009 by Apple Inc. + * 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 @@ -72,9 +72,11 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ sep; /* Option separator */ int print_fd; /* Print file */ int copies; /* Number of copies to print */ - time_t start_time, /* Time of first connect */ - current_time, /* Current time */ + 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 */ @@ -388,6 +390,7 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ CUPS_LLCAST tbytes); } +#ifdef __APPLE__ /* * Wait up to 5 seconds to get any pending back-channel data... */ @@ -396,6 +399,7 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ while (wait_time >= time(¤t_time)) if (wait_bc(device_fd, wait_time - current_time) <= 0) break; +#endif /* __APPLE__ */ if (waiteof) { diff --git a/backend/usb-libusb.c b/backend/usb-libusb.c index 2efece7ef..e46e6ea9d 100644 --- a/backend/usb-libusb.c +++ b/backend/usb-libusb.c @@ -31,6 +31,7 @@ #include #include +#include /* @@ -514,7 +515,7 @@ make_device_uri( * Get the make, model, and serial numbers... */ - num_values = _ppdGet1284Values(device_id, &values); + num_values = _cupsGet1284Values(device_id, &values); if ((sern = cupsGetOption("SERIALNUMBER", num_values, values)) == NULL) if ((sern = cupsGetOption("SERN", num_values, values)) == NULL) diff --git a/cgi-bin/Dependencies b/cgi-bin/Dependencies index f018cd0a0..83c8d7e09 100644 --- a/cgi-bin/Dependencies +++ b/cgi-bin/Dependencies @@ -25,6 +25,7 @@ var.o: cgi-private.h cgi.h ../cups/cups.h ../cups/ipp.h ../cups/http.h var.o: ../cups/versioning.h ../cups/ppd.h ../cups/array.h ../cups/file.h var.o: ../cups/language.h ../cups/array.h help-index.h ../cups/debug.h var.o: ../cups/i18n.h ../cups/transcode.h ../cups/string.h ../config.h +var.o: ../cups/http.h ../cups/md5.h admin.o: cgi-private.h cgi.h ../cups/cups.h ../cups/ipp.h ../cups/http.h admin.o: ../cups/versioning.h ../cups/ppd.h ../cups/array.h ../cups/file.h admin.o: ../cups/language.h ../cups/array.h help-index.h ../cups/debug.h diff --git a/cgi-bin/Makefile b/cgi-bin/Makefile index 7b1abb6f9..f967f46aa 100644 --- a/cgi-bin/Makefile +++ b/cgi-bin/Makefile @@ -1,9 +1,9 @@ # # "$Id: Makefile 7871 2008-08-27 21:12:43Z mike $" # -# CGI makefile for the Common UNIX Printing System (CUPS). +# CGI makefile for CUPS. # -# Copyright 2007-2009 by Apple Inc. +# Copyright 2007-2010 by Apple Inc. # Copyright 1997-2006 by Easy Software Products. # # These coded instructions, statements, and computer programs are the @@ -118,7 +118,7 @@ install-exec: done if test "x$(SYMROOT)" != "x"; then \ $(INSTALL_DIR) $(SYMROOT); \ - for file in $(TARGETS); do \ + for file in $(CGIS); do \ cp $$file $(SYMROOT); \ done \ fi @@ -307,10 +307,10 @@ jobs.cgi: jobs.o ../Makedefs ../cups/$(LIBCUPS) $(LIBCUPSCGI) # makedocset # -makedocset: makedocset.o ../Makedefs libcupscgi.a ../cups/libcups.a +makedocset: makedocset.o ../Makedefs libcupscgi.a ../cups/$(LIBCUPSSTATIC) echo Linking $@... $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ makedocset.o libcupscgi.a \ - ../cups/libcups.a $(COMMONLIBS) $(SSLLIBS) $(DNSSDLIBS) \ + ../cups/$(LIBCUPSSTATIC) $(COMMONLIBS) $(SSLLIBS) $(DNSSDLIBS) \ $(LIBZ) $(LIBGSSAPI) @@ -327,10 +327,10 @@ printers.cgi: printers.o ../Makedefs ../cups/$(LIBCUPS) $(LIBCUPSCGI) # testcgi # -testcgi: testcgi.o ../Makedefs libcupscgi.a ../cups/libcups.a +testcgi: testcgi.o ../Makedefs libcupscgi.a ../cups/$(LIBCUPSSTATIC) echo Linking $@... $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testcgi.o libcupscgi.a \ - ../cups/libcups.a $(COMMONLIBS) $(SSLLIBS) $(DNSSDLIBS) \ + ../cups/$(LIBCUPSSTATIC) $(COMMONLIBS) $(SSLLIBS) $(DNSSDLIBS) \ $(LIBZ) $(LIBGSSAPI) echo Testing CGI API... ./testcgi @@ -340,10 +340,10 @@ testcgi: testcgi.o ../Makedefs libcupscgi.a ../cups/libcups.a # testhi # -testhi: testhi.o ../Makedefs libcupscgi.a ../cups/libcups.a +testhi: testhi.o ../Makedefs libcupscgi.a ../cups/$(LIBCUPSSTATIC) echo Linking $@... $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testhi.o libcupscgi.a \ - ../cups/libcups.a $(COMMONLIBS) $(SSLLIBS) $(DNSSDLIBS) \ + ../cups/$(LIBCUPSSTATIC) $(COMMONLIBS) $(SSLLIBS) $(DNSSDLIBS) \ $(LIBZ) $(LIBGSSAPI) echo Testing help index API... ./testhi @@ -353,9 +353,9 @@ testhi: testhi.o ../Makedefs libcupscgi.a ../cups/libcups.a # testtemplate # -testtemplate: testtemplate.o ../Makedefs libcupscgi.a ../cups/libcups.a +testtemplate: testtemplate.o ../Makedefs libcupscgi.a ../cups/$(LIBCUPSSTATIC) echo Linking $@... - $(CC) $(LDFLAGS) -o $@ testtemplate.o libcupscgi.a ../cups/libcups.a \ + $(CC) $(LDFLAGS) -o $@ testtemplate.o libcupscgi.a ../cups/$(LIBCUPSSTATIC) \ $(COMMONLIBS) $(SSLLIBS) $(DNSSDLIBS) $(LIBZ) $(LIBGSSAPI) @@ -363,10 +363,10 @@ testtemplate: testtemplate.o ../Makedefs libcupscgi.a ../cups/libcups.a # websearch # -websearch: websearch.o ../Makedefs libcupscgi.a ../cups/libcups.a +websearch: websearch.o ../Makedefs libcupscgi.a ../cups/$(LIBCUPSSTATIC) echo Linking $@... $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ websearch.o libcupscgi.a \ - ../cups/libcups.a $(COMMONLIBS) $(SSLLIBS) $(DNSSDLIBS) \ + ../cups/$(LIBCUPSSTATIC) $(COMMONLIBS) $(SSLLIBS) $(DNSSDLIBS) \ $(LIBZ) $(LIBGSSAPI) diff --git a/cgi-bin/admin.c b/cgi-bin/admin.c index ccf10de57..5617be224 100644 --- a/cgi-bin/admin.c +++ b/cgi-bin/admin.c @@ -3,7 +3,7 @@ * * Administration CGI for the Common UNIX Printing System (CUPS). * - * Copyright 2007-2009 by Apple Inc. + * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2007 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -48,6 +48,13 @@ #include +/* + * Local globals... + */ + +static int current_device = 0; /* Current device shown */ + + /* * Local functions... */ @@ -57,7 +64,7 @@ static void choose_device_cb(const char *device_class, const char *device_make_and_model, const char *device_uri, const char *device_location, - int *current_device); + 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); @@ -282,20 +289,35 @@ choose_device_cb( const char *device_make_and_model, /* I - Make and model */ const char *device_uri, /* I - Device URI */ const char *device_location, /* I - Location */ - int *current_device) /* I - Current device index */ + 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); + 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) ++; + current_device ++; } @@ -816,7 +838,6 @@ do_am_printer(http_t *http, /* I - HTTP connection */ const char *name, /* Pointer to class name */ *ptr; /* Pointer to CGI variable */ const char *title; /* Title of page */ - int current_device; /* Index of current device */ static int baudrates[] = /* Baud rates */ { 1200, @@ -977,20 +998,6 @@ do_am_printer(http_t *http, /* I - HTTP connection */ cgiSetVariable("CURRENT_DEVICE_SCHEME", uri); } - /* - * 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 (cgiSupportsMultipart()) - { - cgiStartMultipart(); - cgiStartHTML(title); - cgiCopyTemplateLang("choose-device.tmpl"); - cgiEndHTML(); - fflush(stdout); - } - /* * Scan for devices for up to 30 seconds... */ @@ -1000,7 +1007,7 @@ do_am_printer(http_t *http, /* I - HTTP connection */ current_device = 0; if (cupsGetDevices(http, 30, CUPS_INCLUDE_ALL, CUPS_EXCLUDE_NONE, (cups_device_cb_t)choose_device_cb, - ¤t_device) == IPP_OK) + (void *)title) == IPP_OK) { fputs("DEBUG: Got device list!\n", stderr); diff --git a/cgi-bin/cgi.h b/cgi-bin/cgi.h index 52368ee35..bceb5f519 100644 --- a/cgi-bin/cgi.h +++ b/cgi-bin/cgi.h @@ -1,9 +1,9 @@ /* * "$Id: cgi.h 6649 2007-07-11 21:46:42Z mike $" * - * CGI support library definitions. + * CGI support library definitions for CUPS. * - * Copyright 2007-2009 by Apple Inc. + * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2006 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -69,11 +69,12 @@ 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 char *cgiFormEncode(char *dst, const char *src, + size_t dstsize); extern void cgiFreeSearch(void *search); extern const char *cgiGetArray(const char *name, int element); extern void cgiGetAttributes(ipp_t *request, const char *tmpl); -extern char *cgiGetCookie(const char *name, char *buf, int buflen); +extern const 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); diff --git a/cgi-bin/libcupscgi.exp b/cgi-bin/libcupscgi.exp index 1997cdb10..3a26229d7 100644 --- a/cgi-bin/libcupscgi.exp +++ b/cgi-bin/libcupscgi.exp @@ -10,6 +10,7 @@ _cgiFormEncode _cgiFreeSearch _cgiGetArray _cgiGetAttributes +_cgiGetCookie _cgiGetFile _cgiGetIPPObjects _cgiGetSize @@ -24,6 +25,7 @@ _cgiRewriteURL _cgiSetArray _cgiSetIPPObjectVars _cgiSetIPPVars +_cgiSetCookie _cgiSetServerVersion _cgiSetSize _cgiSetVariable diff --git a/cgi-bin/template.c b/cgi-bin/template.c index 6e9cc5ec6..8ec653878 100644 --- a/cgi-bin/template.c +++ b/cgi-bin/template.c @@ -3,7 +3,7 @@ * * CGI template function. * - * Copyright 2007-2008 by Apple Inc. + * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2006 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -369,6 +369,20 @@ cgi_copy(FILE *out, /* I - Output file */ 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 { /* @@ -437,7 +451,14 @@ cgi_copy(FILE *out, /* I - Output file */ * Test for existance... */ - result = cgiGetArray(name, element) != NULL && outptr[0]; + 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 diff --git a/cgi-bin/var.c b/cgi-bin/var.c index 1467bd878..d376d1009 100644 --- a/cgi-bin/var.c +++ b/cgi-bin/var.c @@ -1,9 +1,9 @@ /* * "$Id: var.c 7460 2008-04-16 02:19:54Z mike $" * - * CGI form variable and array functions. + * CGI form variable and array functions for CUPS. * - * Copyright 2007-2009 by Apple Inc. + * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2005 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -14,25 +14,34 @@ * * Contents: * - * cgiCheckVariables() - Check for the presence of "required" variables. + * cgiCheckVariables() - Check for the presence of "required" + * variables. * cgiClearVariables() - Clear all form variables. - * cgiGetArray() - Get an element from a form array... - * cgiGetFile() - Get the file (if any) that was submitted in the form. + * 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"... + * 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... + * cgiSetVariable() - Set a CGI variable in the database. * cgi_add_variable() - Add a form variable. * cgi_compare_variables() - Compare two variables. - * cgi_find_variable() - Find a variable... - * cgi_initialize_get() - Initialize form variables using the GET method. - * cgi_initialize_multipart() - Initialize variables and file using the POST method. + * cgi_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_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. */ @@ -40,6 +49,15 @@ /*#define DEBUG*/ #include "cgi-private.h" #include +#include +#include + + +/* + * Session ID name + */ + +#define CUPS_SID "org.cups.sid" /* @@ -59,6 +77,8 @@ typedef struct /**** Form variable structure ****/ * 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; @@ -76,11 +96,13 @@ static void cgi_add_variable(const char *name, int element, 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); @@ -161,7 +183,7 @@ cgiClearVariables(void) /* - * 'cgiGetArray()' - Get an element from a form array... + * 'cgiGetArray()' - Get an element from a form array. */ const char * /* O - Element value or NULL */ @@ -181,6 +203,17 @@ cgiGetArray(const char *name, /* I - Name of array variable */ } +/* + * '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. */ @@ -210,10 +243,10 @@ cgiGetSize(const char *name) /* I - Name of variable */ /* - * 'cgiGetVariable()' - Get a CGI variable from the database... + * '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... + * array of values, returns the last element. */ const char * /* O - Value of variable */ @@ -237,14 +270,16 @@ cgiGetVariable(const char *name) /* I - Name of variable */ /* - * 'cgiInitialize()' - Initialize the CGI variable "database"... + * 'cgiInitialize()' - Initialize the CGI variable "database". */ int /* O - Non-zero if there was form data */ cgiInitialize(void) { - const char *method; /* Form posting method */ - const char *content_type; /* Content-Type of post data */ + const char *method, /* Form posting method */ + *content_type, /* Content-Type of post data */ + *cups_sid_cookie, /* SID cookie */ + *cups_sid_form; /* SID form variable */ /* @@ -267,6 +302,20 @@ cgiInitialize(void) 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)... */ @@ -290,9 +339,27 @@ cgiInitialize(void) boundary += 9; if (content_type && !strncmp(content_type, "multipart/form-data; ", 21)) - return (cgi_initialize_multipart(boundary)); + { + 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 (cgi_initialize_post()); + return (1); } else return (0); @@ -370,6 +437,38 @@ cgiSetArray(const char *name, /* I - Name of variable */ } +/* + * '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. */ @@ -418,7 +517,7 @@ cgiSetSize(const char *name, /* I - Name of variable */ /* - * 'cgiSetVariable()' - Set a CGI variable in the database... + * 'cgiSetVariable()' - Set a CGI variable in the database. * * If the variable is an array, this truncates the array to a single element. */ @@ -514,7 +613,7 @@ cgi_compare_variables( /* - * 'cgi_find_variable()' - Find a variable... + * 'cgi_find_variable()' - Find a variable. */ static _cgi_var_t * /* O - Variable pointer or NULL */ @@ -533,6 +632,91 @@ cgi_find_variable(const char *name) /* I - Name of variable */ } +/* + * '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. */ @@ -562,7 +746,8 @@ cgi_initialize_get(void) /* - * 'cgi_initialize_multipart()' - Initialize variables and file using the POST method. + * 'cgi_initialize_multipart()' - Initialize variables and file using the POST + * method. * * TODO: Update to support files > 2GB. */ @@ -874,7 +1059,7 @@ cgi_initialize_string(const char *data) /* I - Form data string */ char *s, /* Pointer to current form string */ ch, /* Temporary character */ name[255], /* Name of form variable */ - value[65536]; /* Variable value... */ + value[65536]; /* Variable value */ /* @@ -1014,6 +1199,46 @@ cgi_passwd(const char *prompt) /* I - Prompt (not used) */ } +/* + * '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), "/", server_name, 0, 0); + + return (cupsGetOption(CUPS_SID, num_cookies, cookies)); +} + + /* * 'cgi_sort_variables()' - Sort all form variables for faster lookup. */ diff --git a/conf/mime.convs.in b/conf/mime.convs.in index a141b5c09..9e6796ad4 100644 --- a/conf/mime.convs.in +++ b/conf/mime.convs.in @@ -7,7 +7,7 @@ # # MIME converts file for the Common UNIX Printing System (CUPS). # -# Copyright 2007-2009 by Apple Inc. +# Copyright 2007-2010 by Apple Inc. # Copyright 1997-2007 by Easy Software Products. # # These coded instructions, statements, and computer programs are the @@ -40,7 +40,6 @@ application/pdf application/vnd.cups-postscript 66 pdftops application/postscript application/vnd.cups-postscript 66 pstops -application/vnd.hp-HPGL application/postscript 66 hpgltops application/x-cshell application/postscript 33 texttops application/x-csource application/postscript 33 texttops application/x-perl application/postscript 33 texttops diff --git a/conf/mime.types b/conf/mime.types index 8ef1c06a9..dd28daaf6 100644 --- a/conf/mime.types +++ b/conf/mime.types @@ -7,7 +7,7 @@ # VERSIONS OF CUPS. Instead, create a "local.types" file that # reflects your local configuration changes. # -# Copyright 2007-2009 by Apple Inc. +# Copyright 2007-2010 by Apple Inc. # Copyright 1997-2007 by Easy Software Products. # # These coded instructions, statements, and computer programs are the @@ -79,14 +79,6 @@ application/postscript ai eps ps string(0,%!) string(0,<04>%!) \ contains(0,4096,"LANGUAGE = POSTSCRIPT") \ (contains(0,4096,<0a>%!) + \ !contains(0,4096,"ENTER LANGUAGE"))) -application/vnd.hp-HPGL hpgl \ - string(0,<1B>E<1B>%0B) \ - string(0,<1B>%-1B) string(0,<201B>)\ - string(0,BP;) string(0,IN;) string(0,DF;) \ - string(0,BPINPS;) \ - (contains(0,128,<1B>%-12345X) + \ - (contains(0,4096,"LANGUAGE=HPGL") \ - contains(0,4096,"LANGUAGE = HPGL"))) ######################################################################## # diff --git a/config-scripts/cups-common.m4 b/config-scripts/cups-common.m4 index d47f14278..361661981 100644 --- a/config-scripts/cups-common.m4 +++ b/config-scripts/cups-common.m4 @@ -281,15 +281,14 @@ AC_SUBST(DBUS_NOTIFIERLIBS) dnl Extra platform-specific libraries... CUPS_DEFAULT_PRINTOPERATOR_AUTH="@SYSTEM" CUPS_SYSTEM_AUTHKEY="" -FONTS="fonts" -LEGACY_BACKENDS="parallel scsi" +LEGACY_BACKENDS="parallel" case $uname in Darwin*) LEGACY_BACKENDS="" BACKLIBS="$BACKLIBS -framework IOKit" - CUPSDLIBS="$CUPSDLIBS -sectorder __TEXT __text cupsd.order -e start -framework IOKit -framework SystemConfiguration -weak_framework ApplicationServices" - LIBS="-framework SystemConfiguration -framework CoreFoundation $LIBS" + CUPSDLIBS="$CUPSDLIBS -sectorder __TEXT __text cupsd.order -e start -framework IOKit -weak_framework ApplicationServices" + LIBS="-framework SystemConfiguration -framework CoreFoundation -framework Security $LIBS" dnl Check for framework headers... AC_CHECK_HEADER(CoreFoundation/CoreFoundation.h,AC_DEFINE(HAVE_COREFOUNDATION_H)) @@ -347,7 +346,6 @@ 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(FONTS) AC_SUBST(LEGACY_BACKENDS) dnl diff --git a/config-scripts/cups-defaults.m4 b/config-scripts/cups-defaults.m4 index 4f455a823..2864cbad4 100644 --- a/config-scripts/cups-defaults.m4 +++ b/config-scripts/cups-defaults.m4 @@ -447,6 +447,15 @@ fi AC_SUBST(BANNERTOPS) AC_SUBST(TEXTTOPS) +dnl Fonts +if test "x$BANNERTOPS" = x -a "x$TEXTTOPS" = x; then + FONTS="" +else + FONTS="fonts" +fi + +AC_SUBST(FONTS) + dnl dnl End of "$Id: cups-defaults.m4 7959 2008-09-17 19:30:58Z mike $". dnl diff --git a/config-scripts/cups-launchd.m4 b/config-scripts/cups-launchd.m4 index a6a893235..23a229516 100644 --- a/config-scripts/cups-launchd.m4 +++ b/config-scripts/cups-launchd.m4 @@ -1,9 +1,9 @@ dnl dnl "$Id: cups-launchd.m4 6649 2007-07-11 21:46:42Z mike $" dnl -dnl launchd stuff for the Common UNIX Printing System (CUPS). +dnl launchd stuff for CUPS. dnl -dnl Copyright 2007-2009 by Apple Inc. +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 @@ -35,7 +35,6 @@ if test x$enable_launchd != xno; then esac fi -AC_DEFINE_UNQUOTED(CUPS_DEFAULT_LAUNCHD_CONF, "$DEFAULT_LAUNCHD_CONF") AC_SUBST(DEFAULT_LAUNCHD_CONF) AC_SUBST(LAUNCHDLIBS) diff --git a/config-scripts/cups-sharedlibs.m4 b/config-scripts/cups-sharedlibs.m4 index 09c55f897..4363bfce2 100644 --- a/config-scripts/cups-sharedlibs.m4 +++ b/config-scripts/cups-sharedlibs.m4 @@ -1,9 +1,9 @@ dnl dnl "$Id: cups-sharedlibs.m4 7630 2008-06-09 22:31:44Z mike $" dnl -dnl Shared library support for the Common UNIX Printing System (CUPS). +dnl Shared library support for CUPS. dnl -dnl Copyright 2007-2009 by Apple Inc. +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 @@ -18,10 +18,14 @@ 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="libcups.so.2" + LIBCUPS="lib$cupsbase.so.2" LIBCUPSCGI="libcupscgi.so.1" LIBCUPSDRIVER="libcupsdriver.so.1" LIBCUPSIMAGE="libcupsimage.so.2" @@ -32,7 +36,7 @@ if test x$enable_shared != xno; then DSOFLAGS="$DSOFLAGS -Wl,-h\`basename \$@\` -G \$(OPTIM)" ;; UNIX_S*) - LIBCUPS="libcups.so.2" + LIBCUPS="lib$cupsbase.so.2" LIBCUPSCGI="libcupscgi.so.1" LIBCUPSDRIVER="libcupsdriver.so.1" LIBCUPSIMAGE="libcupsimage.so.2" @@ -45,7 +49,7 @@ if test x$enable_shared != xno; then HP-UX*) case "$uarch" in ia64) - LIBCUPS="libcups.so.2" + LIBCUPS="lib$cupsbase.so.2" LIBCUPSCGI="libcupscgi.so.1" LIBCUPSDRIVER="libcupsdriver.so.1" LIBCUPSIMAGE="libcupsimage.so.2" @@ -56,7 +60,7 @@ if test x$enable_shared != xno; then DSOFLAGS="$DSOFLAGS -Wl,-b,-z,+h,\`basename \$@\`" ;; *) - LIBCUPS="libcups.sl.2" + LIBCUPS="lib$cupsbase.sl.2" LIBCUPSCGI="libcupscgi.sl.1" LIBCUPSDRIVER="libcupsdriver.sl.1" LIBCUPSIMAGE="libcupsimage.sl.2" @@ -69,7 +73,7 @@ if test x$enable_shared != xno; then esac ;; IRIX) - LIBCUPS="libcups.so.2" + LIBCUPS="lib$cupsbase.so.2" LIBCUPSCGI="libcupscgi.so.1" LIBCUPSDRIVER="libcupsdriver.so.1" LIBCUPSIMAGE="libcupsimage.so.2" @@ -80,7 +84,7 @@ if test x$enable_shared != xno; then DSOFLAGS="$DSOFLAGS -set_version,sgi2.6,-soname,\`basename \$@\` -shared \$(OPTIM)" ;; OSF1* | Linux | GNU | *BSD*) - LIBCUPS="libcups.so.2" + LIBCUPS="lib$cupsbase.so.2" LIBCUPSCGI="libcupscgi.so.1" LIBCUPSDRIVER="libcupsdriver.so.1" LIBCUPSIMAGE="libcupsimage.so.2" @@ -91,7 +95,7 @@ if test x$enable_shared != xno; then DSOFLAGS="$DSOFLAGS -Wl,-soname,\`basename \$@\` -shared \$(OPTIM)" ;; Darwin*) - LIBCUPS="libcups.2.dylib" + LIBCUPS="lib$cupsbase.2.dylib" LIBCUPSCGI="libcupscgi.1.dylib" LIBCUPSDRIVER="libcupsdriver.1.dylib" LIBCUPSIMAGE="libcupsimage.2.dylib" @@ -102,7 +106,8 @@ if test x$enable_shared != xno; then DSOFLAGS="$DSOFLAGS -dynamiclib -single_module -lc" ;; AIX*) - LIBCUPS="libcups_s.a" + LIBCUPS="lib${cupsbase}_s.a" + LIBCUPSBASE="${cupsbase}_s" LIBCUPSCGI="libcupscgi_s.a" LIBCUPSDRIVER="libcupsdriver_s.a" LIBCUPSIMAGE="libcupsimage_s.a" @@ -115,7 +120,7 @@ if test x$enable_shared != xno; then *) echo "Warning: shared libraries may not be supported. Trying -shared" echo " option with compiler." - LIBCUPS="libcups.so.2" + LIBCUPS="lib$cupsbase.so.2" LIBCUPSCGI="libcupscgi.so.1" LIBCUPSDRIVER="libcupsdriver.so.1" LIBCUPSIMAGE="libcupsimage.so.2" @@ -128,7 +133,7 @@ if test x$enable_shared != xno; then esac else PICFLAG=0 - LIBCUPS="libcups.a" + LIBCUPS="lib$cupsbase.a" LIBCUPSCGI="libcupscgi.a" LIBCUPSDRIVER="libcupsdriver.a" LIBCUPSIMAGE="libcupsimage.a" @@ -149,21 +154,23 @@ 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/libcups.a" + LINKCUPS="../cups/lib$cupsbase.a" LINKCUPSIMAGE="../filter/libcupsimage.a" else if test $uname = AIX; then - LINKCUPS="-lcups_s" + LINKCUPS="-l${cupsbase}_s" LINKCUPSIMAGE="-lcupsimage_s" else - LINKCUPS="-lcups" + LINKCUPS="-l${cupsbase}" LINKCUPSIMAGE="-lcupsimage" fi fi diff --git a/config-scripts/cups-ssl.m4 b/config-scripts/cups-ssl.m4 index 7e20ecd90..b0139c78c 100644 --- a/config-scripts/cups-ssl.m4 +++ b/config-scripts/cups-ssl.m4 @@ -1,9 +1,9 @@ dnl dnl "$Id: cups-ssl.m4 7241 2008-01-22 22:34:52Z mike $" dnl -dnl OpenSSL/GNUTLS stuff for the Common UNIX Printing System (CUPS). +dnl OpenSSL/GNUTLS stuff for CUPS. dnl -dnl Copyright 2007-2009 by Apple Inc. +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 @@ -26,13 +26,14 @@ AC_ARG_WITH(openssl-includes, [ --with-openssl-includes set directory for OpenS SSLFLAGS="" SSLLIBS="" +have_ssl=0 if test x$enable_ssl != xno; then dnl Look for CDSA... - if test "x${SSLLIBS}" = "x" -a "x${enable_cdsassl}" != "xno"; then + if test $have_ssl = 0 -a "x${enable_cdsassl}" != "xno"; then if test $uname = Darwin; then AC_CHECK_HEADER(Security/SecureTransport.h, [ - SSLLIBS="-framework CoreFoundation -framework Security" + have_ssl=1 AC_DEFINE(HAVE_SSL) AC_DEFINE(HAVE_CDSASSL) @@ -58,9 +59,10 @@ if test x$enable_ssl != xno; then fi dnl Then look for GNU TLS... - if test "x${SSLLIBS}" = "x" -a "x${enable_gnutls}" != "xno" -a "x$PKGCONFIG" != x; then + if test $have_ssl = 0 -a "x${enable_gnutls}" != "xno" -a "x$PKGCONFIG" != x; then AC_PATH_PROG(LIBGNUTLSCONFIG,libgnutls-config) if $PKGCONFIG --exists gnutls; then + have_ssl=1 SSLLIBS=`$PKGCONFIG --libs gnutls` SSLFLAGS=`$PKGCONFIG --cflags gnutls` AC_DEFINE(HAVE_SSL) @@ -69,7 +71,7 @@ if test x$enable_ssl != xno; then fi dnl Check for the OpenSSL library last... - if test "x${SSLLIBS}" = "x" -a "x${enable_openssl}" != "xno"; then + 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... @@ -87,7 +89,8 @@ if test x$enable_ssl != xno; then "-lcrypto -lRSAglue -lrsaref" do AC_CHECK_LIB(ssl,SSL_new, - [SSLFLAGS="-DOPENSSL_DISABLE_OLD_DES_SUPPORT" + [have_ssl=1 + SSLFLAGS="-DOPENSSL_DISABLE_OLD_DES_SUPPORT" SSLLIBS="-lssl $libcrypto" AC_DEFINE(HAVE_SSL) AC_DEFINE(HAVE_LIBSSL)],, @@ -102,7 +105,7 @@ if test x$enable_ssl != xno; then fi fi -if test "x$SSLLIBS" != x; then +if test $have_ssl = 1; then AC_MSG_RESULT([ Using SSLLIBS="$SSLLIBS"]) AC_MSG_RESULT([ Using SSLFLAGS="$SSLFLAGS"]) fi diff --git a/configure.in b/configure.in index 91f193d1d..34198e412 100644 --- a/configure.in +++ b/configure.in @@ -1,9 +1,9 @@ dnl dnl "$Id: configure.in 7833 2008-08-04 20:55:13Z mike $" dnl -dnl Configuration script for the Common UNIX Printing System (CUPS). +dnl Configuration script for CUPS. dnl -dnl Copyright 2007 by Apple Inc. +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 diff --git a/cups/Makefile b/cups/Makefile index 088611143..b7e9a8d8a 100644 --- a/cups/Makefile +++ b/cups/Makefile @@ -1,9 +1,9 @@ # # "$Id: Makefile 7871 2008-08-27 21:12:43Z mike $" # -# API library Makefile for the Common UNIX Printing System (CUPS). +# API library Makefile for CUPS. # -# Copyright 2007-2009 by Apple Inc. +# 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 @@ -113,10 +113,10 @@ HEADERS = \ # LIBTARGETS = \ + $(LIBCUPSSTATIC) \ $(LIBCUPS) \ $(LIB32CUPS) \ - $(LIB64CUPS) \ - libcups.a + $(LIB64CUPS) UNITTARGETS = \ testadmin \ @@ -140,7 +140,7 @@ TARGETS = \ # Make all targets... # -all: $(TARGETS) +all: $(TARGETS) # @@ -237,9 +237,9 @@ install-libs: $(INSTALLSTATIC) $(INSTALL32) $(INSTALL64) installstatic: $(INSTALL_DIR) -m 755 $(LIBDIR) - $(INSTALL_LIB) -m 755 libcups.a $(LIBDIR) - $(RANLIB) $(LIBDIR)/libcups.a - $(CHMOD) 555 $(LIBDIR)/libcups.a + $(INSTALL_LIB) -m 755 $(LIBCUPSSTATIC) $(LIBDIR) + $(RANLIB) $(LIBDIR)/$(LIBCUPSSTATIC) + $(CHMOD) 555 $(LIBDIR)/$(LIBCUPSSTATIC) install32bit: echo Installing libraries in $(LIB32DIR)... @@ -326,17 +326,21 @@ libcups.so.2 libcups.sl.2: $(LIBOBJS) # libcups.2.dylib # -libcups.2.dylib: $(LIBOBJS) $(LIBCUPSORDER) libcups.exp +libcups.2.dylib: $(LIBOBJS) $(LIBCUPSORDER) + echo Creating export list for $@... + nm $(LIBOBJS) 2>/dev/null | grep "T _" | awk '{print $$3}' | \ + grep -v -e '^(_cupsConnect|_cupsSetDefaults|_cupsSetHTTPError|_cupsUserDefault|_httpWait)$$' | \ + sort >t.exp echo Linking $@... $(DSO) $(ARCHFLAGS) $(DSOFLAGS) -o $@ \ -install_name $(libdir)/$@ \ -current_version 2.8.0 \ -compatibility_version 2.0.0 \ - -exported_symbols_list libcups.exp \ + -exported_symbols_list t.exp \ -sectorder __TEXT __text $(LIBCUPSORDER) \ $(LIBOBJS) $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) \ $(COMMONLIBS) $(LIBZ) - $(RM) libcups.dylib + $(RM) libcups.dylib t.exp $(LN) $@ libcups.dylib @@ -375,37 +379,13 @@ libcups.a: $(LIBOBJS) $(RANLIB) $@ -# -# CUPS language bindings for various scripting languages... -# -# NOTE: Not currently used or functional - see the scripting/php directory -# for the hand-written bindings... -# - -phpcups.so: $(LIBCUPS) php_cups_wrap.o - echo Linking $@... - if test `uname` = Darwin; then \ - DSOFLAGS="-bundle -flat_namespace -undefined suppress"; \ - else \ - DSOFLAGS="$(DSOFLAGS)"; \ - fi; \ - $(DSO) $$DSOFLAGS -o $@ php_cups_wrap.o $(LIBS) `php-config --ldflags --libs` - -php_cups_wrap.o: php_cups_wrap.c - echo Compiling $<... - $(CC) $(CFLAGS) `php-config --includes` -c $< -php_cups_wrap.c: cups.h - echo Creating $< using SWIG... - swig -php -o $@ -module cups cups.h - - # # testadmin (dependency on static CUPS library is intentional) # -testadmin: testadmin.o libcups.a +testadmin: testadmin.o $(LIBCUPSSTATIC) echo Linking $@... - $(CC) $(LDFLAGS) -o $@ testadmin.o libcups.a \ + $(CC) $(LDFLAGS) -o $@ testadmin.o $(LIBCUPSSTATIC) \ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) @@ -413,9 +393,9 @@ testadmin: testadmin.o libcups.a # testarray (dependency on static CUPS library is intentional) # -testarray: testarray.o libcups.a +testarray: testarray.o $(LIBCUPSSTATIC) echo Linking $@... - $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testarray.o libcups.a \ + $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testarray.o $(LIBCUPSSTATIC) \ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) echo Running array API tests... ./testarray @@ -425,9 +405,9 @@ testarray: testarray.o libcups.a # testconflicts (dependency on static CUPS library is intentional) # -testconflicts: testconflicts.o libcups.a +testconflicts: testconflicts.o $(LIBCUPSSTATIC) echo Linking $@... - $(CC) $(LDFLAGS) -o $@ testconflicts.o libcups.a \ + $(CC) $(LDFLAGS) -o $@ testconflicts.o $(LIBCUPSSTATIC) \ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) @@ -435,9 +415,9 @@ testconflicts: testconflicts.o libcups.a # testcups (dependency on static CUPS library is intentional) # -testcups: testcups.o libcups.a +testcups: testcups.o $(LIBCUPSSTATIC) echo Linking $@... - $(CC) $(LDFLAGS) -o $@ testcups.o libcups.a \ + $(CC) $(LDFLAGS) -o $@ testcups.o $(LIBCUPSSTATIC) \ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) @@ -445,9 +425,9 @@ testcups: testcups.o libcups.a # testfile (dependency on static CUPS library is intentional) # -testfile: testfile.o libcups.a +testfile: testfile.o $(LIBCUPSSTATIC) echo Linking $@... - $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testfile.o libcups.a \ + $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testfile.o $(LIBCUPSSTATIC) \ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) echo Running file API tests... ./testfile @@ -457,9 +437,9 @@ testfile: testfile.o libcups.a # testhttp (dependency on static CUPS library is intentional) # -testhttp: testhttp.o libcups.a +testhttp: testhttp.o $(LIBCUPSSTATIC) echo Linking $@... - $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testhttp.o libcups.a \ + $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testhttp.o $(LIBCUPSSTATIC) \ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) echo Running HTTP API tests... ./testhttp @@ -469,9 +449,9 @@ testhttp: testhttp.o libcups.a # testipp (dependency on static CUPS library is intentional) # -testipp: testipp.o libcups.a +testipp: testipp.o $(LIBCUPSSTATIC) echo Linking $@... - $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testipp.o libcups.a \ + $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testipp.o $(LIBCUPSSTATIC) \ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) echo Running IPP API tests... ./testipp @@ -481,9 +461,9 @@ testipp: testipp.o libcups.a # testi18n (dependency on static CUPS library is intentional) # -testi18n: testi18n.o libcups.a +testi18n: testi18n.o $(LIBCUPSSTATIC) echo Linking $@... - $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testi18n.o libcups.a \ + $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testi18n.o $(LIBCUPSSTATIC) \ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) echo Running internationalization API tests... ./testi18n @@ -493,9 +473,9 @@ testi18n: testi18n.o libcups.a # testlang (dependency on static CUPS library is intentional) # -testlang: testlang.o libcups.a +testlang: testlang.o $(LIBCUPSSTATIC) echo Linking $@... - $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testlang.o libcups.a \ + $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testlang.o $(LIBCUPSSTATIC) \ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) echo Running language API tests... ./testlang @@ -505,9 +485,9 @@ testlang: testlang.o libcups.a # testoptions (dependency on static CUPS library is intentional) # -testoptions: testoptions.o libcups.a +testoptions: testoptions.o $(LIBCUPSSTATIC) echo Linking $@... - $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testoptions.o libcups.a \ + $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testoptions.o $(LIBCUPSSTATIC) \ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) echo Running option API tests... ./testoptions @@ -517,9 +497,9 @@ testoptions: testoptions.o libcups.a # testppd (dependency on static CUPS library is intentional) # -testppd: testppd.o libcups.a test.ppd test2.ppd +testppd: testppd.o $(LIBCUPSSTATIC) test.ppd test2.ppd echo Linking $@... - $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testppd.o libcups.a \ + $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testppd.o $(LIBCUPSSTATIC) \ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) echo Running PPD API tests... ./testppd @@ -529,9 +509,9 @@ testppd: testppd.o libcups.a test.ppd test2.ppd # testsnmp (dependency on static CUPS library is intentional) # -testsnmp: testsnmp.o libcups.a +testsnmp: testsnmp.o $(LIBCUPSSTATIC) echo Linking $@... - $(CC) $(LDFLAGS) -o $@ testsnmp.o libcups.a \ + $(CC) $(LDFLAGS) -o $@ testsnmp.o $(LIBCUPSSTATIC) \ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) diff --git a/cups/attr.c b/cups/attr.c index c2c6eb512..2cae04f3d 100644 --- a/cups/attr.c +++ b/cups/attr.c @@ -1,10 +1,9 @@ /* * "$Id: attr.c 7584 2008-05-16 22:55:53Z mike $" * - * PPD model-specific attribute routines for the Common UNIX Printing System - * (CUPS). + * PPD model-specific attribute routines for CUPS. * - * Copyright 2007-2009 by Apple Inc. + * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2006 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -15,8 +14,9 @@ * * Contents: * - * ppdFindAttr() - Find the first matching attribute. - * ppdFindNextAttr() - Find the next matching attribute. + * ppdFindAttr() - Find the first matching attribute. + * ppdFindNextAttr() - Find the next matching attribute. + * _ppdNormalizeMakeAndModel() - Normalize a product/make-and-model string. */ /* @@ -140,89 +140,6 @@ ppdFindNextAttr(ppd_file_t *ppd, /* I - PPD file data */ } -/* - * '_ppdGet1284Values()' - 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 */ -_ppdGet1284Values( - 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 (isspace(*device_id & 255)) - 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 && isspace(ptr[-1] & 255)) - ptr --; - - *ptr = '\0'; - device_id ++; - - while (isspace(*device_id & 255)) - 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 && isspace(ptr[-1] & 255)) - ptr --; - - *ptr = '\0'; - device_id ++; - - num_values = cupsAddOption(key, value, num_values, values); - } - - return (num_values); -} - - /* * '_ppdNormalizeMakeAndModel()' - Normalize a product/make-and-model string. * diff --git a/cups/debug.c b/cups/debug.c index f3d2f1c5b..137edffc4 100644 --- a/cups/debug.c +++ b/cups/debug.c @@ -68,7 +68,7 @@ static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; * 'debug_vsnprintf()' - Format a string into a fixed size buffer. */ -int /* O - Number of bytes formatted */ +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 */ diff --git a/cups/globals.c b/cups/globals.c index 4e49109fc..8207312ce 100644 --- a/cups/globals.c +++ b/cups/globals.c @@ -38,6 +38,51 @@ static void cups_env_init(_cups_globals_t *g) /* I - 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 */ + + + /* + * 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 ((g->cups_datadir = getenv("CUPS_DATADIR")) == NULL) + g->cups_datadir = installdir; + + if ((g->cups_serverbin = getenv("CUPS_SERVERBIN")) == NULL) + g->cups_serverbin = installdir; + + if ((g->cups_serverroot = getenv("CUPS_SERVERROOT")) == NULL) + g->cups_serverroot = confdir; + + if ((g->cups_statedir = getenv("CUPS_STATEDIR")) == NULL) + g->cups_statedir = confdir; + + if ((g->localedir = getenv("LOCALEDIR")) == NULL) + g->localedir = localedir; + +#else if ((g->cups_datadir = getenv("CUPS_DATADIR")) == NULL) g->cups_datadir = CUPS_DATADIR; @@ -52,6 +97,7 @@ cups_env_init(_cups_globals_t *g) /* I - Global data */ if ((g->localedir = getenv("LOCALEDIR")) == NULL) g->localedir = CUPS_LOCALEDIR; +#endif /* WIN32 */ } diff --git a/cups/globals.h b/cups/globals.h index fecbeb3d7..1e07daac6 100644 --- a/cups/globals.h +++ b/cups/globals.h @@ -141,6 +141,8 @@ typedef struct _cups_globals_s /**** CUPS global state data ****/ */ extern http_t *_cupsConnect(void); +extern int _cupsGet1284Values(const char *device_id, + cups_option_t **values); extern const char *_cupsGetPassword(const char *prompt); extern _cups_globals_t *_cupsGlobals(void); extern void _cupsSetDefaults(void); diff --git a/cups/http.c b/cups/http.c index abd241305..084e88e9b 100644 --- a/cups/http.c +++ b/cups/http.c @@ -559,8 +559,9 @@ httpError(http_t *http) /* I - Connection to server */ void httpFlush(http_t *http) /* I - Connection to server */ { - char buffer[8192]; /* Junk buffer */ - int blocking; /* To block or not to block */ + 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, @@ -577,6 +578,7 @@ httpFlush(http_t *http) /* I - Connection to server */ * Read any data we can... */ + oldstate = http->state; while (httpRead2(http, buffer, sizeof(buffer)) > 0); /* @@ -586,7 +588,7 @@ httpFlush(http_t *http) /* I - Connection to server */ http->blocking = blocking; - if (http->state != HTTP_WAITING && http->fd >= 0) + if (http->state == oldstate && http->fd >= 0) { /* * Didn't get the data back, so close the current connection. @@ -625,7 +627,11 @@ httpFlushWrite(http_t *http) /* I - Connection to server */ 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); @@ -634,6 +640,8 @@ httpFlushWrite(http_t *http) /* I - Connection to server */ http->wused = 0; + DEBUG_printf(("1httpFlushWrite: Returning %d.", bytes)); + return (bytes); } @@ -2167,7 +2175,10 @@ _httpWait(http_t *http, /* I - Connection to server */ 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... @@ -2178,16 +2189,27 @@ _httpWait(http_t *http, /* I - Connection to server */ { # ifdef HAVE_LIBSSL if (SSL_pending((SSL *)(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_t *)(http->tls))->session)) + { + 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_t *)(http->tls))->session, &bytes) && bytes > 0) + { + DEBUG_puts("5_httpWait: Return 1 since there is pending SSL data."); return (1); + } # endif /* HAVE_LIBSSL */ } #endif /* HAVE_SSL */ @@ -2230,7 +2252,8 @@ _httpWait(http_t *http, /* I - Connection to server */ # endif /* WIN32 */ #endif /* HAVE_POLL */ - DEBUG_printf(("5_httpWait: returning with nfds=%d...", nfds)); + DEBUG_printf(("5_httpWait: returning with nfds=%d, errno=%d...", nfds, + errno)); return (nfds > 0); } @@ -3258,6 +3281,8 @@ http_write(http_t *http, /* I - Connection to server */ bytes; /* Bytes sent */ + DEBUG_printf(("2http_write(http=%p, buffer=%p, length=%d)", http, buffer, + length)); http->error = 0; tbytes = 0; @@ -3288,7 +3313,8 @@ http_write(http_t *http, /* I - Connection to server */ } #endif /* WIN32 */ - DEBUG_puts("8http_write: error writing data..."); + DEBUG_printf(("3http_write: error writing data (%s).", + strerror(http->error))); return (-1); } @@ -3302,6 +3328,8 @@ http_write(http_t *http, /* I - Connection to server */ http_debug_hex("http_write", buffer - tbytes, tbytes); #endif /* DEBUG */ + DEBUG_printf(("3http_write: Returning %d.", tbytes)); + return (tbytes); } @@ -3359,12 +3387,15 @@ 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) - return (SSL_write((SSL *)(http->tls), buf, len)); + result = SSL_write((SSL *)(http->tls), buf, len); # elif defined(HAVE_GNUTLS) - ssize_t result; /* Return value */ - result = gnutls_record_send(((http_tls_t *)(http->tls))->session, buf, len); if (result < 0 && !errno) @@ -3391,10 +3422,7 @@ http_write_ssl(http_t *http, /* I - Connection to server */ result = -1; } - return ((int)result); - # elif defined(HAVE_CDSASSL) - int result; /* Return value */ OSStatus error; /* Error info */ size_t processed; /* Number of bytes processed */ @@ -3423,9 +3451,11 @@ http_write_ssl(http_t *http, /* I - Connection to server */ result = -1; break; } - - return (result); # endif /* HAVE_LIBSSL */ + + DEBUG_printf(("3http_write_ssl: Returning %d.", (int)result)); + + return ((int)result); } #endif /* HAVE_SSL */ diff --git a/cups/i18n.h b/cups/i18n.h index c61be42c4..bc6e779b0 100644 --- a/cups/i18n.h +++ b/cups/i18n.h @@ -82,19 +82,19 @@ typedef struct _cups_vmap_s /**** VBCS Charmap Struct ****/ * Prototypes... */ -#ifdef __APPLE__ +# ifdef __APPLE__ extern const char *_cupsAppleLanguage(const char *locale, char *language, size_t langsize); -#endif /* __APPLE__ */ +# endif /* __APPLE__ */ extern void _cupsCharmapFlush(void); extern void _cupsCharmapFree(const cups_encoding_t encoding); extern void *_cupsCharmapGet(const cups_encoding_t encoding); extern const char *_cupsEncodingName(cups_encoding_t encoding); extern void _cupsLangPrintError(const char *message); extern int _cupsLangPrintf(FILE *fp, const char *message, ...) -# ifdef __GNUC__ +# ifdef __GNUC__ __attribute__ ((__format__ (__printf__, 2, 3))) -# endif /* __GNUC__ */ +# endif /* __GNUC__ */ ; extern int _cupsLangPuts(FILE *fp, const char *message); extern const char *_cupsLangString(cups_lang_t *lang, const char *message); diff --git a/cups/ipp-support.c b/cups/ipp-support.c index 82200ae7d..663ba3ed7 100644 --- a/cups/ipp-support.c +++ b/cups/ipp-support.c @@ -217,7 +217,7 @@ static char * const ipp_std_ops[] = "dateTime", /* 0x31 */ "resolution", /* 0x32 */ "rangeOfInteger", /* 0x33 */ - "begCollection", /* 0x34 */ + "collection", /* 0x34 */ "textWithLanguage", /* 0x35 */ "nameWithLanguage", /* 0x36 */ "endCollection", /* 0x37 */ diff --git a/cups/ipp.c b/cups/ipp.c index 70fb41f38..2f12f85b4 100644 --- a/cups/ipp.c +++ b/cups/ipp.c @@ -425,7 +425,8 @@ ippAddString(ipp_t *ipp, /* I - IPP message */ value = "en"; /* - * Convert language values to lowercase and change _ to - as needed... + * Convert language and charset values to lowercase and change _ to - as + * needed... */ if ((type == IPP_TAG_LANGUAGE || type == IPP_TAG_CHARSET) && value) @@ -473,6 +474,8 @@ ippAddStrings( 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), " @@ -506,16 +509,36 @@ ippAddStrings( if (values != NULL) { - /* - * Force language to be English for the POSIX locale... - */ + if ((int)type & IPP_TAG_COPY) + value->string.text = (char *)values[i]; + else if (type == IPP_TAG_LANGUAGE && !strcasecmp(values[i], "C")) + { + /* + * Force language to be English for the POSIX locale... + */ - if (type == IPP_TAG_LANGUAGE && !strcasecmp(values[i], "C")) 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 = ((int)type & IPP_TAG_COPY) ? (char *)values[i] : - _cupsStrAlloc(values[i]); + value->string.text = _cupsStrAlloc(values[i]); + } } diff --git a/cups/libcups.exp b/cups/libcups.exp index 16fa94d1d..e69de29bb 100644 --- a/cups/libcups.exp +++ b/cups/libcups.exp @@ -1,356 +0,0 @@ -__cups_debug_fd -__cups_debug_printf -__cups_debug_puts -__cups_strcpy -__cupsAdminGetServerSettings -__cupsAdminSetServerSettings -__cupsAppleLanguage -__cupsCharmapFlush -__cupsCharmapFree -__cupsCharmapGet -__cupsEncodingName -__cupsGetPassword -__cupsGlobals -__cupsLangPrintError -__cupsLangPrintf -__cupsLangPuts -__cupsLangString -__cupsMD5Append -__cupsMD5Finish -__cupsMD5Init -__cupsMessageFree -__cupsMessageLoad -__cupsMessageLookup -__cupsPWGMediaByName -__cupsPWGMediaByLegacy -__cupsPWGMediaBySize -__cupsSetError -__cupsSetLocale -__cupsSNMPClose -__cupsSNMPCopyOID -__cupsSNMPDefaultCommunity -__cupsSNMPIsOID -__cupsSNMPIsOIDPrefixed -__cupsSNMPOIDToString -__cupsSNMPOpen -__cupsSNMPRead -__cupsSNMPSetDebug -__cupsSNMPStringToOID -__cupsSNMPWalk -__cupsSNMPWrite -__cupsStrAlloc -__cupsStrFlush -__cupsStrFormatd -__cupsStrFree -__cupsStrRetain -__cupsStrScand -__cupsStrStatistics -__httpAddrPort -__httpCreate -__httpEncodeURI -__httpReadCDSA -__httpResolveURI -__httpWriteCDSA -__ippAddAttr -__ippFindOption -__ippFreeAttr -__ppdFreeLanguages -__ppdGet1284Values -__ppdGetEncoding -__ppdGetLanguages -__ppdHashName -__ppdLocalizedAttr -__ppdNormalizeMakeAndModel -__ppdParseOptions -_cupsAddDest -_cupsAddOption -_cupsAdminCreateWindowsPPD -_cupsAdminExportSamba -_cupsAdminGetServerSettings -_cupsAdminSetServerSettings -_cupsArrayAdd -_cupsArrayClear -_cupsArrayCount -_cupsArrayCurrent -_cupsArrayDelete -_cupsArrayDup -_cupsArrayFind -_cupsArrayFirst -_cupsArrayGetIndex -_cupsArrayGetInsert -_cupsArrayIndex -_cupsArrayInsert -_cupsArrayLast -_cupsArrayNew -_cupsArrayNew2 -_cupsArrayNext -_cupsArrayPrev -_cupsArrayRemove -_cupsArrayRestore -_cupsArraySave -_cupsArrayUserData -_cupsBackChannelRead -_cupsBackChannelWrite -_cupsBackendDeviceURI -_cupsBackendReport -_cupsCancelJob -_cupsCancelJob2 -_cupsCharsetToUTF8 -_cupsCreateJob -_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 -_cupsFilePutConf -_cupsFilePuts -_cupsFileRead -_cupsFileRewind -_cupsFileSeek -_cupsFileStderr -_cupsFileStdin -_cupsFileStdout -_cupsFileTell -_cupsFileUnlock -_cupsFileWrite -_cupsFinishDocument -_cupsFreeDests -_cupsFreeJobs -_cupsFreeOptions -_cupsGetClasses -_cupsGetConflicts -_cupsGetDefault -_cupsGetDefault2 -_cupsGetDest -_cupsGetDests -_cupsGetDests2 -_cupsGetDevices -_cupsGetFd -_cupsGetFile -_cupsGetJobs -_cupsGetJobs2 -_cupsGetNamedDest -_cupsGetOption -_cupsGetPassword -_cupsGetPassword2 -_cupsGetPPD -_cupsGetPPD2 -_cupsGetPPD3 -_cupsGetPrinters -_cupsGetResponse -_cupsGetServerPPD -_cupsLangDefault -_cupsLangEncoding -_cupsLangFlush -_cupsLangFree -_cupsLangGet -_cupsLastError -_cupsLastErrorString -_cupsMarkOptions -_cupsNotifySubject -_cupsNotifyText -_cupsParseOptions -_cupsPrintFile -_cupsPrintFile2 -_cupsPrintFiles -_cupsPrintFiles2 -_cupsPutFd -_cupsPutFile -_cupsReadResponseData -_cupsRemoveDest -_cupsRemoveOption -_cupsResolveConflicts -_cupsSendRequest -_cupsServer -_cupsSetDefaultDest -_cupsSetDests -_cupsSetDests2 -_cupsSetEncryption -_cupsSetPasswordCB -_cupsSetPasswordCB2 -_cupsSetServer -_cupsSetUser -_cupsSideChannelDoRequest -_cupsSideChannelRead -_cupsSideChannelWrite -_cupsSideChannelSNMPGet -_cupsSideChannelSNMPWalk -_cupsStartDocument -_cupsTempFd -_cupsTempFile -_cupsTempFile2 -_cupsUser -_cupsUTF32ToUTF8 -_cupsUTF8ToCharset -_cupsUTF8ToUTF32 -_cupsWriteRequestData -_httpAddrAny -_httpAddrConnect -_httpAddrEqual -_httpAddrFreeList -_httpAddrGetList -_httpAddrLength -_httpAddrLocalhost -_httpAddrLookup -_httpAddrString -_httpAssembleURI -_httpAssembleURIf -_httpBlocking -_httpCheck -_httpClearCookie -_httpClearFields -_httpClose -_httpConnect -_httpConnectEncrypt -_httpDecode64 -_httpDecode64_2 -_httpDelete -_httpEncode64 -_httpEncode64_2 -_httpEncryption -_httpError -_httpFlush -_httpFlushWrite -_httpGet -_httpGetAuthString -_httpGetBlocking -_httpGetCookie -_httpGetDateString -_httpGetDateString2 -_httpGetDateTime -_httpGetFd -_httpGetField -_httpGetHostByName -_httpGetHostname -_httpGetLength -_httpGetLength2 -_httpGets -_httpGetStatus -_httpGetSubField -_httpGetSubField2 -_httpHead -_httpInitialize -_httpMD5 -_httpMD5Final -_httpMD5String -_httpOptions -_httpPost -_httpPrintf -_httpPut -_httpRead -_httpRead2 -_httpReconnect -_httpSeparate -_httpSeparate2 -_httpSeparateURI -_httpSetAuthString -_httpSetCookie -_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 -_ppdInstallableConflict -_ppdIsMarked -_ppdLastError -_ppdLocalize -_ppdLocalizeAttr -_ppdLocalizeIPPReason -_ppdLocalizeMarkerName -_ppdMarkDefaults -_ppdMarkOption -_ppdNextCustomParam -_ppdNextOption -_ppdOpen -_ppdOpen2 -_ppdOpenFd -_ppdOpenFile -_ppdPageLength -_ppdPageSize -_ppdPageSizeLimits -_ppdPageWidth -_ppdSetConformance diff --git a/cups/libcups2.def b/cups/libcups2.def index 1f99d8888..65f59bd1c 100644 --- a/cups/libcups2.def +++ b/cups/libcups2.def @@ -1,5 +1,5 @@ LIBRARY libcups2 -VERSION 2.7 +VERSION 2.8 EXPORTS _cupsAdminGetServerSettings _cupsAdminSetServerSettings @@ -67,6 +67,7 @@ cupsDirRead cupsDirRewind cupsDoAuthentication cupsDoFileRequest +cupsDoIORequest cupsDoRequest cupsEncodeOptions cupsEncodeOptions2 @@ -115,6 +116,7 @@ cupsGetPPD cupsGetPPD2 cupsGetPassword cupsGetPrinters +cupsGetResponse cupsLangDefault cupsLangEncoding cupsLangFlush @@ -134,6 +136,7 @@ cupsPutFd cupsPutFile cupsRemoveOption cupsResolveConflicts +cupsSendRequest cupsServer cupsSetDests cupsSetDests2 @@ -148,6 +151,7 @@ cupsUTF32ToUTF8 cupsUTF8ToCharset cupsUTF8ToUTF32 cupsUser +cupsWriteRequestData httpAddrAny httpAddrConnect httpAddrEqual @@ -248,6 +252,8 @@ ippRead ippReadFile ippReadIO ippSetPort +ippTagString +ippTagValue ippTimeToDate ippWrite ippWriteFile diff --git a/cups/libcups_s.exp b/cups/libcups_s.exp index 1b45a396a..1ad3017fe 100644 --- a/cups/libcups_s.exp +++ b/cups/libcups_s.exp @@ -5,6 +5,7 @@ _cupsCharmapFlush _cupsCharmapFree _cupsCharmapGet _cupsEncodingName +_cupsGet1284Values _cupsGetPassword _cupsGlobals _cupsLangPrintf @@ -53,7 +54,6 @@ _httpResolveURI _ippAddAttr _ippFreeAttr _ppdFreeLanguages -_ppdGet1284Values _ppdGetEncoding _ppdGetLanguages _ppdHashName diff --git a/cups/options.c b/cups/options.c index 23e4dff1c..0c9069c09 100644 --- a/cups/options.c +++ b/cups/options.c @@ -1,9 +1,9 @@ /* * "$Id: options.c 8181 2008-12-10 17:29:57Z mike $" * - * Option routines for the Common UNIX Printing System (CUPS). + * Option routines for CUPS. * - * Copyright 2007-2009 by Apple Inc. + * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2007 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -16,11 +16,14 @@ * * 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. + * 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. */ /* @@ -500,6 +503,89 @@ cupsRemoveOption( } +/* + * '_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 (isspace(*device_id & 255)) + 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 && isspace(ptr[-1] & 255)) + ptr --; + + *ptr = '\0'; + device_id ++; + + while (isspace(*device_id & 255)) + 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 && isspace(ptr[-1] & 255)) + ptr --; + + *ptr = '\0'; + device_id ++; + + num_values = cupsAddOption(key, value, num_values, values); + } + + return (num_values); +} + + /* * 'cups_compare_options()' - Compare two options. */ diff --git a/cups/page.c b/cups/page.c index 34f0a02d7..71817b613 100644 --- a/cups/page.c +++ b/cups/page.c @@ -3,7 +3,7 @@ * * Page size functions for the Common UNIX Printing System (CUPS). * - * Copyright 2007-2009 by Apple Inc. + * 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 @@ -250,6 +250,9 @@ ppdPageSizeLimits(ppd_file_t *ppd, /* I - PPD file record */ * Figure out the current minimum width and length... */ + width = ppd->custom_min[0]; + length = ppd->custom_min[1]; + if (qualifier2) { /* @@ -284,11 +287,6 @@ ppdPageSizeLimits(ppd_file_t *ppd, /* I - PPD file record */ length = ppd->custom_min[1]; } } - else - { - width = ppd->custom_min[0]; - length = ppd->custom_min[1]; - } minimum->width = width; minimum->length = length; @@ -301,6 +299,9 @@ ppdPageSizeLimits(ppd_file_t *ppd, /* I - PPD file record */ * Figure out the current maximum width and length... */ + width = ppd->custom_max[0]; + length = ppd->custom_max[1]; + if (qualifier2) { /* @@ -335,11 +336,6 @@ ppdPageSizeLimits(ppd_file_t *ppd, /* I - PPD file record */ length = ppd->custom_max[1]; } } - else - { - width = ppd->custom_max[0]; - length = ppd->custom_max[1]; - } maximum->width = width; maximum->length = length; diff --git a/cups/ppd-private.h b/cups/ppd-private.h index fa33e96c6..7b647b511 100644 --- a/cups/ppd-private.h +++ b/cups/ppd-private.h @@ -1,9 +1,9 @@ /* * "$Id$" * - * Private PPD definitions for the Common UNIX Printing System (CUPS). + * Private PPD definitions for CUPS. * - * Copyright 2007-2008 by Apple Inc. + * 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 @@ -68,8 +68,6 @@ typedef struct _ppd_cups_uiconsts_s /**** cupsUIConstraints ****/ */ extern void _ppdFreeLanguages(cups_array_t *languages); -extern int _ppdGet1284Values(const char *device_id, - cups_option_t **values); extern cups_encoding_t _ppdGetEncoding(const char *name); extern cups_array_t *_ppdGetLanguages(ppd_file_t *ppd); extern unsigned _ppdHashName(const char *name); diff --git a/cups/tempfile.c b/cups/tempfile.c index 6a781bb71..1503b4f7d 100644 --- a/cups/tempfile.c +++ b/cups/tempfile.c @@ -118,8 +118,8 @@ cupsTempFd(char *filename, /* I - Pointer to buffer */ * Format a string using the hex time values... */ - snprintf(filename, len - 1, "%s/%05x%08lx", tmpdir, (unsigned)getpid(), - (unsigned long)(curtime.tv_sec + curtime.tv_usec + tries)); + snprintf(filename, len - 1, "%s/%05x%08x", tmpdir, (unsigned)getpid(), + (unsigned)(curtime.tv_sec + curtime.tv_usec + tries)); #endif /* WIN32 */ /* diff --git a/data/HPGLprolog b/data/HPGLprolog deleted file mode 100644 index 2ebf98574..000000000 --- a/data/HPGLprolog +++ /dev/null @@ -1,27 +0,0 @@ -%%BeginResource: procset hpgltops 1.1 0 -% -% "$Id: HPGLprolog 6649 2007-07-11 21:46:42Z mike $" -% -% HP-GL/2 filter procset for the Common UNIX Printing System (CUPS). -% -% This procset contains the basic drawing commands that are used to -% reduce output size. Note the 'MP' (make newpath) definition - this -% should be called 'NP' (newpath), but GhostScript uses the 'NP' name -% for 'noaccess put' in some of its font files... -% -% Copyright 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 is included with the CUPS source distribution. -% -/MO { moveto } bind def -/LI { lineto } bind def -/FI { fill } bind def -/ST { stroke } bind def -/CP { closepath } bind def -/MP { newpath } bind def -/SP { setlinewidth setrgbcolor } bind def -%%EndResource diff --git a/data/Makefile b/data/Makefile index e518c8f01..504d2e5fd 100644 --- a/data/Makefile +++ b/data/Makefile @@ -3,7 +3,7 @@ # # Datafile makefile for the Common UNIX Printing System (CUPS). # -# Copyright 2007-2008 by Apple Inc. +# Copyright 2007-2010 by Apple Inc. # Copyright 1993-2006 by Easy Software Products. # # These coded instructions, statements, and computer programs are the @@ -71,7 +71,6 @@ CHARSETS = \ utf-8 DATAFILES = \ - HPGLprolog \ psglyphs \ testprint diff --git a/doc/help/ref-cupsd-conf.html.in b/doc/help/ref-cupsd-conf.html.in index 6b3384bbc..4f1089a17 100644 --- a/doc/help/ref-cupsd-conf.html.in +++ b/doc/help/ref-cupsd-conf.html.in @@ -945,25 +945,6 @@ of authentication to use for IPP operations that require a username. The default is Basic.

-

DefaultCharset

- -

Examples

- -
-DefaultCharset utf-8
-DefaultCharset iso-8859-1
-DefaultCharset windows-1251
-
- -

Description

- -

The DefaultCharset directive sets the default -character set to use for client connections. The default -character set is utf-8 but is overridden by the -character set for the language specified by the client or the -DefaultLanguage directive.

- -

CUPS 1.2/Mac OS X 10.5DefaultEncryption

Examples

diff --git a/doc/help/ref-page_log.html b/doc/help/ref-page_log.html index a0ec7a0e2..076cc4b9c 100644 --- a/doc/help/ref-page_log.html +++ b/doc/help/ref-page_log.html @@ -45,10 +45,10 @@ the page started printing. The format of this field is identical to the data-time field in the access_log file.

-

The page-number and num-pages fields contain the +

The page-number and num-copies fields contain the page number and number of copies being printed of that page. For printers that cannot produce copies on their own, the -num-pages field will always be 1.

+num-copies field will always be 1.

The job-billing field contains a copy of the job-billing attribute provided with the IPP diff --git a/doc/help/spec-cmp.html b/doc/help/spec-cmp.html index 23e229407..ab9a1329c 100644 --- a/doc/help/spec-cmp.html +++ b/doc/help/spec-cmp.html @@ -103,13 +103,11 @@ diff -urN olddirectory directory >filename.patch in their entirety, however that may delay the adoption of your changes.

-
Patches and files must conform to the standards -outlined in the "Coding Guidelines" and "Makefile Guidelines" 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.
+
Patches and files must conform to the standards outlined in the +"Coding Guidelines" and "Makefile +Guidelines" 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.

Software Development Practices

@@ -151,51 +149,45 @@ MAJOR.MINOR.PATCH 2.0.0 -

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.

+

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.

-
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 will be strictly -enforced. This should yield more frequent minor releases with -fewer new features (and interactions!) to -validate/test.
+
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.
-

Beta-test releases are identified by appending the letter B -to the major and minor version numbers followed by the beta -release number:

+

Beta-test releases are identified by appending the letter B to the major and +minor version numbers followed by the beta release number:

 MAJOR.MINORbNUMBER
 1.2b1
 
-

Release candidates are identified by appending the letters RC -to the major and minor version numbers followed by the release -candidate number:

+

Release candidates are identified by appending the letters RC to the major +and minor version numbers followed by the release candidate number:

 MAJOR.MINORrcNUMBER
 1.2rc1
 
-

Developer snapshots are identified by appending the letters -SVN-R to the major and minor version numbers followed by the -revision number:

+

Developer snapshots are identified by appending the letters SVN-R to the +major and minor version numbers followed by the revision number:

 MAJOR.MINORsvn-rREV
 1.2svn-r1234
 
-

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.

+

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.

Version Control (Subversion)

@@ -212,16 +204,9 @@ applicable STRs. The following format must be used for commit log messages:

-Summary of the change ("fix PostScript printing bug") along
-with corresponding STRs ("STR #1, STR #6")
+Summary of the change on one line followed by bug number (STR #NNNN)
 
-foo.cxx:
-    - function(): Detailed list of changes
-    - function2(): Detailed list of changes
-    - Summary of design changes ("added new foo struct")
-
-bar.h:
-    - More detailed changes
+Detailed list of changes.
 

Primary development occurs on the trunk branch, @@ -625,7 +610,7 @@ the Subversion "$Id$" tag:

* * Description of file contents. * - * Copyright 2007 by Apple Inc. + * Copyright 2010 by Apple Inc. * * These coded instructions, statements, and computer programs are the * property of Apple Inc. and are protected by Federal copyright @@ -703,13 +688,15 @@ special text in the function description comment:

    -
  • @since CUPS version@ - Marks the - function as new in the specified version of CUPS.
  • -
  • @deprecated@ - Marks the function as deprecated (not recommended for new development and scheduled for removal)
  • +
  • @since CUPS version@ - Marks the + function as new in the specified version of CUPS.
  • + +
  • @private@ - Marks the function as private.
  • +

Variables

diff --git a/driver/Dependencies b/driver/Dependencies index 2111f79f0..ed31ab6c7 100644 --- a/driver/Dependencies +++ b/driver/Dependencies @@ -44,7 +44,7 @@ cmyk.o: ../cups/versioning.h ../cups/ppd.h ../cups/array.h ../cups/file.h cmyk.o: ../cups/language.h ../cups/raster.h ../cups/string.h ../config.h dither.o: driver.h ../cups/cups.h ../cups/ipp.h ../cups/http.h dither.o: ../cups/versioning.h ../cups/ppd.h ../cups/array.h ../cups/file.h -dither.o: ../cups/language.h ../cups/raster.h +dither.o: ../cups/language.h ../cups/raster.h ../config.h lut.o: driver.h ../cups/cups.h ../cups/ipp.h ../cups/http.h lut.o: ../cups/versioning.h ../cups/ppd.h ../cups/array.h ../cups/file.h lut.o: ../cups/language.h ../cups/raster.h diff --git a/driver/Makefile b/driver/Makefile index dcfef5556..8f017ace1 100644 --- a/driver/Makefile +++ b/driver/Makefile @@ -3,7 +3,7 @@ # # Makefile for the CUPS base drivers. # -# Copyright 2007-2009 by Apple Inc. +# Copyright 2007-2010 by Apple Inc. # Copyright 2002-2005 by Easy Software Products. # # These coded instructions, statements, and computer programs are the @@ -51,12 +51,14 @@ UNITTARGETS = \ testcmyk \ testdither \ testrgb -TARGETS = \ - $(LIBTARGETS) \ +FILTERS = \ commandtoescpx \ commandtopclx \ rastertoescpx \ rastertopclx +TARGETS = \ + $(LIBTARGETS) \ + $(FILTERS) # @@ -120,12 +122,12 @@ install-data: install-exec: $(INSTALL_DIR) $(SERVERBIN)/filter - for file in commandtoescpx commandtopclx rastertoescpx rastertopclx; do \ + for file in $(FILTERS); do \ $(INSTALL_BIN) $$file $(SERVERBIN)/filter; \ done if test "x$(SYMROOT)" != "x"; then \ $(INSTALL_DIR) $(SYMROOT); \ - for file in commandtoescpx commandtopclx rastertoescpx rastertopclx; do \ + for file in $(FILTERS); do \ cp $$file $(SYMROOT); \ done \ fi diff --git a/filter/Dependencies b/filter/Dependencies index a50962a1a..59fc5065d 100644 --- a/filter/Dependencies +++ b/filter/Dependencies @@ -1,37 +1,5 @@ # DO NOT DELETE -hpgl-attr.o: hpgltops.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h -hpgl-attr.o: ../cups/versioning.h ../cups/ppd.h ../cups/array.h -hpgl-attr.o: ../cups/file.h ../cups/language.h ../cups/language.h -hpgl-attr.o: ../cups/string.h ../config.h -hpgl-config.o: hpgltops.h common.h ../cups/cups.h ../cups/ipp.h -hpgl-config.o: ../cups/http.h ../cups/versioning.h ../cups/ppd.h -hpgl-config.o: ../cups/array.h ../cups/file.h ../cups/language.h -hpgl-config.o: ../cups/language.h ../cups/string.h ../config.h -hpgl-main.o: hpgltops.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h -hpgl-main.o: ../cups/versioning.h ../cups/ppd.h ../cups/array.h -hpgl-main.o: ../cups/file.h ../cups/language.h ../cups/language.h -hpgl-main.o: ../cups/string.h ../config.h ../cups/i18n.h ../cups/transcode.h -hpgl-prolog.o: hpgltops.h common.h ../cups/cups.h ../cups/ipp.h -hpgl-prolog.o: ../cups/http.h ../cups/versioning.h ../cups/ppd.h -hpgl-prolog.o: ../cups/array.h ../cups/file.h ../cups/language.h -hpgl-prolog.o: ../cups/language.h ../cups/string.h ../config.h -hpgl-char.o: hpgltops.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h -hpgl-char.o: ../cups/versioning.h ../cups/ppd.h ../cups/array.h -hpgl-char.o: ../cups/file.h ../cups/language.h ../cups/language.h -hpgl-char.o: ../cups/string.h ../config.h -hpgl-input.o: hpgltops.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h -hpgl-input.o: ../cups/versioning.h ../cups/ppd.h ../cups/array.h -hpgl-input.o: ../cups/file.h ../cups/language.h ../cups/language.h -hpgl-input.o: ../cups/string.h ../config.h ../cups/i18n.h ../cups/transcode.h -hpgl-polygon.o: hpgltops.h common.h ../cups/cups.h ../cups/ipp.h -hpgl-polygon.o: ../cups/http.h ../cups/versioning.h ../cups/ppd.h -hpgl-polygon.o: ../cups/array.h ../cups/file.h ../cups/language.h -hpgl-polygon.o: ../cups/language.h ../cups/string.h ../config.h -hpgl-vector.o: hpgltops.h common.h ../cups/cups.h ../cups/ipp.h -hpgl-vector.o: ../cups/http.h ../cups/versioning.h ../cups/ppd.h -hpgl-vector.o: ../cups/array.h ../cups/file.h ../cups/language.h -hpgl-vector.o: ../cups/language.h ../cups/string.h ../config.h image-bmp.o: image-private.h image.h ../cups/raster.h ../cups/cups.h image-bmp.o: ../cups/ipp.h ../cups/http.h ../cups/versioning.h ../cups/ppd.h image-bmp.o: ../cups/array.h ../cups/file.h ../cups/language.h @@ -99,17 +67,6 @@ raster.o: image-private.h image.h ../cups/raster.h ../cups/cups.h raster.o: ../cups/ipp.h ../cups/http.h ../cups/versioning.h ../cups/ppd.h raster.o: ../cups/array.h ../cups/file.h ../cups/language.h ../cups/debug.h raster.o: ../cups/string.h ../config.h -form-main.o: form.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h -form-main.o: ../cups/versioning.h ../cups/ppd.h ../cups/array.h -form-main.o: ../cups/file.h ../cups/language.h ../cups/language.h -form-main.o: ../cups/string.h ../config.h -form-ps.o: form.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h -form-ps.o: ../cups/versioning.h ../cups/ppd.h ../cups/array.h ../cups/file.h -form-ps.o: ../cups/language.h ../cups/language.h ../cups/string.h ../config.h -form-tree.o: form.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h -form-tree.o: ../cups/versioning.h ../cups/ppd.h ../cups/array.h -form-tree.o: ../cups/file.h ../cups/language.h ../cups/language.h -form-tree.o: ../cups/string.h ../config.h bannertops.o: pstext.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h bannertops.o: ../cups/versioning.h ../cups/ppd.h ../cups/array.h bannertops.o: ../cups/file.h ../cups/language.h ../cups/language.h @@ -120,8 +77,7 @@ commandtops.o: ../cups/versioning.h ../cups/ppd.h ../cups/array.h commandtops.o: ../cups/file.h ../cups/language.h ../cups/string.h ../config.h commandtops.o: ../cups/sidechannel.h gziptoany.o: ../cups/file.h ../cups/versioning.h ../cups/string.h ../config.h -gziptoany.o: ../cups/i18n.h ../cups/transcode.h ../cups/language.h -gziptoany.o: ../cups/array.h +gziptoany.o: ../cups/i18n.h ../cups/transcode.h imagetops.o: common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h imagetops.o: ../cups/versioning.h ../cups/ppd.h ../cups/array.h imagetops.o: ../cups/file.h ../cups/language.h ../cups/language.h @@ -147,9 +103,9 @@ pstops.o: common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h pstops.o: ../cups/versioning.h ../cups/ppd.h ../cups/array.h ../cups/file.h pstops.o: ../cups/language.h ../cups/language.h ../cups/string.h ../config.h pstops.o: ../cups/file.h ../cups/array.h ../cups/i18n.h ../cups/transcode.h -rasterbench.o: ../cups/raster.h ../cups/cups.h ../cups/ipp.h ../cups/http.h -rasterbench.o: ../cups/versioning.h ../cups/ppd.h ../cups/array.h -rasterbench.o: ../cups/file.h ../cups/language.h +rasterbench.o: ../config.h ../cups/raster.h ../cups/cups.h ../cups/ipp.h +rasterbench.o: ../cups/http.h ../cups/versioning.h ../cups/ppd.h +rasterbench.o: ../cups/array.h ../cups/file.h ../cups/language.h rastertoepson.o: ../cups/cups.h ../cups/ipp.h ../cups/http.h rastertoepson.o: ../cups/versioning.h ../cups/ppd.h ../cups/array.h rastertoepson.o: ../cups/file.h ../cups/language.h ../cups/ppd.h @@ -182,38 +138,6 @@ texttops.o: ../cups/language.h ../cups/language.h ../cups/string.h texttops.o: ../config.h ../cups/i18n.h ../cups/transcode.h # DO NOT DELETE -hpgl-attr.32.o: hpgl-attr.c hpgltops.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h -hpgl-attr.32.o: hpgl-attr.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h -hpgl-attr.32.o: hpgl-attr.c ../cups/file.h ../cups/language.h ../cups/language.h -hpgl-attr.32.o: hpgl-attr.c ../cups/string.h ../config.h -hpgl-config.32.o: hpgl-config.c hpgltops.h common.h ../cups/cups.h ../cups/ipp.h -hpgl-config.32.o: hpgl-config.c ../cups/http.h ../cups/versioning.h ../cups/ppd.h -hpgl-config.32.o: hpgl-config.c ../cups/array.h ../cups/file.h ../cups/language.h -hpgl-config.32.o: hpgl-config.c ../cups/language.h ../cups/string.h ../config.h -hpgl-main.32.o: hpgl-main.c hpgltops.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h -hpgl-main.32.o: hpgl-main.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h -hpgl-main.32.o: hpgl-main.c ../cups/file.h ../cups/language.h ../cups/language.h -hpgl-main.32.o: hpgl-main.c ../cups/string.h ../config.h ../cups/i18n.h ../cups/transcode.h -hpgl-prolog.32.o: hpgl-prolog.c hpgltops.h common.h ../cups/cups.h ../cups/ipp.h -hpgl-prolog.32.o: hpgl-prolog.c ../cups/http.h ../cups/versioning.h ../cups/ppd.h -hpgl-prolog.32.o: hpgl-prolog.c ../cups/array.h ../cups/file.h ../cups/language.h -hpgl-prolog.32.o: hpgl-prolog.c ../cups/language.h ../cups/string.h ../config.h -hpgl-char.32.o: hpgl-char.c hpgltops.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h -hpgl-char.32.o: hpgl-char.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h -hpgl-char.32.o: hpgl-char.c ../cups/file.h ../cups/language.h ../cups/language.h -hpgl-char.32.o: hpgl-char.c ../cups/string.h ../config.h -hpgl-input.32.o: hpgl-input.c hpgltops.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h -hpgl-input.32.o: hpgl-input.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h -hpgl-input.32.o: hpgl-input.c ../cups/file.h ../cups/language.h ../cups/language.h -hpgl-input.32.o: hpgl-input.c ../cups/string.h ../config.h ../cups/i18n.h ../cups/transcode.h -hpgl-polygon.32.o: hpgl-polygon.c hpgltops.h common.h ../cups/cups.h ../cups/ipp.h -hpgl-polygon.32.o: hpgl-polygon.c ../cups/http.h ../cups/versioning.h ../cups/ppd.h -hpgl-polygon.32.o: hpgl-polygon.c ../cups/array.h ../cups/file.h ../cups/language.h -hpgl-polygon.32.o: hpgl-polygon.c ../cups/language.h ../cups/string.h ../config.h -hpgl-vector.32.o: hpgl-vector.c hpgltops.h common.h ../cups/cups.h ../cups/ipp.h -hpgl-vector.32.o: hpgl-vector.c ../cups/http.h ../cups/versioning.h ../cups/ppd.h -hpgl-vector.32.o: hpgl-vector.c ../cups/array.h ../cups/file.h ../cups/language.h -hpgl-vector.32.o: hpgl-vector.c ../cups/language.h ../cups/string.h ../config.h 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/ipp.h ../cups/http.h ../cups/versioning.h ../cups/ppd.h image-bmp.32.o: image-bmp.c ../cups/array.h ../cups/file.h ../cups/language.h @@ -281,17 +205,6 @@ raster.32.o: raster.c image-private.h image.h ../cups/raster.h ../cups/cups.h raster.32.o: raster.c ../cups/ipp.h ../cups/http.h ../cups/versioning.h ../cups/ppd.h raster.32.o: raster.c ../cups/array.h ../cups/file.h ../cups/language.h ../cups/debug.h raster.32.o: raster.c ../cups/string.h ../config.h -form-main.32.o: form-main.c form.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h -form-main.32.o: form-main.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h -form-main.32.o: form-main.c ../cups/file.h ../cups/language.h ../cups/language.h -form-main.32.o: form-main.c ../cups/string.h ../config.h -form-ps.32.o: form-ps.c form.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h -form-ps.32.o: form-ps.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h ../cups/file.h -form-ps.32.o: form-ps.c ../cups/language.h ../cups/language.h ../cups/string.h ../config.h -form-tree.32.o: form-tree.c form.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h -form-tree.32.o: form-tree.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h -form-tree.32.o: form-tree.c ../cups/file.h ../cups/language.h ../cups/language.h -form-tree.32.o: form-tree.c ../cups/string.h ../config.h bannertops.32.o: bannertops.c pstext.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h bannertops.32.o: bannertops.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h bannertops.32.o: bannertops.c ../cups/file.h ../cups/language.h ../cups/language.h @@ -302,8 +215,7 @@ commandtops.32.o: commandtops.c ../cups/versioning.h ../cups/ppd.h ../cups/arra commandtops.32.o: commandtops.c ../cups/file.h ../cups/language.h ../cups/string.h ../config.h commandtops.32.o: commandtops.c ../cups/sidechannel.h gziptoany.32.o: gziptoany.c ../cups/file.h ../cups/versioning.h ../cups/string.h ../config.h -gziptoany.32.o: gziptoany.c ../cups/i18n.h ../cups/transcode.h ../cups/language.h -gziptoany.32.o: gziptoany.c ../cups/array.h +gziptoany.32.o: gziptoany.c ../cups/i18n.h ../cups/transcode.h imagetops.32.o: imagetops.c common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h imagetops.32.o: imagetops.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h imagetops.32.o: imagetops.c ../cups/file.h ../cups/language.h ../cups/language.h @@ -329,9 +241,9 @@ pstops.32.o: pstops.c common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h pstops.32.o: pstops.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h ../cups/file.h pstops.32.o: pstops.c ../cups/language.h ../cups/language.h ../cups/string.h ../config.h pstops.32.o: pstops.c ../cups/file.h ../cups/array.h ../cups/i18n.h ../cups/transcode.h -rasterbench.32.o: rasterbench.c ../cups/raster.h ../cups/cups.h ../cups/ipp.h ../cups/http.h -rasterbench.32.o: rasterbench.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h -rasterbench.32.o: rasterbench.c ../cups/file.h ../cups/language.h +rasterbench.32.o: rasterbench.c ../config.h ../cups/raster.h ../cups/cups.h ../cups/ipp.h +rasterbench.32.o: rasterbench.c ../cups/http.h ../cups/versioning.h ../cups/ppd.h +rasterbench.32.o: rasterbench.c ../cups/array.h ../cups/file.h ../cups/language.h rastertoepson.32.o: rastertoepson.c ../cups/cups.h ../cups/ipp.h ../cups/http.h rastertoepson.32.o: rastertoepson.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h rastertoepson.32.o: rastertoepson.c ../cups/file.h ../cups/language.h ../cups/ppd.h @@ -364,38 +276,6 @@ texttops.32.o: texttops.c ../cups/language.h ../cups/language.h ../cups/string. texttops.32.o: texttops.c ../config.h ../cups/i18n.h ../cups/transcode.h # DO NOT DELETE -hpgl-attr.64.o: hpgl-attr.c hpgltops.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h -hpgl-attr.64.o: hpgl-attr.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h -hpgl-attr.64.o: hpgl-attr.c ../cups/file.h ../cups/language.h ../cups/language.h -hpgl-attr.64.o: hpgl-attr.c ../cups/string.h ../config.h -hpgl-config.64.o: hpgl-config.c hpgltops.h common.h ../cups/cups.h ../cups/ipp.h -hpgl-config.64.o: hpgl-config.c ../cups/http.h ../cups/versioning.h ../cups/ppd.h -hpgl-config.64.o: hpgl-config.c ../cups/array.h ../cups/file.h ../cups/language.h -hpgl-config.64.o: hpgl-config.c ../cups/language.h ../cups/string.h ../config.h -hpgl-main.64.o: hpgl-main.c hpgltops.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h -hpgl-main.64.o: hpgl-main.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h -hpgl-main.64.o: hpgl-main.c ../cups/file.h ../cups/language.h ../cups/language.h -hpgl-main.64.o: hpgl-main.c ../cups/string.h ../config.h ../cups/i18n.h ../cups/transcode.h -hpgl-prolog.64.o: hpgl-prolog.c hpgltops.h common.h ../cups/cups.h ../cups/ipp.h -hpgl-prolog.64.o: hpgl-prolog.c ../cups/http.h ../cups/versioning.h ../cups/ppd.h -hpgl-prolog.64.o: hpgl-prolog.c ../cups/array.h ../cups/file.h ../cups/language.h -hpgl-prolog.64.o: hpgl-prolog.c ../cups/language.h ../cups/string.h ../config.h -hpgl-char.64.o: hpgl-char.c hpgltops.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h -hpgl-char.64.o: hpgl-char.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h -hpgl-char.64.o: hpgl-char.c ../cups/file.h ../cups/language.h ../cups/language.h -hpgl-char.64.o: hpgl-char.c ../cups/string.h ../config.h -hpgl-input.64.o: hpgl-input.c hpgltops.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h -hpgl-input.64.o: hpgl-input.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h -hpgl-input.64.o: hpgl-input.c ../cups/file.h ../cups/language.h ../cups/language.h -hpgl-input.64.o: hpgl-input.c ../cups/string.h ../config.h ../cups/i18n.h ../cups/transcode.h -hpgl-polygon.64.o: hpgl-polygon.c hpgltops.h common.h ../cups/cups.h ../cups/ipp.h -hpgl-polygon.64.o: hpgl-polygon.c ../cups/http.h ../cups/versioning.h ../cups/ppd.h -hpgl-polygon.64.o: hpgl-polygon.c ../cups/array.h ../cups/file.h ../cups/language.h -hpgl-polygon.64.o: hpgl-polygon.c ../cups/language.h ../cups/string.h ../config.h -hpgl-vector.64.o: hpgl-vector.c hpgltops.h common.h ../cups/cups.h ../cups/ipp.h -hpgl-vector.64.o: hpgl-vector.c ../cups/http.h ../cups/versioning.h ../cups/ppd.h -hpgl-vector.64.o: hpgl-vector.c ../cups/array.h ../cups/file.h ../cups/language.h -hpgl-vector.64.o: hpgl-vector.c ../cups/language.h ../cups/string.h ../config.h 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/ipp.h ../cups/http.h ../cups/versioning.h ../cups/ppd.h image-bmp.64.o: image-bmp.c ../cups/array.h ../cups/file.h ../cups/language.h @@ -463,17 +343,6 @@ raster.64.o: raster.c image-private.h image.h ../cups/raster.h ../cups/cups.h raster.64.o: raster.c ../cups/ipp.h ../cups/http.h ../cups/versioning.h ../cups/ppd.h raster.64.o: raster.c ../cups/array.h ../cups/file.h ../cups/language.h ../cups/debug.h raster.64.o: raster.c ../cups/string.h ../config.h -form-main.64.o: form-main.c form.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h -form-main.64.o: form-main.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h -form-main.64.o: form-main.c ../cups/file.h ../cups/language.h ../cups/language.h -form-main.64.o: form-main.c ../cups/string.h ../config.h -form-ps.64.o: form-ps.c form.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h -form-ps.64.o: form-ps.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h ../cups/file.h -form-ps.64.o: form-ps.c ../cups/language.h ../cups/language.h ../cups/string.h ../config.h -form-tree.64.o: form-tree.c form.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h -form-tree.64.o: form-tree.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h -form-tree.64.o: form-tree.c ../cups/file.h ../cups/language.h ../cups/language.h -form-tree.64.o: form-tree.c ../cups/string.h ../config.h bannertops.64.o: bannertops.c pstext.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h bannertops.64.o: bannertops.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h bannertops.64.o: bannertops.c ../cups/file.h ../cups/language.h ../cups/language.h @@ -484,8 +353,7 @@ commandtops.64.o: commandtops.c ../cups/versioning.h ../cups/ppd.h ../cups/arra commandtops.64.o: commandtops.c ../cups/file.h ../cups/language.h ../cups/string.h ../config.h commandtops.64.o: commandtops.c ../cups/sidechannel.h gziptoany.64.o: gziptoany.c ../cups/file.h ../cups/versioning.h ../cups/string.h ../config.h -gziptoany.64.o: gziptoany.c ../cups/i18n.h ../cups/transcode.h ../cups/language.h -gziptoany.64.o: gziptoany.c ../cups/array.h +gziptoany.64.o: gziptoany.c ../cups/i18n.h ../cups/transcode.h imagetops.64.o: imagetops.c common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h imagetops.64.o: imagetops.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h imagetops.64.o: imagetops.c ../cups/file.h ../cups/language.h ../cups/language.h @@ -511,9 +379,9 @@ pstops.64.o: pstops.c common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h pstops.64.o: pstops.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h ../cups/file.h pstops.64.o: pstops.c ../cups/language.h ../cups/language.h ../cups/string.h ../config.h pstops.64.o: pstops.c ../cups/file.h ../cups/array.h ../cups/i18n.h ../cups/transcode.h -rasterbench.64.o: rasterbench.c ../cups/raster.h ../cups/cups.h ../cups/ipp.h ../cups/http.h -rasterbench.64.o: rasterbench.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h -rasterbench.64.o: rasterbench.c ../cups/file.h ../cups/language.h +rasterbench.64.o: rasterbench.c ../config.h ../cups/raster.h ../cups/cups.h ../cups/ipp.h +rasterbench.64.o: rasterbench.c ../cups/http.h ../cups/versioning.h ../cups/ppd.h +rasterbench.64.o: rasterbench.c ../cups/array.h ../cups/file.h ../cups/language.h rastertoepson.64.o: rastertoepson.c ../cups/cups.h ../cups/ipp.h ../cups/http.h rastertoepson.64.o: rastertoepson.c ../cups/versioning.h ../cups/ppd.h ../cups/array.h rastertoepson.64.o: rastertoepson.c ../cups/file.h ../cups/language.h ../cups/ppd.h diff --git a/filter/Makefile b/filter/Makefile index 6e2e96bd1..184b3072d 100644 --- a/filter/Makefile +++ b/filter/Makefile @@ -3,7 +3,7 @@ # # Filter makefile for the Common UNIX Printing System (CUPS). # -# Copyright 2007-2009 by Apple Inc. +# Copyright 2007-2010 by Apple Inc. # Copyright 1997-2006 by Easy Software Products. # # These coded instructions, statements, and computer programs are the @@ -22,7 +22,6 @@ FILTERS = \ $(BANNERTOPS) \ commandtops \ gziptoany \ - hpgltops \ $(TEXTTOPS) \ pstops \ $(IMGFILTERS) \ @@ -43,16 +42,13 @@ TARGETS = \ $(LIBTARGETS) \ $(FILTERS) -HPGLOBJS = hpgl-attr.o hpgl-config.o hpgl-main.o hpgl-prolog.o \ - hpgl-char.o hpgl-input.o hpgl-polygon.o hpgl-vector.o 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) -FORMOBJS = form-attr.o form-main.o form-ps.o form-text.o form-tree.o -OBJS = $(HPGLOBJS) $(IMAGEOBJS) $(FORMOBJS) \ +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 \ @@ -131,7 +127,7 @@ install-exec: $(LN) rastertolabel $(SERVERBIN)/filter/rastertodymo if test "x$(SYMROOT)" != "x"; then \ $(INSTALL_DIR) $(SYMROOT); \ - for file in $(TARGETS); do \ + for file in $(FILTERS); do \ cp $$file $(SYMROOT); \ done \ fi @@ -161,6 +157,10 @@ install-libs: $(INSTALLSTATIC) $(INSTALL32) $(INSTALL64) $(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) @@ -292,15 +292,6 @@ commandtops: commandtops.o ../cups/$(LIBCUPS) $(CC) $(LDFLAGS) -o $@ commandtops.o $(LIBS) -# -# formtops -# - -formtops: $(FORMOBJS) common.o ../cups/$(LIBCUPS) - echo Linking $@... - $(CC) $(LDFLAGS) -o $@ $(FORMOBJS) common.o $(LIBS) -lm - - # # gziptoany # @@ -310,15 +301,6 @@ gziptoany: gziptoany.o ../Makedefs ../cups/$(LIBCUPS) $(CC) $(LDFLAGS) -o $@ gziptoany.o $(LIBZ) $(LIBS) -# -# hpgltops -# - -hpgltops: $(HPGLOBJS) common.o ../cups/$(LIBCUPS) - echo Linking $@... - $(CC) $(LDFLAGS) -o $@ $(HPGLOBJS) common.o $(LIBS) -lm - - # # libcupsimage.so.2, libcupsimage.sl.2 # diff --git a/filter/form-main.c b/filter/form-main.c deleted file mode 100644 index 0f4ff1b61..000000000 --- a/filter/form-main.c +++ /dev/null @@ -1,53 +0,0 @@ -/* - * "$Id: form-main.c 6649 2007-07-11 21:46:42Z mike $" - * - * CUPS form main entry for the Common UNIX Printing System (CUPS). - * - * 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/". - * - * This file is subject to the Apple OS-Developed Software exception. - * - * Contents: - * - * main() - Load the specified form file and output PostScript. - */ - -/* - * Include necessary headers... - */ - -#include "form.h" - - -/* - * Globals... - */ - -int NumOptions; /* Number of command-line options */ -cups_option_t *Options; /* Command-line options */ -ppd_file_t *PPD; /* PPD file */ - - -/* - * 'main()' - Load the specified form file and output PostScript. - */ - -int /* O - Exit status */ -main(int argc, /* I - Number of command-line arguments */ - char *argv[]) /* I - Command-line arguments */ -{ - - return (0); -} - - -/* - * End of "$Id: form-main.c 6649 2007-07-11 21:46:42Z mike $". - */ diff --git a/filter/form-ps.c b/filter/form-ps.c deleted file mode 100644 index 6a1e1e327..000000000 --- a/filter/form-ps.c +++ /dev/null @@ -1,40 +0,0 @@ -/* - * "$Id: form-ps.c 6649 2007-07-11 21:46:42Z mike $" - * - * CUPS form PostScript routines for the Common UNIX Printing System (CUPS). - * - * 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/". - * - * This file is subject to the Apple OS-Developed Software exception. - * - * Contents: - * - */ - -/* - * Include necessary headers... - */ - -#include "form.h" - - -/* - * 'formWrite()' - Write PostScript output for the given form document. - */ - -void -formWrite(tree_t *t) /* I - Document tree to write */ -{ -} - - -/* - * End of "$Id: form-ps.c 6649 2007-07-11 21:46:42Z mike $". - */ diff --git a/filter/form-tree.c b/filter/form-tree.c deleted file mode 100644 index 337924d09..000000000 --- a/filter/form-tree.c +++ /dev/null @@ -1,615 +0,0 @@ -/* - * "$Id: form-tree.c 6649 2007-07-11 21:46:42Z mike $" - * - * CUPS form document tree routines for the Common UNIX Printing - * System (CUPS). - * - * 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/". - * - * This file is subject to the Apple OS-Developed Software exception. - * - * Contents: - * - */ - -/* - * Include necessary headers... - */ - -#include "form.h" - - -/* - * Local functions... - */ - -static int compare_attr(attr_t *a0, attr_t *a1); -static int compare_elements(char **e0, char **e1); -static int parse_attr(tree_t *t, FILE *fp); -static int parse_element(tree_t *t, FILE *fp); - - -/* - * Local globals... - */ - -static char *elements[] = - { - "", - "!--", - "ARC", - "BOX", - "BR", - "B", - "CUPSFORM", - "DEFVAR", - "FONT", - "H1", - "H2", - "H3", - "H4", - "H5", - "H6", - "HEAD", - "IMG", - "I", - "LINE", - "PAGE", - "PIE", - "POLY", - "PRE", - "P", - "RECT", - "TEXT", - "TT", - "VAR" - }; - - -/* - * 'formDelete()' - Delete a node and its children. - */ - -void -formDelete(tree_t *t) /* I - Tree node */ -{ -} - - -/* - * 'formGetAttr()' - Get a node attribute value. - */ - -char * /* O - Value or NULL */ -formGetAttr(tree_t *t, /* I - Tree node */ - const char *name) /* I - Name of attribute */ -{ -} - - -/* - * 'formNew()' - Create a new form node. - */ - -tree_t * /* O - New tree node */ -formNew(tree_t *p) /* I - Parent node */ -{ - tree_t *t; /* New tree node */ - - - /* - * Allocate the new node... - */ - - if ((t = (tree_t *)calloc(sizeof(tree_t), 1)) == NULL) - return (NULL); - - /* - * Set/copy attributes... - */ - - if (p == NULL) - { - t->bg[0] = 1.0; - t->bg[1] = 1.0; - t->bg[2] = 1.0; - t->halign = HALIGN_LEFT; - t->valign = VALIGN_MIDDLE; - t->typeface = "Courier"; - t->size = 12.0; - } - else - { - memcpy(t, p, sizeof(tree_t)); - - t->prev = NULL; - t->next = NULL; - t->child = NULL; - t->last_child = NULL; - t->parent = NULL; - t->num_attrs = 0; - t->attrs = NULL; - t->data = NULL; - } - - /* - * Return the new node... - */ - - return (t); -} - - -/* - * 'formRead()' - Read a form tree from a file. - */ - -tree_t * /* O - New form tree */ -formRead(FILE *fp, /* I - File to read from */ - tree_t *p) /* I - Parent node */ -{ - int ch, /* Character from file */ - closech, /* Closing character */ - have_whitespace; /* Leading whitespace? */ - static char s[10240]; /* String from file */ - uchar *ptr, /* Pointer in string */ - glyph[16], /* Glyph name (&#nnn;) */ - *glyphptr; /* Pointer in glyph string */ - tree_t *tree, /* "top" of this tree */ - *t, /* New tree node */ - *prev, /* Previous tree node */ - *temp; /* Temporary looping var */ - uchar *face, /* Typeface for FONT tag */ - *color, /* Color for FONT tag */ - *size; /* Size for FONT tag */ - - - /* - * Start off with no previous tree node... - */ - - prev = NULL; - tree = NULL; - - /* - * Parse data until we hit end-of-file... - */ - - while ((ch = getc(fp)) != EOF) - { - /* - * Ignore leading whitespace... - */ - - have_whitespace = 0; - closech = '/'; - - if (p == NULL || !p->preformatted) - { - while (isspace(ch & 255)) - { - have_whitespace = 1; - ch = getc(fp); - } - - if (ch == EOF) - break; - } - - /* - * Allocate a new tree node - use calloc() to get zeroed data... - */ - - t = formNew(p); - - /* - * See what the character was... - */ - - if (ch == '<') - { - /* - * Markup char; grab the next char to see if this is a /... - */ - - ch = getc(fp); - if (ch == ' ') - { - /* - * Illegal lone "<"! Ignore it... - */ - - free(t); - continue; - } - - if (ch != '/') - ungetc(ch, fp); - - if (parse_element(t, fp) < 0) - { - free(t); - break; - } - - if ((closech = getc(fp)) == '/') - getc(fp); - - /* - * If this is the matching close mark, or if we are starting the same - * element, or if we've completed a list, we're done! - */ - - if (ch == '/') - { - /* - * Close element; find matching element... - */ - - for (temp = p; temp != NULL; temp = temp->p) - if (temp->element == t->element) - break; - - free(t); - - if (temp != NULL) - break; - else - continue; - } - } - else if (t->preformatted) - { - /* - * Read a pre-formatted string into the current tree node... - */ - - ptr = s; - while (ch != '<' && ch != EOF && ptr < (s + sizeof(s) - 1)) - { - if (ch == '&') - { - for (glyphptr = glyph; - (ch = getc(fp)) != EOF && (glyphptr - glyph) < 15; - glyphptr ++) - if (!isalnum(ch & 255)) - break; - else - *glyphptr = ch; - - *glyphptr = '\0'; - if (atoi(glyph) > 0) - ch = atoi(glyph); - else if (strcmp(glyph, "lt") == 0) - ch = '<'; - else if (strcmp(glyph, "gt") == 0) - ch = '>'; - else if (strcmp(glyph, "quot") == 0) - ch = '\''; - else if (strcmp(glyph, "nbsp") == 0) - ch = ' '; - else - ch = '&'; - } - - if (ch != 0) - *ptr++ = ch; - - if (ch == '\n') - break; - - ch = getc(fp); - } - - *ptr = '\0'; - - if (ch == '<') - ungetc(ch, fp); - - t->element = ELEMENT_FRAGMENT; - t->data = strdup(s); - } - else - { - /* - * Read the next string fragment... - */ - - ptr = s; - if (have_whitespace) - *ptr++ = ' '; - - while (!isspace(ch & 255) && ch != '<' && ch != EOF && ptr < (s + sizeof(s) - 1)) - { - if (ch == '&') - { - for (glyphptr = glyph; - (ch = getc(fp)) != EOF && (glyphptr - glyph) < 15; - glyphptr ++) - if (!isalnum(ch & 255)) - break; - else - *glyphptr = ch; - - *glyphptr = '\0'; - if (atoi(glyph) > 0) - ch = atoi(glyph); - else if (strcmp(glyph, "lt") == 0) - ch = '<'; - else if (strcmp(glyph, "gt") == 0) - ch = '>'; - else if (strcmp(glyph, "quot") == 0) - ch = '\''; - else if (strcmp(glyph, "nbsp") == 0) - ch = ' '; - else - ch = '&'; - } - - if (ch != 0) - *ptr++ = ch; - - ch = getc(fp); - } - - if (isspace(ch & 255)) - *ptr++ = ' '; - - *ptr = '\0'; - - if (ch == '<') - ungetc(ch, fp); - - t->element = ELEMENT_FRAGMENT; - t->data = strdup(s); - } - - /* - * If the p tree pointer is not NULL and this is the first - * entry we've read, set the child pointer... - */ - - if (p != NULL && prev == NULL) - p->child = t; - - if (p != NULL) - p->last_child = t; - - /* - * Do the prev/next links... - */ - - t->parent = p; - t->prev = prev; - if (prev != NULL) - prev->next = t; - else - tree = t; - - prev = t; - - /* - * Do child stuff as needed... - */ - - if (closech == '>') - t->child = formRead(t, fp); - } - - return (tree); -} - - -/* - * 'formSetAttr()' - Set a node attribute. - */ - -void -formSetAttr(tree_t *t, /* I - Tree node */ - const char *name, /* I - Attribute name */ - const char *value) /* I - Attribute value */ -{ -} - - -/* - * 'compare_attr()' - Compare two attributes. - */ - -static int /* O - -1 if a0 < a1, etc. */ -compare_attr(attr_t *a0, /* I - First attribute */ - attr_t *a1) /* I - Second attribute */ -{ - return (strcasecmp(a0->name, a1->name)); -} - - -/* - * 'compare_elements()' - Compare two elements. - */ - -static int /* O - -1 if e0 < e1, etc. */ -compare_elements(char **e0, /* I - First element */ - char **e1) /* I - Second element */ -{ - return (strcasecmp(*e0, *e1)); -} - - -/* - * 'parse_attr()' - Parse an element attribute string. - */ - -static int /* O - -1 on error, 0 on success */ -parse_attr(tree_t *t, /* I - Current tree node */ - FILE *fp) /* I - Input file */ -{ - char name[1024], /* Name of attr */ - value[10240], /* Value of attr */ - *ptr; /* Temporary pointer */ - int ch; /* Character from file */ - - - ptr = name; - while ((ch = getc(fp)) != EOF) - if (isalnum(ch & 255)) - { - if (ptr < (name + sizeof(name) - 1)) - *ptr++ = ch; - } - else - break; - - *ptr = '\0'; - - while (isspace(ch & 255) || ch == '\r') - ch = getc(fp); - - switch (ch) - { - default : - ungetc(ch, fp); - return (formSetAttr(t, name, NULL)); - case EOF : - return (-1); - case '=' : - ptr = value; - ch = getc(fp); - - while (isspace(ch & 255) || ch == '\r') - ch = getc(fp); - - if (ch == EOF) - return (-1); - - if (ch == '\'') - { - while ((ch = getc(fp)) != EOF) - if (ch == '\'') - break; - else if (ptr < (value + sizeof(value) - 1)) - *ptr++ = ch; - - *ptr = '\0'; - } - else if (ch == '\"') - { - while ((ch = getc(fp)) != EOF) - if (ch == '\"') - break; - else if (ptr < (value + sizeof(value) - 1)) - *ptr++ = ch; - - *ptr = '\0'; - } - else - { - *ptr++ = ch; - while ((ch = getc(fp)) != EOF) - if (isspace(ch & 255) || ch == '>' || ch == '/' || ch == '\r') - break; - else if (ptr < (value + sizeof(value) - 1)) - *ptr++ = ch; - - *ptr = '\0'; - if (ch == '>' || ch == '/') - ungetc(ch, fp); - } - - return (formSetAttr(t, name, value)); - } -} - - -/* - * 'parse_element()' - Parse an element. - */ - -static int /* O - -1 on error or ELEMENT_nnnn */ -parse_element(tree_t *t, /* I - Current tree node */ - FILE *fp) /* I - Input file */ -{ - int ch; /* Character from file */ - char element[255], /* Element string... */ - *eptr, /* Current character... */ - comment[10240], /* Comment string */ - *cptr, /* Current char... */ - **temp; /* Element variable entry */ - - - eptr = element; - - while ((ch = getc(fp)) != EOF && eptr < (element + sizeof(element) - 1)) - if (ch == '>' || ch == '/' || isspace(ch & 255)) - break; - else - *eptr++ = ch; - - *eptr = '\0'; - - if (ch == EOF) - return (ELEMENT_ERROR); - - eptr = element; - temp = bsearch(&mptr, elements, sizeof(elements) / sizeof(elements[0]), - sizeof(elements[0]), - (int (*)(const void *, const void *))compare_elements); - - if (temp == NULL) - { - /* - * Unrecognized element stuff... - */ - - t->element = ELEMENT_COMMENT; - strcpy(comment, element); - cptr = comment + strlen(comment); - } - else - { - t->element = (element_t)((char **)temp - elements); - cptr = comment; - } - - if (t->element == ELEMENT_COMMENT) - { - while (ch != EOF && ch != '>' && cptr < (comment + sizeof(comment) - 1)) - { - *cptr++ = ch; - ch = getc(fp); - } - - *cptr = '\0'; - t->data = strdup(comment); - } - else - { - while (ch != EOF && ch != '>' && ch != '/') - { - if (!isspace(ch & 255)) - { - ungetc(ch, fp); - parse_variable(t, fp); - } - - ch = getc(fp); - } - - if (ch != EOF) - ungetc(ch, fp); - } - - return (t->element); -} - - -/* - * End of "$Id: form-tree.c 6649 2007-07-11 21:46:42Z mike $". - */ diff --git a/filter/form.h b/filter/form.h deleted file mode 100644 index 7b4598ef3..000000000 --- a/filter/form.h +++ /dev/null @@ -1,168 +0,0 @@ -/* - * "$Id: form.h 6649 2007-07-11 21:46:42Z mike $" - * - * CUPS form header file for the Common UNIX Printing System (CUPS). - * - * 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/". - * - * This file is subject to the Apple OS-Developed Software exception. - */ - -/* - * Include necessary headers... - */ - -#include "common.h" - - -/* - * Form elements... - */ - -typedef enum -{ - ELEMENT_FILE = -1, /* Pseudo element, not in file, but above */ - ELEMENT_FRAGMENT, /* Text fragment */ - ELEMENT_COMMENT, /* */ - ELEMENT_ARC, - ELEMENT_BOX, - ELEMENT_BR, - ELEMENT_B, - ELEMENT_CUPSFORM, - ELEMENT_DEFVAR, - ELEMENT_FONT, - ELEMENT_H1, - ELEMENT_H2, - ELEMENT_H3, - ELEMENT_H4, - ELEMENT_H5, - ELEMENT_H6, - ELEMENT_HEAD, - ELEMENT_IMG, - ELEMENT_I, - ELEMENT_LINE, - ELEMENT_PAGE, - ELEMENT_PIE, - ELEMENT_POLY, - ELEMENT_PRE, - ELEMENT_P, - ELEMENT_RECT, - ELEMENT_TEXT, - ELEMENT_TT, - ELEMENT_VAR -} element_t; - - -/* - * Font styles... - */ - -typedef enum -{ - STYLE_NORMAL, - STYLE_BOLD, - STYLE_ITALIC, - STYLE_BOLD_ITALIC -} style_t; - - -/* - * Text alignments... - */ - -typedef enum -{ - HALIGN_LEFT, - HALIGN_CENTER, - HALIGN_RIGHT -} halign_t; - -typedef enum -{ - VALIGN_BOTTOM, - VALIGN_CENTER, - VALIGN_TOP -} valign_t; - - -/* - * Text directions... - */ - -typedef enun -{ - DIR_LEFT_TO_RIGHT, - DIR_RIGHT_TO_LEFT -} dir_t; - - -/* - * Attribute structure... - */ - -typedef struct -{ - char *name, /* Name of attribute */ - *value; /* Value of attribute */ -} attr_t; - - -/* - * Form document tree structure... - */ - -typedef struct tree_str -{ - struct tree_str *prev, /* Previous tree node */ - *next, /* Next tree node */ - *parent, /* Parent tree node */ - *child, /* First child node */ - *last_child; /* Last child node */ - element_t element; /* Element type */ - float x, y, w, h; /* Position and size in points */ - float bg[3], fg[3]; /* Colors of element */ - float thickness; /* Thickness of lines */ - int preformatted; /* Preformatted text? */ - float size; /* Height of text in points */ - char *typeface; /* Typeface of text */ - style_t style; /* Style of text */ - halign_t halign; /* Horizontal alignment */ - valign_t valign; /* Vertical alignment */ - dir_t dir; /* Direction of text */ - int num_attrs; /* Number of attributes */ - attr_t *attrs; /* Attributes */ - void *data; /* Text fragment data */ -} tree_t; - - -/* - * Globals... - */ - -extern int NumOptions; /* Number of command-line options */ -extern cups_option_t *Options; /* Command-line options */ -extern ppd_file_t *PPD; /* PPD file */ - - -/* - * Prototypes... - */ - -extern void formDelete(tree_t *t); -extern char *formGetAttr(tree_t *t, const char *name); -extern tree_t *formNew(tree_t *p); -extern tree_t *formRead(FILE *fp, tree_t *p); -extern void formSetAttr(tree_t *t, const char *name, const char *value); -extern void formWrite(tree_t *p); - - -/* - * End of "$Id: form.h 6649 2007-07-11 21:46:42Z mike $". - */ diff --git a/filter/hpgl-attr.c b/filter/hpgl-attr.c deleted file mode 100644 index 7a93ad7d8..000000000 --- a/filter/hpgl-attr.c +++ /dev/null @@ -1,479 +0,0 @@ -/* - * "$Id: hpgl-attr.c 6649 2007-07-11 21:46:42Z mike $" - * - * HP-GL/2 attribute processing for the Common UNIX Printing System (CUPS). - * - * Copyright 2007-2008 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: - * - * CR_color_range() - Set the range for color values. - * AC_anchor_corner() - Set the anchor corner. - * FT_fill_type() - Set the fill type or pattern. - * LA_line_attributes() - Set the line drawing attributes. - * LT_line_type() - Set the line type (style)... - * NP_number_pens() - Set the number of pens to be used. - * PC_pen_color() - Set the pen color... - * PW_pen_width() - Set the pen width. - * RF_raster_fill() - Set the raster fill pattern. - * SM_symbol_mode() - Set where symbols are drawn. - * SP_select_pen() - Select a pen for drawing. - * UL_user_line_type() - Set a user-defined line type. - * WU_width_units() - Set the units used for pen widths. - */ - -/* - * Include necessary headers... - */ - -#include "hpgltops.h" - - -/* - * 'CR_color_range()' - Set the range for color values. - */ - -void -CR_color_range(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - if (num_params == 0) - { - /* - * Default to 0 to 255 for all color values. - */ - - ColorRange[0][0] = 0.0; - ColorRange[0][1] = 255.0; - ColorRange[1][0] = 0.0; - ColorRange[1][1] = 255.0; - ColorRange[2][0] = 0.0; - ColorRange[2][1] = 255.0; - } - else if (num_params == 6) - { - /* - * Set the range based on the parameters... - */ - - ColorRange[0][0] = params[0].value.number; - ColorRange[0][1] = params[1].value.number - params[0].value.number; - ColorRange[1][0] = params[2].value.number; - ColorRange[1][1] = params[3].value.number - params[2].value.number; - ColorRange[2][0] = params[4].value.number; - ColorRange[2][1] = params[5].value.number - params[4].value.number; - } - else - fprintf(stderr, - "DEBUG: HP-GL/2 \'CR\' command with invalid number of " - "parameters (%d)!\n", num_params); -} - - -/* - * 'AC_anchor_corner()' - Set the anchor corner. - */ - -void -AC_anchor_corner(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - (void)num_params; - (void)params; -} - - -/* - * 'FT_fill_type()' - Set the fill type or pattern. - * - * Note: - * - * This needs to be updated to support non-solid fill. - */ - -void -FT_fill_type(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - if (num_params == 0 || - params[0].value.number == 1 || - params[0].value.number == 2) - { - /**** SOLID PATTERN ****/ - } -} - - -/* - * 'LA_line_attributes()' - Set the line drawing attributes. - */ - -void -LA_line_attributes(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - int i; /* Looping var */ - - - if (num_params == 0) - { - MiterLimit = 3.0f; - LineCap = 0; - LineJoin = 0; - } - else for (i = 0; i < (num_params - 1); i += 2) - switch ((int)params[i].value.number) - { - case 1 : - LineCap = params[i + 1].value.number == 1 ? 0 : - params[i + 1].value.number == 4 ? 1 : 2; - break; - case 2 : - switch ((int)params[i + 1].value.number) - { - case 1 : - case 2 : - case 3 : - LineJoin = 0; - break; - case 5 : - LineJoin = 2; - break; - default : - LineJoin = 1; - break; - } - break; - case 3 : - MiterLimit = 1.0 + 0.5 * (params[i + 1].value.number - 1.0); - break; - } - - if (PageDirty) - { - printf("%.1f setmiterlimit\n", MiterLimit); - printf("%d setlinecap\n", LineCap); - printf("%d setlinejoin\n", LineJoin); - } -} - - -/* - * 'LT_line_type()' - Set the line type (style)... - * - * Note: - * - * This needs to be updated to support line types. - */ - -void -LT_line_type(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - (void)num_params; - (void)params; -} - - -/* - * 'NP_number_pens()' - Set the number of pens to be used. - */ - -void -NP_number_pens(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - int i; /* Looping var */ - - - if (num_params == 0) - PenCount = 8; - else if (num_params == 1) - { - if (params[0].value.number < 1 || params[0].value.number > MAX_PENS) - { - fprintf(stderr, - "DEBUG: HP-GL/2 \'NP\' command with invalid number of " - "pens (%d)!\n", (int)params[0].value.number); - PenCount = 8; - } - else - PenCount = (int)params[0].value.number; - } - else - fprintf(stderr, - "DEBUG: HP-GL/2 \'NP\' command with invalid number of " - "parameters (%d)!\n", num_params); - - for (i = 0; i < PenCount; i ++) - Pens[i].width = PenWidth; - - PC_pen_color(0, NULL); -} - - -/* - * 'PC_pen_color()' - Set the pen color... - */ - -void -PC_pen_color(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - int i; /* Looping var */ - static float standard_colors[8][3] = /* Standard colors for first 8 pens */ - { - { 0.0, 0.0, 0.0 }, /* Black */ - { 1.0, 0.0, 0.0 }, /* Red */ - { 0.0, 1.0, 0.0 }, /* Green */ - { 1.0, 1.0, 0.0 }, /* Yellow */ - { 0.0, 0.0, 1.0 }, /* Blue */ - { 1.0, 0.0, 1.0 }, /* Magenta */ - { 0.0, 1.0, 1.0 }, /* Cyan */ - { 1.0, 1.0, 1.0 } /* White */ - }; - - - if (num_params == 0) - { - for (i = 0; i < PenCount; i ++) - if (i < 8) - { - Pens[i].rgb[0] = standard_colors[i][0]; - Pens[i].rgb[1] = standard_colors[i][1]; - Pens[i].rgb[2] = standard_colors[i][2]; - } - else - { - Pens[i].rgb[0] = 0.0f; - Pens[i].rgb[1] = 0.0f; - Pens[i].rgb[2] = 0.0f; - } - - if (PageDirty) - printf("%.3f %.3f %.3f %.2f SP\n", Pens[PenNumber].rgb[0], - Pens[PenNumber].rgb[1], Pens[PenNumber].rgb[2], - Pens[PenNumber].width * PenScaling); - } - else if (num_params == 1 || num_params == 4) - { - i = (int)params[0].value.number - 1; - - if (i < 0 || i >= PenCount) - { - fprintf(stderr, - "DEBUG: HP-GL/2 \'PC\' command with invalid pen (%d)!\n", i + 1); - return; - } - - if (num_params == 1) - { - Pens[i].rgb[0] = standard_colors[i & 7][0]; - Pens[i].rgb[1] = standard_colors[i & 7][1]; - Pens[i].rgb[2] = standard_colors[i & 7][2]; - } - else - { - Pens[i].rgb[0] = (params[1].value.number - ColorRange[0][0]) / - (ColorRange[0][1] - ColorRange[0][0]); - Pens[i].rgb[1] = (params[2].value.number - ColorRange[1][0]) / - (ColorRange[1][1] - ColorRange[1][0]); - Pens[i].rgb[2] = (params[3].value.number - ColorRange[2][0]) / - (ColorRange[2][1] - ColorRange[2][0]); - - fprintf(stderr, "DEBUG: Pen %d %.0f %.0f %.0f = %.3f %.3f %.3f\n", - i, params[1].value.number, params[2].value.number, - params[3].value.number, Pens[i].rgb[0], Pens[i].rgb[1], - Pens[i].rgb[2]); - } - - if (PageDirty && i == PenNumber) - printf("%.3f %.3f %.3f %.2f SP\n", Pens[PenNumber].rgb[0], - Pens[PenNumber].rgb[1], Pens[PenNumber].rgb[2], - Pens[PenNumber].width * PenScaling); - } - else - fprintf(stderr, - "DEBUG: HP-GL/2 \'PC\' command with invalid number of " - "parameters (%d)!\n", num_params); -} - - -/* - * 'PW_pen_width()' - Set the pen width. - */ - -void -PW_pen_width(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - int pen; /* Pen number */ - float w; /* Width value */ - - - if (WidthUnits == 0) - { - /* - * Metric... - */ - - if (num_params == 0) - w = 0.35f / 25.4f * 72.0f; - else - w = params[0].value.number / 25.4f * 72.0f; - } - else - { - /* - * Relative... - */ - - w = (float)hypot(PlotSize[0], PlotSize[1]) / 1016.0f * 72.0f; - - if (num_params == 0) - w *= 0.01f; - else - w *= params[0].value.number; - } - - if (num_params == 2) - { - pen = (int)params[1].value.number - 1; - - if (pen < 0 || pen >= PenCount) - { - fprintf(stderr, - "DEBUG: HP-GL/2 \'PW\' command with invalid pen (%d)!\n", - pen + 1); - return; - } - - Pens[pen].width = w; - - if (PageDirty && pen == PenNumber) - printf("%.3f %.3f %.3f %.2f SP\n", Pens[PenNumber].rgb[0], - Pens[PenNumber].rgb[1], Pens[PenNumber].rgb[2], - Pens[PenNumber].width * PenScaling); - } - else if (num_params < 2) - { - /* - * Set width for all pens... - */ - - for (pen = 0; pen < PenCount; pen ++) - Pens[pen].width = w; - - if (PageDirty) - printf("%.3f %.3f %.3f %.2f SP\n", Pens[PenNumber].rgb[0], - Pens[PenNumber].rgb[1], Pens[PenNumber].rgb[2], - Pens[PenNumber].width * PenScaling); - } - else - fprintf(stderr, - "DEBUG: HP-GL/2 \'PW\' command with invalid number of " - "parameters (%d)!\n", num_params); -} - - -/* - * 'RF_raster_fill()' - Set the raster fill pattern. - * - * Note: - * - * This needs to be implemented. - */ - -void -RF_raster_fill(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - (void)num_params; - (void)params; -} - - -/* - * 'SM_symbol_mode()' - Set where symbols are drawn. - */ - -void -SM_symbol_mode(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - (void)num_params; - (void)params; -} - - -/* - * 'SP_select_pen()' - Select a pen for drawing. - */ - -void -SP_select_pen(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - if (num_params == 0) - PenNumber = 0; - else if (num_params > 1) - fprintf(stderr, - "DEBUG: HP-GL/2 \'SP\' command with invalid number of parameters " - "(%d)!\n", num_params); - else if (params[0].value.number <= 0 || params[0].value.number >= PenCount) - fprintf(stderr, "DEBUG: HP-GL/2 \'SP\' command with invalid pen (%d)!\n", - (int)params[0].value.number); - else - PenNumber = (int)params[0].value.number - 1; - - if (PageDirty) - printf("%.3f %.3f %.3f %.2f SP\n", Pens[PenNumber].rgb[0], - Pens[PenNumber].rgb[1], Pens[PenNumber].rgb[2], - Pens[PenNumber].width * PenScaling); -} - - -/* - * 'UL_user_line_type()' - Set a user-defined line type. - */ - -void -UL_user_line_type(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - (void)num_params; - (void)params; -} - - -/* - * 'WU_width_units()' - Set the units used for pen widths. - */ - -void -WU_width_units(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - if (num_params == 0) - WidthUnits = 0; - else if (num_params == 1) - WidthUnits = (int)params[0].value.number; - else - fprintf(stderr, - "DEBUG: HP-GL/2 \'WU\' command with invalid number of " - "parameters (%d)!\n", num_params); -} - - -/* - * End of "$Id: hpgl-attr.c 6649 2007-07-11 21:46:42Z mike $". - */ diff --git a/filter/hpgl-char.c b/filter/hpgl-char.c deleted file mode 100644 index 031b938fd..000000000 --- a/filter/hpgl-char.c +++ /dev/null @@ -1,631 +0,0 @@ -/* - * "$Id: hpgl-char.c 6649 2007-07-11 21:46:42Z mike $" - * - * HP-GL/2 character processing for the Common UNIX Printing System (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/". - * - * This file is subject to the Apple OS-Developed Software exception. - * - * Contents: - * - * AD_define_alternate() - Define the alternate font. - * CF_character_fill() - Set whether or not to fill or outline - * characters. - * CP_character_plot() - Move the current pen position for the given - * number of columns and rows. - * DI_absolute_direction() - Set the direction vector for text. - * DR_relative_direction() - Set the relative direction vector for text. - * DT_define_label_term() - Set the label string terminator. - * DV_define_variable_path() - Define a path for text. - * ES_extra_space() - Set extra spacing (kerning) between characters. - * LB_label() - Display a label string. - * LO_label_origin() - Set the label origin. - * SA_select_alternate() - Select the alternate font. - * SD_define_standard() - Define the standard font... - * SI_absolute_size() - Set the absolute size of text. - * SL_character_slant() - Set the slant of text. - * SR_relative_size() - Set the relative size of text. - * SS_select_standard() - Select the standard font for text. - * TD_transparent_data() - Send transparent print data. - * - */ - -/* - * Include necessary headers... - */ - -#include "hpgltops.h" - - -/* - * 'define_font()' - Define the specified font... - */ - -void -define_font(int f) /* I - Font number */ -{ - font_t *font; /* Font */ - const char *fstring; /* Font string - SA or SS */ - float xform[2][2]; /* Transform matrix */ - - - /* - * Get the correct font data... - */ - - if (f) - { - font = &AlternateFont; - fstring = "SA"; - } - else - { - font = &StandardFont; - fstring = "SS"; - } - - /* - * Compute the font matrix, accounting for any rotation... - */ - - switch (Rotation) - { - default : - case 0 : - xform[0][0] = font->xpitch * font->x * font->height; - xform[0][1] = font->xpitch * font->y * font->height; - xform[1][0] = -font->y * font->height; - xform[1][1] = font->x * font->height; - break; - - case 90 : - xform[0][0] = -font->xpitch * font->y * font->height; - xform[0][1] = font->xpitch * font->x * font->height; - xform[1][0] = -font->x * font->height; - xform[1][1] = -font->y * font->height; - break; - - case 180 : - xform[0][0] = -font->xpitch * font->x * font->height; - xform[0][1] = -font->xpitch * font->y * font->height; - xform[1][0] = font->y * font->height; - xform[1][1] = -font->x * font->height; - break; - - case 270 : - xform[0][0] = font->xpitch * font->y * font->height; - xform[0][1] = -font->xpitch * font->x * font->height; - xform[1][0] = font->x * font->height; - xform[1][1] = font->y * font->height; - break; - } - - /* - * Send the font definition... - */ - - printf("/%s {\n" - " /%s%s%s%s findfont\n" - " [ %f %f %f %f 0.0 0.0 ] makefont\n" - " setfont\n" - "} bind def\n", - fstring, font->spacing ? "Helvetica" : "Courier", - (font->weight > 0 || font->posture) ? "-" : "", - font->weight > 0 ? "Bold" : "", - font->posture ? "Oblique" : "", - xform[0][0], xform[0][1], xform[1][0], xform[1][1]); - - if (f == CharFont) - printf("%s\n", fstring); -} - - -/* - * 'AD_define_alternate()' - Define the alternate font. - */ - -void -AD_define_alternate(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - int i; /* Looping var */ - - - /* - * Set default font attributes... - */ - - AlternateFont.symbol_set = 277; - AlternateFont.spacing = 0; - AlternateFont.pitch = 9; - AlternateFont.height = 11.5; - AlternateFont.posture = 0; - AlternateFont.weight = 0; - AlternateFont.typeface = 48; - AlternateFont.x = 1.0; - AlternateFont.y = 0.0; - - /* - * Loop through parameter value pairs... - */ - - for (i = 0; i < (num_params - 1); i += 2) - switch ((int)params[i].value.number) - { - case 1 : /* Symbol Set */ - AlternateFont.symbol_set = (int)params[i + 1].value.number; - break; - case 2 : /* Font Spacing */ - AlternateFont.spacing = (int)params[i + 1].value.number; - break; - case 3 : /* Pitch */ - AlternateFont.pitch = params[i + 1].value.number; - break; - case 4 : /* Height */ - AlternateFont.height = params[i + 1].value.number; - break; - case 5 : /* Posture */ - AlternateFont.posture = (int)params[i + 1].value.number; - break; - case 6 : /* Stroke Weight */ - AlternateFont.weight = (int)params[i + 1].value.number; - break; - case 7 : /* Typeface */ - AlternateFont.typeface = (int)params[i + 1].value.number; - break; - } - - if (AlternateFont.spacing) - { - /* - * Set proportional spacing font... - */ - - AlternateFont.xpitch = 1.0f; - } - else - { - /* - * Set fixed-spaced font... - */ - - AlternateFont.xpitch = 0.6f * AlternateFont.height / AlternateFont.pitch; - } - - /* - * Define the font... - */ - - if (PageDirty) - { - printf("%% AD"); - for (i = 0; i < num_params; i ++) - if (i) - printf(",%g", params[i].value.number); - else - printf("%g", params[i].value.number); - puts(";"); - - define_font(1); - } - - CharHeight[1] = AlternateFont.height; -} - - -/* - * 'CF_character_fill()' - Set whether or not to fill or outline characters. - */ - -void -CF_character_fill(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - if (num_params == 0) - CharFillMode = 0; - else - CharFillMode = (int)params[0].value.number; - - if (num_params == 2) - CharPen = (int)params[1].value.number; -} - - -/* - * 'CP_character_plot()' - Move the current pen position for the given number - * of columns and rows. - */ - -void -CP_character_plot(int num_params, - param_t *params) -{ - if (num_params < 2) - return; - - switch (Rotation) - { - case 0: - PenPosition[0] += params[0].value.number * 1.2f / CharHeight[CharFont]; - PenPosition[1] += params[1].value.number * CharHeight[CharFont]; - break; - case 90: - PenPosition[0] -= params[1].value.number * 1.2f / CharHeight[CharFont]; - PenPosition[1] += params[0].value.number * CharHeight[CharFont]; - break; - case 180: - PenPosition[0] -= params[0].value.number * 1.2f / CharHeight[CharFont]; - PenPosition[1] -= params[1].value.number * CharHeight[CharFont]; - break; - case 270: - PenPosition[0] += params[1].value.number * 1.2f / CharHeight[CharFont]; - PenPosition[1] -= params[0].value.number * CharHeight[CharFont]; - break; - } -} - - -/* - * 'DI_absolute_direction()' - Set the direction vector for text. - */ - -void -DI_absolute_direction(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - if (num_params != 2) - return; - - if (CharFont) - { - AlternateFont.x = params[0].value.number; - AlternateFont.y = params[1].value.number; - } - else - { - StandardFont.x = params[0].value.number; - StandardFont.y = params[1].value.number; - } - - if (PageDirty) - { - printf("%% DI%g,%g\n", params[0].value.number, params[1].value.number); - - define_font(CharFont); - } -} - - -/* - * 'DR_relative_direction()' - Set the relative direction vector for text. - */ - -void -DR_relative_direction(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - (void)num_params; - (void)params; -} - - -/* - * 'DT_define_label_term()' - Set the label string terminator. - */ - -void -DT_define_label_term(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - if (num_params == 0) - StringTerminator = '\003'; - else - StringTerminator = params[0].value.string[0]; -} - - -/* - * 'DV_define_variable_path()' - Define a path for text. - */ - -void -DV_define_variable_path(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - (void)num_params; - (void)params; -} - - -/* - * 'ES_extra_space()' - Set extra spacing (kerning) between characters. - */ - -void -ES_extra_space(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - (void)num_params; - (void)params; -} - - -/* - * 'LB_label()' - Display a label string. - */ - -void -LB_label(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - char *s; /* Pointer into string */ - - - if (num_params == 0) - return; - - Outputf("gsave\n"); - Outputf("currentmiterlimit 1.0 setmiterlimit\n"); - Outputf("MP\n"); - Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]); - PenValid = 1; - - Outputf("("); - for (s = params[0].value.string; *s != '\0'; s ++) - if (strchr("()\\", *s) != NULL) - Outputf("\\%c", *s); - else - Outputf("%c", *s); - Outputf(") true charpath\n"); - - if (CharFillMode != 1) - Outputf("FI\n"); - if (CharFillMode == 1 || CharFillMode == 3) - { - Outputf("%.3f %.3f %.3f %.2f SP ST\n", Pens[CharPen].rgb[0], - Pens[CharPen].rgb[CharPen], Pens[CharPen].rgb[2], - Pens[CharPen].width * PenScaling); - Outputf("%.3f %.3f %.3f %.2f SP\n", Pens[PenNumber].rgb[0], - Pens[PenNumber].rgb[1], Pens[PenNumber].rgb[2], - Pens[PenNumber].width * PenScaling); - } - - Outputf("setmiterlimit\n"); - Outputf("grestore\n"); -} - - -/* - * 'LO_label_origin()' - Set the label origin. - */ - -void -LO_label_origin(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - (void)num_params; - (void)params; -} - - -/* - * 'SA_select_alternate()' - Select the alternate font. - */ - -void -SA_select_alternate(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - (void)num_params; - (void)params; - - if (PageDirty) - puts("SA"); - - CharFont = 1; -} - - -/* - * 'SD_define_standard()' - Define the standard font... - */ - -void -SD_define_standard(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - int i; /* Looping var */ - - - /* - * Set default font attributes... - */ - - StandardFont.symbol_set = 277; - StandardFont.spacing = 0; - StandardFont.pitch = 9; - StandardFont.height = 11.5; - StandardFont.posture = 0; - StandardFont.weight = 0; - StandardFont.typeface = 48; - StandardFont.x = 1.0; - StandardFont.y = 0.0; - - /* - * Loop through parameter value pairs... - */ - - for (i = 0; i < (num_params - 1); i += 2) - switch ((int)params[i].value.number) - { - case 1 : /* Symbol Set */ - StandardFont.symbol_set = (int)params[i + 1].value.number; - break; - case 2 : /* Font Spacing */ - StandardFont.spacing = (int)params[i + 1].value.number; - break; - case 3 : /* Pitch */ - StandardFont.pitch = params[i + 1].value.number; - break; - case 4 : /* Height */ - StandardFont.height = params[i + 1].value.number; - break; - case 5 : /* Posture */ - StandardFont.posture = (int)params[i + 1].value.number; - break; - case 6 : /* Stroke Weight */ - StandardFont.weight = (int)params[i + 1].value.number; - break; - case 7 : /* Typeface */ - StandardFont.typeface = (int)params[i + 1].value.number; - break; - } - - if (StandardFont.spacing || StandardFont.pitch <= 0.0) - { - /* - * Set proportional spacing font... - */ - - StandardFont.xpitch = 1.0f; - } - else - { - /* - * Set fixed-spaced font... - */ - - StandardFont.xpitch = 0.6f * StandardFont.height / StandardFont.pitch; - } - - /* - * Define the font... - */ - - if (PageDirty) - { - printf("%% SD"); - for (i = 0; i < num_params; i ++) - if (i) - printf(",%g", params[i].value.number); - else - printf("%g", params[i].value.number); - puts(";"); - - define_font(0); - } - - CharHeight[0] = StandardFont.height; -} - - -/* - * 'SI_absolute_size()' - Set the absolute size of text. - */ - -void -SI_absolute_size(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - float xsize, ysize; /* Font size... */ - - - if (num_params != 2) - return; - - /* - * The "SI" values are supposed to be cm, but they appear to be inches - * when tested on real HP devices... - */ - - xsize = params[0].value.number * 72.0f; - ysize = params[1].value.number * 72.0f * 0.6f; - - if (CharFont) - { - AlternateFont.xpitch = xsize / ysize; - AlternateFont.height = ysize; - } - else - { - StandardFont.xpitch = xsize / ysize; - StandardFont.height = ysize; - } - - if (PageDirty) - { - printf("%% SI%g,%g\n", params[0].value.number, params[1].value.number); - - define_font(CharFont); - } -} - - -/* - * 'SL_character_slant()' - Set the slant of text. - */ - -void -SL_character_slant(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - (void)num_params; - (void)params; -} - - -/* - * 'SR_relative_size()' - Set the relative size of text. - */ - -void -SR_relative_size(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - (void)num_params; - (void)params; -} - - -/* - * 'SS_select_standard()' - Select the standard font for text. - */ - -void -SS_select_standard(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - (void)num_params; - (void)params; - - if (PageDirty) - puts("SS"); - - CharFont = 0; -} - - -/* - * 'TD_transparent_data()' - Send transparent print data. - */ - -void -TD_transparent_data(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - (void)num_params; - (void)params; -} - - -/* - * End of "$Id: hpgl-char.c 6649 2007-07-11 21:46:42Z mike $". - */ diff --git a/filter/hpgl-config.c b/filter/hpgl-config.c deleted file mode 100644 index 180674d79..000000000 --- a/filter/hpgl-config.c +++ /dev/null @@ -1,636 +0,0 @@ -/* - * "$Id: hpgl-config.c 6649 2007-07-11 21:46:42Z mike $" - * - * HP-GL/2 configuration routines for the Common UNIX Printing System (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/". - * - * This file is subject to the Apple OS-Developed Software exception. - * - * Contents: - * - * update_transform() - Update the page transformation matrix as needed. - * BP_begin_plot() - Start a plot... - * DF_default_values() - Set all state info to the default values. - * IN_initialize() - Initialize the plotter. - * IP_input_absolute() - Set P1 and P2 values for the plot. - * IR_input_relative() - Update P1 and P2. - * IW_input_window() - Setup an input window. - * PG_advance_page() - Eject the current page. - * PS_plot_size() - Set the plot size. - * RO_rotate() - Rotate the plot. - * RP_replot() - Replot the current page. - * SC_scale() - Set user-defined scaling. - */ - -/* - * Include necessary headers... - */ - -#include "hpgltops.h" - -#define max(a,b) ((a) < (b) ? (b) : (a)) - - -/* - * 'update_transform()' - Update the page transformation matrix as needed. - */ - -void -update_transform(void) -{ - float page_width, /* Actual page width */ - page_height; /* Actual page height */ - float scaling; /* Scaling factor */ - float left, right, /* Scaling window */ - bottom, top; - float width, height; /* Scaling width and height */ - float iw1[2], iw2[2]; /* Clipping window */ - - - /* - * Get the page and input window sizes... - */ - - if (FitPlot) - { - page_width = PageRight - PageLeft; - page_height = PageTop - PageBottom; - } - else - { - page_width = (P2[0] - P1[0]) * 72.0f / 1016.0f; - page_height = (P2[1] - P1[1]) * 72.0f / 1016.0f; - } - - fprintf(stderr, "DEBUG: page_width = %.0f, page_height = %.0f\n", - page_width, page_height); - - if (page_width == 0 || page_height == 0) - return; - - /* - * Set the scaling window... - */ - - switch (ScalingType) - { - default : /* No user scaling */ - left = P1[0]; - bottom = P1[1]; - right = P2[0]; - top = P2[1]; - break; - - case 0 : /* Anisotropic (non-uniform) scaling */ - left = Scaling1[0]; - bottom = Scaling1[1]; - right = Scaling2[0]; - top = Scaling2[1]; - break; - - case 1 : /* Isotropic (uniform) scaling */ - left = Scaling1[0]; - bottom = Scaling1[1]; - right = Scaling2[0]; - top = Scaling2[1]; - - width = right - left; - height = top - bottom; - - if (width == 0 || height == 0) - return; - - if ((width * page_height) != (height * page_width)) - { - scaling = height * page_width / page_height; - if (width < scaling) - { - width = scaling; - left = 0.5f * (left + right - width); - right = left + width; - } - else - { - height = width * page_height / page_width; - bottom = 0.5f * (bottom + top - height); - top = bottom + height; - } - } - break; - - case 2 : - left = Scaling1[0]; - bottom = Scaling1[1]; - right = left + page_width * Scaling2[0] * 1016.0f / 72.0f; - top = bottom + page_height * Scaling2[1] * 1016.0f / 72.0f; - break; - } - - width = right - left; - height = top - bottom; - - if (width == 0 || height == 0) - return; - - /* - * Scale the plot as needed... - */ - - if (Rotation == 0 || Rotation == 180) - scaling = page_width / width; - else - scaling = page_width / height; - - if (FitPlot) - scaling *= max(page_width, page_height) / max(PlotSize[1], PlotSize[0]); - - /* - * Offset for the current P1 location... - */ - - if (FitPlot) - { - left = 0; - bottom = 0; - } - else - { - left = P1[0] * 72.0f / 1016.0f; - bottom = P1[1] * 72.0f / 1016.0f; - } - - /* - * Generate a new transformation matrix... - */ - - switch (Rotation) - { - default : - case 0 : - Transform[0][0] = scaling; - Transform[0][1] = 0.0; - Transform[0][2] = -left; - Transform[1][0] = 0.0; - Transform[1][1] = scaling; - Transform[1][2] = -bottom; - break; - - case 90 : - Transform[0][0] = 0.0; - Transform[0][1] = -scaling; - Transform[0][2] = PageLength - left; - Transform[1][0] = scaling; - Transform[1][1] = 0.0; - Transform[1][2] = -bottom; - break; - - case 180 : - Transform[0][0] = -scaling; - Transform[0][1] = 0.0; - Transform[0][2] = PageLength - left; - Transform[1][0] = 0.0; - Transform[1][1] = -scaling; - Transform[1][2] = PageWidth - bottom; - break; - - case 270 : - Transform[0][0] = 0.0; - Transform[0][1] = scaling; - Transform[0][2] = -left; - Transform[1][0] = -scaling; - Transform[1][1] = 0.0; - Transform[1][2] = PageWidth - bottom; - break; - } - - fprintf(stderr, "DEBUG: Transform = [ %.3f %.3f\n" - "DEBUG: %.3f %.3f\n" - "DEBUG: %.3f %.3f ]\n", - Transform[0][0], Transform[1][0], Transform[0][1], - Transform[1][1], Transform[0][2], Transform[1][2]); - - if (FitPlot) - { - if (Rotation == 0 || Rotation == 180) - PenScaling = page_width / PlotSize[1]; - else - PenScaling = page_width / PlotSize[0]; - } - else - PenScaling = 1.0; - - if (PenScaling < 0.0) - PenScaling = -PenScaling; - - if (PageDirty) - { - printf("%.2f setlinewidth\n", Pens[PenNumber].width * PenScaling); - - if (IW1[0] != IW2[0] && IW1[1] != IW2[1]) - { - iw1[0] = IW1[0] * 72.0f / 1016.0f; - iw1[1] = IW1[1] * 72.0f / 1016.0f; - iw2[0] = IW2[0] * 72.0f / 1016.0f; - iw2[1] = IW2[1] * 72.0f / 1016.0f; - - printf("initclip MP %.3f %.3f MO %.3f %.3f LI %.3f %.3f LI %.3f %.3f LI CP clip\n", - iw1[0], iw1[1], iw1[0], iw2[1], iw2[0], iw2[1], iw2[0], iw1[1]); - } - } -} - - -/* - * 'BP_begin_plot()' - Start a plot... - */ - -void -BP_begin_plot(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - (void)num_params; - (void)params; -} - - -/* - * 'DF_default_values()' - Set all state info to the default values. - */ - -void -DF_default_values(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - (void)num_params; - (void)params; - - NP_number_pens(0, NULL); - AC_anchor_corner(0, NULL); - AD_define_alternate(0, NULL); - SD_define_standard(0, NULL); - CF_character_fill(0, NULL); - DI_absolute_direction(0, NULL); - DT_define_label_term(0, NULL); - DV_define_variable_path(0, NULL); - ES_extra_space(0, NULL); - FT_fill_type(0, NULL); - IW_input_window(0, NULL); - LA_line_attributes(0, NULL); - LO_label_origin(0, NULL); - LT_line_type(0, NULL); - PA_plot_absolute(0, NULL); - PolygonMode = 0; - RF_raster_fill(0, NULL); - SC_scale(0, NULL); - SM_symbol_mode(0, NULL); - SS_select_standard(0, NULL); - TD_transparent_data(0, NULL); - UL_user_line_type(0, NULL); -} - - -/* - * 'IN_initialize()' - Initialize the plotter. - */ - -void -IN_initialize(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - (void)num_params; - (void)params; - - DF_default_values(0, NULL); - PU_pen_up(0, NULL); - RO_rotate(0, NULL); - PS_plot_size(0, NULL); - WU_width_units(0, NULL); - PW_pen_width(0, NULL); - - PenWidth = 1; - - PenPosition[0] = PenPosition[1] = 0.0; -} - - -/* - * 'IP_input_absolute()' - Set P1 and P2 values for the plot. - */ - -void -IP_input_absolute(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - if (num_params == 0) - { - P1[0] = PageLeft / 72.0f * 1016.0f; - P1[1] = PageBottom / 72.0f * 1016.0f; - P2[0] = PageRight / 72.0f * 1016.0f; - P2[1] = PageTop / 72.0f * 1016.0f; - } - else if (num_params == 2) - { - P2[0] -= P1[0]; - P2[1] -= P1[1]; - P1[0] = params[0].value.number; - P1[1] = params[1].value.number; - P2[0] += P1[0]; - P2[1] += P1[1]; - } - else if (num_params == 4) - { - P1[0] = params[0].value.number; - P1[1] = params[1].value.number; - P2[0] = params[2].value.number; - P2[1] = params[3].value.number; - } - - IW1[0] = 0.0; - IW1[1] = 0.0; - IW2[0] = 0.0; - IW2[1] = 0.0; - - if (ScalingType < 0) - { - Scaling1[0] = P1[0]; - Scaling1[0] = P1[1]; - Scaling2[0] = P2[0]; - Scaling2[1] = P2[1]; - } - - update_transform(); -} - - -/* - * 'IR_input_relative()' - Update P1 and P2. - */ - -void -IR_input_relative(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - if (num_params == 0) - { - P1[0] = PageLeft / 72.0f * 1016.0f; - P1[1] = PageBottom / 72.0f * 1016.0f; - P2[0] = PageRight / 72.0f * 1016.0f; - P2[1] = PageTop / 72.0f * 1016.0f; - } - else if (num_params == 2) - { - P2[0] -= P1[0]; - P2[1] -= P1[1]; - P1[0] = params[0].value.number * PlotSize[0] / 72.0f * 1016.0f / 100.0f; - P1[1] = params[1].value.number * PlotSize[1] / 72.0f * 1016.0f / 100.0f; - P2[0] += P1[0]; - P2[1] += P1[1]; - } - else if (num_params == 4) - { - P1[0] = params[0].value.number * PlotSize[0] / 72.0f * 1016.0f / 100.0f; - P1[1] = params[1].value.number * PlotSize[1] / 72.0f * 1016.0f / 100.0f; - P2[0] = params[2].value.number * PlotSize[0] / 72.0f * 1016.0f / 100.0f; - P2[1] = params[3].value.number * PlotSize[1] / 72.0f * 1016.0f / 100.0f; - } - - IW1[0] = 0.0; - IW1[1] = 0.0; - IW2[0] = 0.0; - IW2[1] = 0.0; - - if (ScalingType < 0) - { - Scaling1[0] = P1[0]; - Scaling1[0] = P1[1]; - Scaling2[0] = P2[0]; - Scaling2[1] = P2[1]; - } - - update_transform(); -} - - -/* - * 'IW_input_window()' - Setup an input window. - */ - -void -IW_input_window(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - if (num_params == 0) - { - IW1[0] = PageLeft / 72.0f * 1016.0f; - IW1[1] = PageBottom / 72.0f * 1016.0f; - IW2[0] = PageRight / 72.0f * 1016.0f; - IW2[1] = PageTop / 72.0f * 1016.0f; - } - else if (num_params == 4) - { - - if (ScalingType < 0) - { - IW1[0] = params[0].value.number; - IW1[1] = params[1].value.number; - IW2[0] = params[2].value.number; - IW2[1] = params[3].value.number; - } - else - { - IW1[0] = (Transform[0][0] * params[0].value.number + - Transform[0][1] * params[1].value.number + - Transform[0][2]) / 72.0f * 1016.0f; - IW1[1] = (Transform[1][0] * params[0].value.number + - Transform[1][1] * params[1].value.number + - Transform[1][2]) / 72.0f * 1016.0f; - IW2[0] = (Transform[0][0] * params[2].value.number + - Transform[0][1] * params[3].value.number + - Transform[0][2]) / 72.0f * 1016.0f; - IW2[1] = (Transform[1][0] * params[2].value.number + - Transform[1][1] * params[3].value.number + - Transform[1][2]) / 72.0f * 1016.0f; - } - - fprintf(stderr, "DEBUG: IW%.0f,%.0f,%.0f,%.0f = [ %.0f %.0f %.0f %.0f ]\n", - params[0].value.number, params[1].value.number, - params[2].value.number, params[3].value.number, - IW1[0], IW1[1], IW2[0], IW2[1]); - } - - - update_transform(); -} - - -/* - * 'PG_advance_page()' - Eject the current page. - */ - -void -PG_advance_page(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - (void)num_params; - (void)params; - - if (PageDirty) - { - puts("grestore"); - puts("showpage"); - - PageDirty = 0; - } -} - - -/* - * 'PS_plot_size()' - Set the plot size. - */ - -void -PS_plot_size(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - switch (num_params) - { - case 0 : /* PS ; */ - if (Rotation == 0 || Rotation == 180) - { - PlotSize[0] = PageWidth; - PlotSize[1] = PageLength; - } - else - { - PlotSize[0] = PageLength; - PlotSize[1] = PageWidth; - } - - PlotSizeSet = 0; - break; - case 1 : /* PS length ; */ - if (Rotation == 0 || Rotation == 180) - { - PlotSize[1] = 72.0f * params[0].value.number / 1016.0f; - PlotSize[0] = 0.75f * PlotSize[1]; - } - else - { - PlotSize[0] = 72.0f * params[0].value.number / 1016.0f; - PlotSize[1] = 0.75f * PlotSize[0]; - } - - PlotSizeSet = 1; - break; - case 2 : /* PS length, width ; */ - /* - * Unfortunately, it appears that NO application correctly - * sends a two-argument PS command as documented in the - * HP-GL/2 Reference Manual from HP. Instead, applications - * send the width before the length, which causes all sorts - * of problems when scaling. - * - * Rather than fight it, we now look for them as width,length - * instead of length,width. - * - * Don't like it? Send mail to the folks that make Ideas, Pro/E, - * AutoCAD, etc. - */ - - if (Rotation == 0 || Rotation == 180) - { - PlotSize[0] = 72.0f * params[0].value.number / 1016.0f; - PlotSize[1] = 72.0f * params[1].value.number / 1016.0f; - } - else - { - PlotSize[0] = 72.0f * params[1].value.number / 1016.0f; - PlotSize[1] = 72.0f * params[0].value.number / 1016.0f; - } - - PlotSizeSet = 1; - break; - } - - /* - * This is required for buggy files that don't set the input window. - */ - - IP_input_absolute(0, NULL); -} - - -/* - * 'RO_rotate()' - Rotate the plot. - */ - -void -RO_rotate(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - if (num_params == 0) - Rotation = 0; - else - Rotation = (int)params[0].value.number; - - update_transform(); -} - - -/* - * 'RP_replot()' - Replot the current page. - */ - -void -RP_replot(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - (void)num_params; - (void)params; -} - - -/* - * 'SC_scale()' - Set user-defined scaling. - */ - -void -SC_scale(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - if (num_params == 0) - { - ScalingType = -1; - Scaling1[0] = P1[0]; - Scaling1[0] = P1[1]; - Scaling2[0] = P2[0]; - Scaling2[1] = P2[1]; - } - else if (num_params > 3) - { - Scaling1[0] = params[0].value.number; - Scaling2[0] = params[1].value.number; - Scaling1[1] = params[2].value.number; - Scaling2[1] = params[3].value.number; - - if (num_params > 4) - ScalingType = (int)params[4].value.number; - else - ScalingType = 1; - } - - update_transform(); -} - - -/* - * End of "$Id: hpgl-config.c 6649 2007-07-11 21:46:42Z mike $". - */ diff --git a/filter/hpgl-input.c b/filter/hpgl-input.c deleted file mode 100644 index 195094c75..000000000 --- a/filter/hpgl-input.c +++ /dev/null @@ -1,272 +0,0 @@ -/* - * "$Id: hpgl-input.c 7219 2008-01-14 22:00:02Z mike $" - * - * HP-GL/2 input processing for the Common UNIX Printing System (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/". - * - * This file is subject to the Apple OS-Developed Software exception. - * - * Contents: - * - * ParseCommand() - Parse an HPGL/2 command. - * FreeParameters() - Free all string parameter values. - */ - -/* - * Include necessary headers... - */ - -#include "hpgltops.h" -#include -#include - -#define MAX_PARAMS 16384 - - -/* - * 'ParseCommand()' - Parse an HPGL/2 command. - * - * Returns the number of parameters seen or -1 on EOF. - */ - -int /* O - -1 on EOF, # params otherwise */ -ParseCommand(FILE *fp, /* I - File to read from */ - char *name, /* O - Name of command */ - param_t **params) /* O - Parameter list */ -{ - int num_params, /* Number of parameters seen */ - ch, /* Current char */ - done, /* Non-zero when the current command is read */ - i; /* Looping var */ - char buf[262144], /* String buffer */ - *bufptr; /* Pointer into buffer */ - float temp; /* Temporary parameter value */ - static param_t p[MAX_PARAMS]; /* Parameter buffer */ - - - num_params = 0; - done = 0; - - do - { - while ((ch = getc(fp)) != EOF) - if (strchr(" \t\r\n,;", ch) == NULL) - break; - - if (ch == EOF) - { - return (-1); - } - - if (ch == 0x1b) - switch (getc(fp)) - { - case '.' : /* HP-GL/2 job control */ - i = getc(fp); - - if (strchr(")Z", i) != NULL) - { - /* - * 'Printer Off' command - look for next 'Printer On' command... - */ - - for (;;) - { - while ((i = getc(fp)) != EOF && i != 0x1b); - - if (i == EOF) - return (-1); - - if (getc(fp) != '.') - continue; - - if ((i = getc(fp)) == '(' || - i == 'Y') - break; - } - } - else if (strchr("@HIMNTI\003", i) != NULL) - { - while ((i = getc(fp)) != EOF && i != ':'); - } - break; - - case '%' : /* PJL command? */ - if ((i = getc(fp)) == '-') - if ((i = getc(fp)) == '1') - if ((i = getc(fp)) == '2') - { - /* - * Yes, dump everything up to the "ENTER LANGUAGE" line... - */ - - while (fgets(buf, sizeof(buf), fp) != NULL) - if (strstr(buf, "ENTER") && strstr(buf, "LANGUAGE")) - break; - break; - } - - ungetc(i, fp); - - default : /* HP RTL/PCL control */ - while ((i = getc(fp)) != EOF && !isupper(i & 255)); - - if (i == EOF) - return (-1); - break; - } - } while (ch < ' '); - - name[0] = ch; - name[1] = getc(fp); - name[2] = '\0'; - - if (name[1] < ' ') - { - /* - * If we get here, then more than likely we are faced with a raw PCL - * file which we can't handle - abort! - */ - - fputs(_("ERROR: Invalid HP-GL/2 command seen, unable to print file\n"), - stderr); - return (-1); - } - - if (!strcasecmp(name, "LB")) - { - bufptr = buf; - while ((ch = getc(fp)) != StringTerminator && ch != EOF) - if (bufptr < (buf + sizeof(buf) - 1)) - *bufptr++ = ch; - *bufptr = '\0'; - - p[num_params].type = PARAM_STRING; - p[num_params].value.string = strdup(buf); - num_params ++; - } - else if (!strcasecmp(name, "SM")) - { - buf[0] = getc(fp); - buf[1] = '\0'; - p[num_params].type = PARAM_STRING; - p[num_params].value.string = strdup(buf); - num_params ++; - } - else if (!strcasecmp(name, "DT")) - { - if ((buf[0] = getc(fp)) != ';') - { - buf[1] = '\0'; - p[num_params].type = PARAM_STRING; - p[num_params].value.string = strdup(buf); - num_params ++; - } - } - else if (!strcasecmp(name, "PE")) - { - bufptr = buf; - while ((ch = getc(fp)) != ';') - if (ch == EOF) - break; - else if (bufptr < (buf + sizeof(buf) - 1)) - *bufptr++ = ch; - *bufptr = '\0'; - - p[num_params].type = PARAM_STRING; - p[num_params].value.string = strdup(buf); - num_params ++; - } - - while (!done) - switch (ch = getc(fp)) - { - case EOF : - done = 1; - break; - - case ',' : - case ' ' : - case '\n' : - case '\r' : - case '\t' : - break; - - case '\"' : - fscanf(fp, "%262143[^\"]\"", buf); - if (num_params < MAX_PARAMS) - { - p[num_params].type = PARAM_STRING; - p[num_params].value.string = strdup(buf); - num_params ++; - }; - break; - - case '-' : - case '+' : - ungetc(ch, fp); - if (fscanf(fp, "%f", &temp) == 1 && num_params < MAX_PARAMS) - { - p[num_params].type = PARAM_RELATIVE; - p[num_params].value.number = temp; - num_params ++; - } - break; - case '0' : - case '1' : - case '2' : - case '3' : - case '4' : - case '5' : - case '6' : - case '7' : - case '8' : - case '9' : - case '.' : - ungetc(ch, fp); - if (fscanf(fp, "%f", &temp) == 1 && num_params < MAX_PARAMS) - { - p[num_params].type = PARAM_ABSOLUTE; - p[num_params].value.number = temp; - num_params ++; - } - break; - default : - ungetc(ch, fp); - done = 1; - break; - } - - *params = p; - return (num_params); -} - - -/* - * 'FreeParameters()' - Free all string parameter values. - */ - -void -FreeParameters(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameter values */ -{ - int i; /* Looping var */ - - - for (i = 0; i < num_params; i ++) - if (params[i].type == PARAM_STRING) - free(params[i].value.string); -} - - -/* - * End of "$Id: hpgl-input.c 7219 2008-01-14 22:00:02Z mike $". - */ diff --git a/filter/hpgl-main.c b/filter/hpgl-main.c deleted file mode 100644 index 953d44702..000000000 --- a/filter/hpgl-main.c +++ /dev/null @@ -1,269 +0,0 @@ -/* - * "$Id: hpgl-main.c 6649 2007-07-11 21:46:42Z mike $" - * - * HP-GL/2 filter main entry for the Common UNIX Printing System (CUPS). - * - * Copyright 2007-2008 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 HP-GL/2 filter. - * compare_names() - Compare two command names. - */ - -/* - * Include necessary headers... - */ - -/*#define DEBUG*/ -#define _HPGL_MAIN_C_ -#include "hpgltops.h" -#include - - -/* - * HP-GL/2 command table... - */ - -typedef struct -{ - char name[4]; /* Name of command */ - void (*func)(int, param_t *); /* Function to call */ -} name_t; - -static name_t commands[] = -{ - { "BP", BP_begin_plot }, - { "DF", DF_default_values }, - { "IN", IN_initialize }, - { "IP", IP_input_absolute }, - { "IR", IR_input_relative }, - { "IW", IW_input_window }, - { "PG", PG_advance_page }, - { "RO", RO_rotate }, - { "RP", RP_replot }, - { "SC", SC_scale }, - { "AA", AA_arc_absolute }, - { "AR", AR_arc_relative }, - { "AT", AT_arc_absolute3 }, - { "CI", CI_circle }, - { "PA", PA_plot_absolute }, - { "PD", PD_pen_down }, - { "PE", PE_polyline_encoded }, - { "PR", PR_plot_relative }, - { "PS", PS_plot_size }, - { "PU", PU_pen_up }, - { "RT", RT_arc_relative3 }, - { "EA", EA_edge_rect_absolute }, - { "EP", EP_edge_polygon }, - { "ER", ER_edge_rect_relative }, - { "EW", EW_edge_wedge }, - { "FP", FP_fill_polygon }, - { "PM", PM_polygon_mode }, - { "RA", RA_fill_rect_absolute }, - { "RR", RR_fill_rect_relative }, - { "WG", WG_fill_wedge }, - { "AD", AD_define_alternate }, - { "CF", CF_character_fill }, - { "CP", CP_character_plot }, - { "DI", DI_absolute_direction }, - { "DR", DR_relative_direction }, - { "DT", DT_define_label_term }, - { "DV", DV_define_variable_path }, - { "ES", ES_extra_space }, - { "LB", LB_label }, - { "LO", LO_label_origin }, - { "SA", SA_select_alternate }, - { "SD", SD_define_standard }, - { "SI", SI_absolute_size }, - { "SL", SL_character_slant }, - { "SR", SR_relative_size }, - { "SS", SS_select_standard }, - { "TD", TD_transparent_data }, - { "AC", AC_anchor_corner }, - { "FT", FT_fill_type }, - { "LA", LA_line_attributes }, - { "LT", LT_line_type }, - { "NP", NP_number_pens }, - { "PC", PC_pen_color }, - { "CR", CR_color_range }, - { "PW", PW_pen_width }, - { "RF", RF_raster_fill }, - { "SM", SM_symbol_mode }, - { "SP", SP_select_pen }, - { "UL", UL_user_line_type }, - { "WU", WU_width_units } -}; -#define NUM_COMMANDS (sizeof(commands) / sizeof(name_t)) - - -/* - * Local functions... - */ - -static int compare_names(const void *p1, const void *p2); - - -/* - * 'main()' - Main entry for HP-GL/2 filter. - */ - -int /* O - Exit status */ -main(int argc, /* I - Number of command-line arguments */ - char *argv[]) /* I - Command-line arguments */ -{ - FILE *fp; /* Input file */ - int num_params; /* Number of parameters */ - param_t *params; /* Command parameters */ - name_t *command, /* Command */ - name; /* Name of command */ - int num_options; /* Number of print options */ - cups_option_t *options; /* Print options */ - const char *val; /* Option value */ - int shading; /* -1 = black, 0 = grey, 1 = color */ - - - /* - * Make sure status messages are not buffered... - */ - - setbuf(stdout, NULL); - setbuf(stderr, NULL); - - /* - * Check command-line... - */ - - if (argc < 6 || argc > 7) - { - fprintf(stderr, _("Usage: %s job-id user title copies options [file]\n"), - argv[0]); - return (1); - } - - /* - * If we have 7 arguments, print the file named on the command-line. - * Otherwise, send stdin instead... - */ - - if (argc == 6) - fp = stdin; - 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); - - PPD = SetCommonOptions(num_options, options, 1); - - PlotSize[0] = PageWidth; - PlotSize[1] = PageLength; - - shading = 1; - PenWidth = 1.0; - - if ((val = cupsGetOption("blackplot", num_options, options)) != NULL && - strcasecmp(val, "no") && strcasecmp(val, "off") && - strcasecmp(val, "false")) - shading = 0; - - if ((val = cupsGetOption("fitplot", num_options, options)) != NULL && - !strcasecmp(val, "true")) - FitPlot = 1; - else if ((val = cupsGetOption("fit-to-page", num_options, options)) != NULL && - !strcasecmp(val, "true")) - FitPlot = 1; - - if ((val = cupsGetOption("penwidth", num_options, options)) != NULL) - PenWidth = (float)atoi(val) * 0.001f; - - /* - * Write the PostScript prolog and initialize the plotting "engine"... - */ - - OutputProlog(argv[3], argv[2], shading); - - IP_input_absolute(0, NULL); - - /* - * Sort the command array... - */ - - qsort(commands, NUM_COMMANDS, sizeof(name_t), - (int (*)(const void *, const void *))compare_names); - - /* - * Read commands until we reach the end of file. - */ - - while ((num_params = ParseCommand(fp, name.name, ¶ms)) >= 0) - { - Outputf("%% %s(%d)\n", name.name, num_params); - -#ifdef DEBUG - { - int i; - fprintf(stderr, "DEBUG: %s(%d)", name.name, num_params); - for (i = 0; i < num_params; i ++) - if (params[i].type == PARAM_STRING) - fprintf(stderr, " \'%s\'", params[i].value.string); - else - fprintf(stderr, " %f", params[i].value.number); - fputs("\n", stderr); - } -#endif /* DEBUG */ - - if ((command = bsearch(&name, commands, NUM_COMMANDS, sizeof(name_t), - (int (*)(const void *, const void *))compare_names)) != NULL) - (*command->func)(num_params, params); - - FreeParameters(num_params, params); - } - - OutputTrailer(); - - if (fp != stdin) - fclose(fp); - - return (0); -} - - -/* - * 'compare_names()' - Compare two command names. - */ - -static int /* O - Result of strcasecmp() on names */ -compare_names(const void *p1, /* I - First name */ - const void *p2) /* I - Second name */ -{ - return (strcasecmp(((name_t *)p1)->name, ((name_t *)p2)->name)); -} - - -/* - * End of "$Id: hpgl-main.c 6649 2007-07-11 21:46:42Z mike $". - */ diff --git a/filter/hpgl-polygon.c b/filter/hpgl-polygon.c deleted file mode 100644 index 6f8df01c3..000000000 --- a/filter/hpgl-polygon.c +++ /dev/null @@ -1,385 +0,0 @@ -/* - * "$Id: hpgl-polygon.c 6649 2007-07-11 21:46:42Z mike $" - * - * HP-GL/2 polygon routines for the Common UNIX Printing System (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/". - * - * This file is subject to the Apple OS-Developed Software exception. - * - * Contents: - * - * EA_edge_rect_absolute() - Draw a rectangle. - * EP_edge_polygon() - Stroke the edges of a polygon. - * ER_edge_rect_relative() - Draw a rectangle relative to the current - * EW_edge_wedge() - Draw a pie wedge. - * FP_fill_polygon() - Fill a polygon. - * PM_polygon_mode() - Set the polygon drawing mode. - * RA_fill_rect_absolute() - Fill a rectangle. - * RR_fill_rect_relative() - Fill a rectangle relative to the current - * WG_fill_wedge() - Fill a pie wedge. - */ - -/* - * Include necessary headers... - */ - -#include "hpgltops.h" - - -/* - * 'EA_edge_rect_absolute()' - Draw a rectangle. - */ - -void -EA_edge_rect_absolute(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - float x, y; /* Transformed coordinates */ - - - if (num_params < 2) - return; - - x = Transform[0][0] * params[0].value.number + - Transform[0][1] * params[1].value.number + - Transform[0][2]; - y = Transform[1][0] * params[0].value.number + - Transform[1][1] * params[1].value.number + - Transform[1][2]; - - if (!PolygonMode) - Outputf("MP\n"); - - PenValid = 1; - - Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]); - Outputf("%.3f %.3f LI\n", PenPosition[0], y); - Outputf("%.3f %.3f LI\n", x, y); - Outputf("%.3f %.3f LI\n", x, PenPosition[1]); - - Outputf("CP\n"); - if (!PolygonMode) - Outputf("ST\n"); -} - - -/* - * 'EP_edge_polygon()' - Stroke the edges of a polygon. - */ - -void -EP_edge_polygon(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - (void)num_params; - (void)params; - - Outputf("ST\n"); -} - - -/* - * 'ER_edge_rect_relative()' - Draw a rectangle relative to the current - * pen position. - */ - -void -ER_edge_rect_relative(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - float x, y; /* Transformed coordinates */ - - - if (num_params < 2) - return; - - x = Transform[0][0] * params[0].value.number + - Transform[0][1] * params[1].value.number + - PenPosition[0]; - y = Transform[1][0] * params[0].value.number + - Transform[1][1] * params[1].value.number + - PenPosition[1]; - - if (!PolygonMode) - Outputf("MP\n"); - - PenValid = 1; - - Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]); - Outputf("%.3f %.3f LI\n", PenPosition[0], y); - Outputf("%.3f %.3f LI\n", x, y); - Outputf("%.3f %.3f LI\n", x, PenPosition[1]); - - Outputf("CP\n"); - if (!PolygonMode) - Outputf("ST\n"); -} - - -/* - * 'EW_edge_wedge()' - Draw a pie wedge. - */ - -void -EW_edge_wedge(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - float x, y; /* Transformed coordinates */ - float start, end, /* Start and end of arc */ - theta, /* Current angle */ - dt, /* Step between points */ - radius; /* Radius of arc */ - - - if (num_params < 3) - return; - - radius = params[0].value.number; - start = params[1].value.number; - end = start + params[2].value.number; - - if (num_params > 3) - dt = (float)fabs(params[3].value.number); - else - dt = 5.0f; - - if (!PolygonMode) - Outputf("MP\n"); - - PenValid = 1; - - Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]); - - if (start < end) - for (theta = start + dt; theta < end; theta += dt) - { - x = (float)(PenPosition[0] + - radius * cos(M_PI * theta / 180.0) * Transform[0][0] + - radius * sin(M_PI * theta / 180.0) * Transform[0][1]); - y = (float)(PenPosition[1] + - radius * cos(M_PI * theta / 180.0) * Transform[1][0] + - radius * sin(M_PI * theta / 180.0) * Transform[1][1]); - - Outputf("%.3f %.3f LI\n", x, y); - } - else - for (theta = start - dt; theta > end; theta -= dt) - { - x = (float)(PenPosition[0] + - radius * cos(M_PI * theta / 180.0) * Transform[0][0] + - radius * sin(M_PI * theta / 180.0) * Transform[0][1]); - y = (float)(PenPosition[1] + - radius * cos(M_PI * theta / 180.0) * Transform[1][0] + - radius * sin(M_PI * theta / 180.0) * Transform[1][1]); - - Outputf("%.3f %.3f LI\n", x, y); - } - - x = (float)(PenPosition[0] + - radius * cos(M_PI * end / 180.0) * Transform[0][0] + - radius * sin(M_PI * end / 180.0) * Transform[0][1]); - y = (float)(PenPosition[1] + - radius * cos(M_PI * end / 180.0) * Transform[1][0] + - radius * sin(M_PI * end / 180.0) * Transform[1][1]); - Outputf("%.3f %.3f LI\n", x, y); - - Outputf("CP\n"); - if (!PolygonMode) - Outputf("ST\n"); -} - - -/* - * 'FP_fill_polygon()' - Fill a polygon. - */ - -void -FP_fill_polygon(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - (void)num_params; - (void)params; - - Outputf("FI\n"); -} - - -/* - * 'PM_polygon_mode()' - Set the polygon drawing mode. - */ - -void -PM_polygon_mode(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - if (num_params == 0 || - params[0].value.number == 0) - { - Outputf("MP\n"); - PenValid = 0; - PolygonMode = 1; - } - else if (params[0].value.number == 2) - PolygonMode = 0; -} - - -/* - * 'RA_fill_rect_absolute()' - Fill a rectangle. - */ - -void -RA_fill_rect_absolute(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - float x, y; /* Transformed coordinates */ - - - if (num_params < 2) - return; - - x = Transform[0][0] * params[0].value.number + - Transform[0][1] * params[1].value.number + - Transform[0][2]; - y = Transform[1][0] * params[0].value.number + - Transform[1][1] * params[1].value.number + - Transform[1][2]; - - if (!PolygonMode) - Outputf("MP\n"); - - PenValid = 1; - - Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]); - Outputf("%.3f %.3f LI\n", PenPosition[0], y); - Outputf("%.3f %.3f LI\n", x, y); - Outputf("%.3f %.3f LI\n", x, PenPosition[1]); - - Outputf("CP\n"); - if (!PolygonMode) - Outputf("FI\n"); -} - - -/* - * 'RR_fill_rect_relative()' - Fill a rectangle relative to the current - * pen position. - */ - -void -RR_fill_rect_relative(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - float x, y; /* Transformed coordinates */ - - - if (num_params < 2) - return; - - x = Transform[0][0] * params[0].value.number + - Transform[0][1] * params[1].value.number + - PenPosition[0]; - y = Transform[1][0] * params[0].value.number + - Transform[1][1] * params[1].value.number + - PenPosition[1]; - - if (!PolygonMode) - Outputf("MP\n"); - - PenValid = 1; - - Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]); - Outputf("%.3f %.3f LI\n", PenPosition[0], y); - Outputf("%.3f %.3f LI\n", x, y); - Outputf("%.3f %.3f LI\n", x, PenPosition[1]); - - Outputf("CP\n"); - if (!PolygonMode) - Outputf("FI\n"); -} - - -/* - * 'WG_fill_wedge()' - Fill a pie wedge. - */ - -void -WG_fill_wedge(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - float x, y; /* Transformed coordinates */ - float start, end, /* Start and end angles */ - theta, /* Current angle */ - dt, /* Step between points */ - radius; /* Radius of arc */ - - - if (num_params < 3) - return; - - radius = params[0].value.number; - start = params[1].value.number; - end = start + params[2].value.number; - - if (num_params > 3) - dt = (float)fabs(params[3].value.number); - else - dt = 5.0; - - if (!PolygonMode) - Outputf("MP\n"); - - PenValid = 1; - - Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]); - - if (start < end) - for (theta = start + dt; theta < end; theta += dt) - { - x = (float)(PenPosition[0] + - radius * cos(M_PI * theta / 180.0) * Transform[0][0] + - radius * sin(M_PI * theta / 180.0) * Transform[0][1]); - y = (float)(PenPosition[1] + - radius * cos(M_PI * theta / 180.0) * Transform[1][0] + - radius * sin(M_PI * theta / 180.0) * Transform[1][1]); - - Outputf("%.3f %.3f LI\n", x, y); - } - else - for (theta = start - dt; theta > end; theta -= dt) - { - x = (float)(PenPosition[0] + - radius * cos(M_PI * theta / 180.0) * Transform[0][0] + - radius * sin(M_PI * theta / 180.0) * Transform[0][1]); - y = (float)(PenPosition[1] + - radius * cos(M_PI * theta / 180.0) * Transform[1][0] + - radius * sin(M_PI * theta / 180.0) * Transform[1][1]); - - Outputf("%.3f %.3f LI\n", x, y); - } - - x = (float)(PenPosition[0] + - radius * cos(M_PI * end / 180.0) * Transform[0][0] + - radius * sin(M_PI * end / 180.0) * Transform[0][1]); - y = (float)(PenPosition[1] + - radius * cos(M_PI * end / 180.0) * Transform[1][0] + - radius * sin(M_PI * end / 180.0) * Transform[1][1]); - Outputf("%.3f %.3f LI\n", x, y); - - Outputf("CP\n"); - if (!PolygonMode) - Outputf("FI\n"); -} - - -/* - * End of "$Id: hpgl-polygon.c 6649 2007-07-11 21:46:42Z mike $". - */ diff --git a/filter/hpgl-prolog.c b/filter/hpgl-prolog.c deleted file mode 100644 index 00e512b7a..000000000 --- a/filter/hpgl-prolog.c +++ /dev/null @@ -1,369 +0,0 @@ -/* - * "$Id: hpgl-prolog.c 6649 2007-07-11 21:46:42Z mike $" - * - * HP-GL/2 prolog routines for for the Common UNIX Printing System (CUPS). - * - * Copyright 2007 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: - * - * OutputProlog() - Output the PostScript prolog... - * OutputTrailer() - Output the PostScript trailer... - * Outputf() - Write a formatted string to the output file, creating the - * page header as needed... - */ - -/* - * Include necessary headers... - */ - -#include "hpgltops.h" -#include - - -/* - * 'OutputProlog()' - Output the PostScript prolog... - */ - -void -OutputProlog(char *title, /* I - Job title */ - char *user, /* I - Username */ - int shading) /* I - Type of shading */ -{ - FILE *prolog; /* Prolog file */ - char line[255]; /* Line from prolog file */ - const char *datadir; /* CUPS_DATADIR environment variable */ - char filename[1024]; /* Name of prolog file */ - time_t curtime; /* Current time */ - struct tm *curtm; /* Current date */ - - - curtime = time(NULL); - curtm = localtime(&curtime); - - puts("%!PS-Adobe-3.0"); - printf("%%%%BoundingBox: %.0f %.0f %.0f %.0f\n", - PageLeft, PageBottom, PageRight, PageTop); - puts("%%Pages: (atend)"); - printf("%%%%LanguageLevel: %d\n", LanguageLevel); - puts("%%DocumentData: Clean7Bit"); - puts("%%DocumentSuppliedResources: procset hpgltops 1.1 0"); - puts("%%DocumentNeededResources: font Courier Helvetica"); - puts("%%Creator: hpgltops/" CUPS_SVERSION); - strftime(line, sizeof(line), "%c", curtm); - printf("%%%%CreationDate: %s\n", line); - WriteTextComment("Title", title); - WriteTextComment("For", user); - printf("%%cupsRotation: %d\n", (Orientation & 3) * 90); - puts("%%EndComments"); - puts("%%BeginProlog"); - printf("/DefaultPenWidth %.2f def\n", PenWidth * 72.0 / 25.4); - if (!shading) /* Black only */ - puts("/setrgbcolor { pop pop pop } bind def"); - else if (!ColorDevice) /* Greyscale */ - puts("/setrgbcolor { 0.08 mul exch 0.61 mul add exch 0.31 mul add setgray } bind def\n"); - - if ((datadir = getenv("CUPS_DATADIR")) == NULL) - datadir = CUPS_DATADIR; - - snprintf(filename, sizeof(filename), "%s/data/HPGLprolog", datadir); - - if ((prolog = fopen(filename, "r")) == NULL) - { - fprintf(stderr, - "DEBUG: Unable to open HPGL prolog \"%s\" for reading - %s\n", - filename, strerror(errno)); - exit(1); - } - - while (fgets(line, sizeof(line), prolog) != NULL) - fputs(line, stdout); - - fclose(prolog); - - puts("%%EndProlog"); - - IN_initialize(0, NULL); -} - - -/* - * 'OutputTrailer()' - Output the PostScript trailer... - */ - -void -OutputTrailer(void) -{ - if (PageDirty) - PG_advance_page(0, NULL); - - puts("%%Trailer"); - printf("%%%%Pages: %d\n", PageCount); - puts("%%EOF"); -} - - -/* - * 'Outputf()' - Write a formatted string to the output file, creating the - * page header as needed... - */ - -int /* O - Number of bytes written */ -Outputf(const char *format, /* I - Printf-style string */ - ...) /* I - Additional args as needed */ -{ - va_list ap; /* Argument pointer */ - int bytes; /* Number of bytes written */ - float iw1[2], iw2[2]; /* Clipping window */ - int i; /* Looping var */ - ppd_size_t *size; /* Page size */ - ppd_option_t *option; /* Page size option */ - ppd_choice_t *choice; /* Page size choice */ - float width, length; /* Page dimensions */ - int landscape; /* Rotate for landscape orientation? */ - - - /* - * Write the page header as needed... - */ - - if (!PageDirty) - { - PageDirty = 1; - PageCount ++; - - printf("%%%%Page: %d %d\n", PageCount, PageCount); - - landscape = 0; - - if (!FitPlot && PlotSizeSet) - { - /* - * Set the page size for this page... - */ - - if (PageRotation == 0 || PageRotation == 180) - { - width = PlotSize[0]; - length = PlotSize[1]; - } - else - { - width = PlotSize[1]; - length = PlotSize[0]; - } - - fprintf(stderr, "DEBUG: hpgltops setting page size (%.0f x %.0f)\n", - width, length); - - if (PPD != NULL) - { - fputs("DEBUG: hpgltops has a PPD file!\n", stderr); - - /* - * Lookup the closest PageSize and set it... - */ - - for (i = PPD->num_sizes, size = PPD->sizes; i > 0; i --, size ++) - if ((fabs(length - size->length) < 36.0 && size->width >= width) || - (fabs(length - size->width) < 36.0 && size->length >= width)) - break; - - if (i == 0 && PPD->variable_sizes) - { - for (i = PPD->num_sizes, size = PPD->sizes; i > 0; i --, size ++) - if (strcasecmp(size->name, "custom") == 0) - break; - } - - if (i > 0) - { - /* - * Found a matching size... - */ - - option = ppdFindOption(PPD, "PageSize"); - choice = ppdFindChoice(option, size->name); - - puts("%%BeginPageSetup"); - printf("%%%%BeginFeature: PageSize %s\n", size->name); - - if (strcasecmp(size->name, "custom") == 0) - { - PageLeft = PPD->custom_margins[0]; - PageRight = width - PPD->custom_margins[2]; - PageWidth = width; - PageBottom = PPD->custom_margins[1]; - PageTop = length - PPD->custom_margins[3]; - PageLength = length; - - printf("%.0f %.0f 0 0 0\n", width, length); - - if (choice->code == NULL) - { - /* - * This can happen with certain buggy PPD files that don't include - * a CustomPageSize command sequence... We just use a generic - * Level 2 command sequence... - */ - - puts("pop pop pop"); - puts("<>setpagedevice\n"); - } - else - { - /* - * Use the vendor-supplied command... - */ - - printf("%s\n", choice->code); - } - } - else - { - if (choice->code) - printf("%s\n", choice->code); - - if (fabs(length - size->width) < 36.0) - { - /* - * Do landscape orientation... - */ - - PageLeft = size->bottom; - PageRight = size->top; - PageWidth = size->length; - PageBottom = size->left; - PageTop = size->right; - PageLength = size->width; - - landscape = 1; - } - else - { - /* - * Do portrait orientation... - */ - - PageLeft = size->left; - PageRight = size->right; - PageWidth = size->width; - PageBottom = size->bottom; - PageTop = size->top; - PageLength = size->length; - } - } - - puts("%%EndFeature"); - puts("%%EndPageSetup"); - } - } - else - { - fputs("DEBUG: hpgltops does not have a PPD file!\n", stderr); - - puts("%%BeginPageSetup"); - printf("%%%%BeginFeature: PageSize w%.0fh%.0f\n", width, length); - printf("<>setpagedevice\n", - width, length); - puts("%%EndFeature"); - puts("%%EndPageSetup"); - - PageLeft = 0.0; - PageRight = width; - PageWidth = width; - PageBottom = 0.0; - PageTop = length; - PageLength = length; - } - } - - define_font(0); - define_font(1); - - printf("%.1f setmiterlimit\n", MiterLimit); - printf("%d setlinecap\n", LineCap); - printf("%d setlinejoin\n", LineJoin); - - printf("%.3f %.3f %.3f %.2f SP\n", Pens[1].rgb[0], Pens[1].rgb[1], - Pens[1].rgb[2], Pens[1].width * PenScaling); - - puts("gsave"); - - if (Duplex && (PageCount & 1) == 0) - switch ((PageRotation / 90 + landscape) & 3) - { - case 0 : - printf("%.1f %.1f translate\n", PageWidth - PageRight, PageBottom); - break; - case 1 : - printf("%.0f 0 translate 90 rotate\n", PageLength); - printf("%.1f %.1f translate\n", PageLength - PageTop, - PageWidth - PageRight); - break; - case 2 : - printf("%.0f %.0f translate 180 rotate\n", PageWidth, PageLength); - printf("%.1f %.1f translate\n", PageLeft, PageLength - PageTop); - break; - case 3 : - printf("0 %.0f translate -90 rotate\n", PageWidth); - printf("%.1f %.1f translate\n", PageBottom, PageLeft); - break; - } - else - switch ((PageRotation / 90 + landscape) & 3) - { - case 0 : - printf("%.1f %.1f translate\n", PageLeft, PageBottom); - break; - case 1 : - printf("%.0f 0 translate 90 rotate\n", PageLength); - printf("%.1f %.1f translate\n", PageBottom, PageWidth - PageRight); - break; - case 2 : - printf("%.0f %.0f translate 180 rotate\n", PageWidth, PageLength); - printf("%.1f %.1f translate\n", PageWidth - PageRight, - PageLength - PageTop); - break; - case 3 : - printf("0 %.0f translate -90 rotate\n", PageWidth); - printf("%.1f %.1f translate\n", PageLength - PageTop, PageLeft); - break; - } - - if (IW1[0] != IW2[0] && IW1[1] != IW2[1]) - { - iw1[0] = IW1[0] * 72.0f / 1016.0f; - iw1[1] = IW1[1] * 72.0f / 1016.0f; - iw2[0] = IW2[0] * 72.0f / 1016.0f; - iw2[1] = IW2[1] * 72.0f / 1016.0f; - - printf("initclip MP %.3f %.3f MO %.3f %.3f LI %.3f %.3f LI %.3f %.3f LI CP clip\n", - iw1[0], iw1[1], iw1[0], iw2[1], iw2[0], iw2[1], iw2[0], iw1[1]); - } - } - - /* - * Write the string to the output file... - */ - - va_start(ap, format); - bytes = vprintf(format, ap); - va_end(ap); - - return (bytes); -} - - -/* - * End of "$Id: hpgl-prolog.c 6649 2007-07-11 21:46:42Z mike $". - */ diff --git a/filter/hpgl-vector.c b/filter/hpgl-vector.c deleted file mode 100644 index fdf8664a4..000000000 --- a/filter/hpgl-vector.c +++ /dev/null @@ -1,773 +0,0 @@ -/* - * "$Id: hpgl-vector.c 6649 2007-07-11 21:46:42Z mike $" - * - * HP-GL/2 vector routines for the Common UNIX Printing System (CUPS). - * - * Copyright 2007-2008 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: - * - * AA_arc_absolute() - Draw an arc. - * AR_arc_relative() - Draw an arc relative to the current pen - * AT_arc_absolute3() - Draw an arc using 3 points. - * CI_circle() - Draw a circle. - * PA_plot_absolute() - Plot a line using absolute coordinates. - * PD_pen_down() - Start drawing. - * PE_polygon_encoded() - Draw an encoded polyline. - * PR_plot_relative() - Plot a line using relative coordinates. - * PU_pen_up() - Stop drawing. - * RT_arc_relative3() - Draw an arc through 3 points relative to the - * decode_number() - Decode an encoded number. - * plot_points() - Plot the specified points. - */ - -/* - * Include necessary headers... - */ - -#include "hpgltops.h" - - -/* - * Local functions... - */ - -static double decode_number(unsigned char **, int, double); -static void plot_points(int, param_t *); - - -/* - * 'AA_arc_absolute()' - Draw an arc. - */ - -void -AA_arc_absolute(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - float x, y, /* Transformed coordinates */ - dx, dy; /* Distance from current pen */ - float start, end, /* Start and end angles */ - theta, /* Current angle */ - dt, /* Step between points */ - radius; /* Radius of arc */ - - - if (num_params < 3) - return; - - x = Transform[0][0] * params[0].value.number + - Transform[0][1] * params[1].value.number + - Transform[0][2]; - y = Transform[1][0] * params[0].value.number + - Transform[1][1] * params[1].value.number + - Transform[1][2]; - - dx = PenPosition[0] - x; - dy = PenPosition[1] - y; - - start = (float)(180.0 * atan2(dy, dx) / M_PI); - if (start < 0.0) - start += 360.0f; - - end = start + params[2].value.number; - radius = (float)hypot(dx, dy); - - if (PenDown) - { - if (num_params > 3 && params[3].value.number > 0.0) - dt = (float)fabs(params[3].value.number); - else - dt = 5.0; - - if (!PolygonMode) - Outputf("MP\n"); - - PenValid = 1; - - Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]); - - if (start < end) - for (theta = start + dt; theta < end; theta += dt) - { - PenPosition[0] = (float)(x + radius * cos(M_PI * theta / 180.0)); - PenPosition[1] = (float)(y + radius * sin(M_PI * theta / 180.0)); - - Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]); - } - else - for (theta = start - dt; theta > end; theta -= dt) - { - PenPosition[0] = (float)(x + radius * cos(M_PI * theta / 180.0)); - PenPosition[1] = (float)(y + radius * sin(M_PI * theta / 180.0)); - - Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]); - } - } - - PenPosition[0] = (float)(x + radius * cos(M_PI * end / 180.0)); - PenPosition[1] = (float)(y + radius * sin(M_PI * end / 180.0)); - - if (PenDown) - { - Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]); - - if (!PolygonMode) - Outputf("ST\n"); - } -} - - -/* - * 'AR_arc_relative()' - Draw an arc relative to the current pen - * position. - */ - -void -AR_arc_relative(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - float x, y, /* Transformed coordinates */ - dx, dy; /* Distance from current pen */ - float start, end, /* Start and end angles */ - theta, /* Current angle */ - dt, /* Step between points */ - radius; /* Radius of arc */ - - - if (num_params < 3) - return; - - x = Transform[0][0] * params[0].value.number + - Transform[0][1] * params[1].value.number + - PenPosition[0]; - y = Transform[1][0] * params[0].value.number + - Transform[1][1] * params[1].value.number + - PenPosition[1]; - - dx = PenPosition[0] - x; - dy = PenPosition[1] - y; - - start = (float)(180.0 * atan2(dy, dx) / M_PI); - if (start < 0.0) - start += 360.0f; - - end = start + params[2].value.number; - radius = (float)hypot(dx, dy); - - if (PenDown) - { - if (num_params > 3 && params[3].value.number > 0.0) - dt = (float)fabs(params[3].value.number); - else - dt = 5.0; - - if (!PolygonMode) - Outputf("MP\n"); - - PenValid = 1; - - Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]); - - if (start < end) - for (theta = start + dt; theta < end; theta += dt) - { - PenPosition[0] = (float)(x + radius * cos(M_PI * theta / 180.0)); - PenPosition[1] = (float)(y + radius * sin(M_PI * theta / 180.0)); - - Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]); - } - else - for (theta = start - dt; theta > end; theta -= dt) - { - PenPosition[0] = (float)(x + radius * cos(M_PI * theta / 180.0)); - PenPosition[1] = (float)(y + radius * sin(M_PI * theta / 180.0)); - - Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]); - } - } - - PenPosition[0] = (float)(x + radius * cos(M_PI * end / 180.0)); - PenPosition[1] = (float)(y + radius * sin(M_PI * end / 180.0)); - - if (PenDown) - { - Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]); - - if (!PolygonMode) - Outputf("ST\n"); - } -} - - -/* - * 'AT_arc_absolute3()' - Draw an arc using 3 points. - * - * Note: - * - * Currently this only draws two line segments through the - * specified points. - */ - -void -AT_arc_absolute3(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - if (num_params < 4) - return; - - if (PenDown) - { - if (!PolygonMode) - Outputf("MP\n"); - - PenValid = 1; - - Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]); - - PenPosition[0] = Transform[0][0] * params[0].value.number + - Transform[0][1] * params[1].value.number + - Transform[0][2]; - PenPosition[1] = Transform[1][0] * params[0].value.number + - Transform[1][1] * params[1].value.number + - Transform[1][2]; - - Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]); - } - - PenPosition[0] = Transform[0][0] * params[2].value.number + - Transform[0][1] * params[3].value.number + - Transform[0][2]; - PenPosition[1] = Transform[1][0] * params[2].value.number + - Transform[1][1] * params[3].value.number + - Transform[1][2]; - - if (PenDown) - { - Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]); - - if (!PolygonMode) - Outputf("ST\n"); - } -} - - -/* - * 'CI_circle()' - Draw a circle. - */ - -void -CI_circle(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - float x, y; /* Transformed coordinates */ - float theta, /* Current angle */ - dt, /* Step between points */ - radius; /* Radius of circle */ - - - if (num_params < 1) - return; - - if (!PenDown) - return; - - radius = params[0].value.number; - - if (num_params > 1) - dt = (float)fabs(params[1].value.number); - else - dt = 5.0; - - if (!PolygonMode) - Outputf("MP\n"); - - PenValid = 1; - - for (theta = 0.0; theta < 360.0; theta += dt) - { - x = (float)(PenPosition[0] + - radius * cos(M_PI * theta / 180.0) * Transform[0][0] + - radius * sin(M_PI * theta / 180.0) * Transform[0][1]); - y = (float)(PenPosition[1] + - radius * cos(M_PI * theta / 180.0) * Transform[1][0] + - radius * sin(M_PI * theta / 180.0) * Transform[1][1]); - - Outputf("%.3f %.3f %s\n", x, y, theta == 0.0 ? "MO" : "LI"); - } - - Outputf("CP\n"); - if (!PolygonMode) - Outputf("ST\n"); -} - - -/* - * 'PA_plot_absolute()' - Plot a line using absolute coordinates. - */ - -void -PA_plot_absolute(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - PenMotion = 0; - - if (num_params > 1) - plot_points(num_params, params); -} - - -/* - * 'PD_pen_down()' - Start drawing. - */ - -void -PD_pen_down(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - PenDown = 1; - - if (num_params > 1) - plot_points(num_params, params); -} - - -/* - * 'PE_polygon_encoded()' - Draw an encoded polyline. - */ - -void -PE_polyline_encoded(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - unsigned char *s; /* Pointer into string */ - int temp, /* Temporary value */ - base_bits, /* Data bits per byte */ - draw, /* Draw or move */ - abscoords; /* Use absolute coordinates */ - double tx, ty, /* Transformed coordinates */ - x, y, /* Raw coordinates */ - frac_bits; /* Multiplier for encoded number */ - - - base_bits = 6; - frac_bits = 1.0; - draw = PenDown; - abscoords = 0; - - if (num_params == 0) - return; - - if (!PolygonMode) - { - Outputf("MP\n"); - PenValid = 0; - } - - if (!PenValid) - { - Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]); - PenValid = 1; - } - - for (s = (unsigned char *)params[0].value.string; *s != '\0';) - switch (*s) - { - case '7' : - s ++; - base_bits = 5; - -#ifdef DEBUG - fputs("DEBUG: 7-bit\n", stderr); -#endif /* DEBUG */ - - Outputf("%% PE: 7-bit\n"); - break; - case ':' : /* Select pen */ - s ++; - temp = (int)decode_number(&s, base_bits, 1.0) - 1; - if (temp < 0 || temp >= PenCount) - { - fprintf(stderr, "DEBUG: Bad pen number %d in PE\n", temp + 1); - return; - } - - PenNumber = temp; - -#ifdef DEBUG - fprintf(stderr, "DEBUG: set pen #%d\n", PenNumber + 1); -#endif /* DEBUG */ - - Outputf("%% PE: set pen #%d\n", PenNumber + 1); - - if (PageDirty) - printf("%.3f %.3f %.3f %.2f SP\n", Pens[PenNumber].rgb[0], - Pens[PenNumber].rgb[1], Pens[PenNumber].rgb[2], - Pens[PenNumber].width * PenScaling); - break; - case '<' : /* Next coords are a move-to */ - draw = 0; - s ++; - -#ifdef DEBUG - fputs("DEBUG: moveto\n", stderr); -#endif /* DEBUG */ - - Outputf("%% PE: moveto\n"); - break; - case '>' : /* Set fractional bits */ - s ++; - temp = (int)decode_number(&s, base_bits, 1.0); - frac_bits = 1.0 / (1 << temp); - -#ifdef DEBUG - fprintf(stderr, "DEBUG: set fractional bits %d\n", temp); -#endif /* DEBUG */ - - Outputf("%% PE: set fractional bits %d\n", temp); - break; - case '=' : /* Next coords are absolute */ - s ++; - abscoords = 1; - -#ifdef DEBUG - fputs("DEBUG: absolute\n", stderr); -#endif /* DEBUG */ - - Outputf("%% PE: absolute\n"); - break; - default : - if (*s >= 63) - { - /* - * Coordinate... - */ - - x = decode_number(&s, base_bits, frac_bits); - y = decode_number(&s, base_bits, frac_bits); - -#ifdef DEBUG - fprintf(stderr, "DEBUG: coords %.3f %.3f\n", x, y); -#endif /* DEBUG */ - - Outputf("%% PE: coords %.3f %.3f\n", x, y); - - if (abscoords) - { - tx = Transform[0][0] * x + Transform[0][1] * y + - Transform[0][2]; - ty = Transform[1][0] * x + Transform[1][1] * y + - Transform[1][2]; - } - else if (x == 0.0 && y == 0.0) - { - draw = 1; - continue; - } - else - { - tx = Transform[0][0] * x + Transform[0][1] * y + - PenPosition[0]; - ty = Transform[1][0] * x + Transform[1][1] * y + - PenPosition[1]; - } - - if (draw) - { - if (fabs(PenPosition[0] - tx) > 0.001 || - fabs(PenPosition[1] - ty) > 0.001) - Outputf("%.3f %.3f LI\n", tx, ty); - } - else - Outputf("%.3f %.3f MO\n", tx, ty); - - PenPosition[0] = (float)tx; - PenPosition[1] = (float)ty; - - draw = 1; - abscoords = 0; - } - else - { - /* - * Junk - ignore... - */ - - if (*s != '\n' && *s != '\r') - fprintf(stderr, "WARNING: ignoring illegal PE char \'%c\'...\n", *s); - s ++; - } - break; - } - - if (!PolygonMode) - Outputf("ST\n"); -} - - -/* - * 'PR_plot_relative()' - Plot a line using relative coordinates. - */ - -void -PR_plot_relative(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - PenMotion = 1; - - if (num_params > 1) - plot_points(num_params, params); -} - - -/* - * 'PU_pen_up()' - Stop drawing. - */ - -void -PU_pen_up(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - PenDown = 0; - - if (num_params > 1) - plot_points(num_params, params); -} - - -/* - * 'RT_arc_relative3()' - Draw an arc through 3 points relative to the - * current pen position. - * - * Note: - * - * This currently only draws two line segments through the specified - * points. - */ - -void -RT_arc_relative3(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - if (num_params < 4) - return; - - if (PenDown) - { - if (!PolygonMode) - Outputf("MP\n"); - - PenValid = 1; - - Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]); - - PenPosition[0] = Transform[0][0] * params[0].value.number + - Transform[0][1] * params[1].value.number + - PenPosition[0]; - PenPosition[1] = Transform[1][0] * params[0].value.number + - Transform[1][1] * params[1].value.number + - PenPosition[1]; - - Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]); - } - - PenPosition[0] = Transform[0][0] * params[2].value.number + - Transform[0][1] * params[3].value.number + - PenPosition[0]; - PenPosition[1] = Transform[1][0] * params[2].value.number + - Transform[1][1] * params[3].value.number + - PenPosition[1]; - - if (PenDown) - { - Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]); - - if (!PolygonMode) - Outputf("ST\n"); - } -} - - -/* - * 'decode_number()' - Decode an encoded number. - */ - -static double /* O - Value */ -decode_number(unsigned char **s, /* IO - String to decode */ - int base_bits, /* I - Number of data bits per byte */ - double frac_bits) /* I - Multiplier for fractional data */ -{ - double temp, /* Current value */ - shift; /* Multiplier */ - int sign; /* Sign of result */ - - - sign = 0; - - if (base_bits == 5) - { - for (temp = 0.0, shift = frac_bits * 0.5; **s != '\0'; (*s) ++) - if (**s >= 95 && **s < 127) - { - if (sign == 0) - { - if ((**s - 95) & 1) - sign = -1; - else - sign = 1; - - temp += ((**s - 95) & ~1) * shift; - } - else - temp += (**s - 95) * shift; - break; - } - else if (**s < 63) - { - if (**s != '\r' && **s != '\n') - fprintf(stderr, "DEBUG: Bad PE character 0x%02X!\n", **s); - - continue; - } - else - { - if (sign == 0) - { - if ((**s - 63) & 1) - sign = -1; - else - sign = 1; - - temp += ((**s - 63) & ~1) * shift; - } - else - temp += (**s - 63) * shift; - - shift *= 32.0; - } - } - else - { - for (temp = 0.0, shift = frac_bits * 0.5; **s != '\0'; (*s) ++) - if (**s >= 191 && **s < 255) - { - if (sign == 0) - { - if ((**s - 191) & 1) - sign = -1; - else - sign = 1; - - temp += ((**s - 191) & ~1) * shift; - } - else - temp += (**s - 191) * shift; - break; - } - else if (**s < 63) - { - if (**s != '\r' && **s != '\n') - fprintf(stderr, "DEBUG: Bad PE character 0x%02X!\n", **s); - - continue; - } - else - { - if (sign == 0) - { - if ((**s - 63) & 1) - sign = -1; - else - sign = 1; - - temp += ((**s - 63) & ~1) * shift; - } - else - temp += (**s - 63) * shift; - - shift *= 64.0; - } - } - - (*s) ++; - - return (temp * sign); -} - - -/* - * 'plot_points()' - Plot the specified points. - */ - -static void -plot_points(int num_params, /* I - Number of parameters */ - param_t *params) /* I - Parameters */ -{ - int i; /* Looping var */ - float x, y; /* Transformed coordinates */ - - - if (PenDown) - { - if (!PolygonMode) - { - Outputf("MP\n"); - Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]); - - PenValid = 1; - } - } - - for (i = 0; i < num_params; i += 2) - { - if (PenMotion == 0) - { - x = Transform[0][0] * params[i + 0].value.number + - Transform[0][1] * params[i + 1].value.number + - Transform[0][2]; - y = Transform[1][0] * params[i + 0].value.number + - Transform[1][1] * params[i + 1].value.number + - Transform[1][2]; - } - else - { - x = Transform[0][0] * params[i + 0].value.number + - Transform[0][1] * params[i + 1].value.number + - PenPosition[0]; - y = Transform[1][0] * params[i + 0].value.number + - Transform[1][1] * params[i + 1].value.number + - PenPosition[1]; - } - - if (PenDown) - { - if (PolygonMode && i == 0) - Outputf("%.3f %.3f MO\n", x, y); - else if (fabs(PenPosition[0] - x) > 0.001 || - fabs(PenPosition[1] - y) > 0.001) - Outputf("%.3f %.3f LI\n", x, y); - } - - PenPosition[0] = x; - PenPosition[1] = y; - } - - if (PenDown) - { - if (!PolygonMode) - Outputf("ST\n"); - } -} - - -/* - * End of "$Id: hpgl-vector.c 6649 2007-07-11 21:46:42Z mike $". - */ diff --git a/filter/hpgltops.h b/filter/hpgltops.h deleted file mode 100644 index 4fe45d282..000000000 --- a/filter/hpgltops.h +++ /dev/null @@ -1,240 +0,0 @@ -/* - * "$Id: hpgltops.h 6649 2007-07-11 21:46:42Z mike $" - * - * HP-GL/2 to PostScript filter for the Common UNIX Printing System (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/". - * - * This file is subject to the Apple OS-Developed Software exception. - */ - -/* - * Include necessary headers... - */ - -#include "common.h" -#include - -#ifndef M_PI -# define M_PI 3.14159265358979323846 -#endif /* M_PI */ - - -/* - * Maximum number of pens we emulate... - */ - -#define MAX_PENS 1024 - - -/* - * Parameter value structure... - */ - -typedef struct -{ - int type; - union - { - float number; - char *string; - } value; -} param_t; - -#define PARAM_ABSOLUTE 0 -#define PARAM_RELATIVE 1 -#define PARAM_STRING 2 - - -/* - * Font information... - */ - -typedef struct -{ - int symbol_set, /* Symbol set */ - spacing, /* Spacing (0 = fixed, 1 = proportional) */ - posture, /* Posture number */ - weight, /* Weight number */ - typeface; /* Typeface number */ - float pitch, /* Characters per inch */ - height, /* Height/size of font */ - xpitch; /* X pitch scaling value */ - float x, y; /* X and Y direction/scaling */ -} font_t; - - -/* - * Pen information... - */ - -typedef struct -{ - float rgb[3]; /* Pen color */ - float width; /* Pen width */ -} pen_t; - - -/* - * Globals... - */ - -#ifdef _HPGL_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 /* _HPGL_MAIN_C_ */ - -VAR ppd_file_t *PPD VALUE(NULL); /* PPD file */ - -VAR float P1[2], /* Lower-lefthand physical limit */ - P2[2], /* Upper-righthand physical limit */ - IW1[2], /* Window lower-lefthand limit */ - IW2[2]; /* Window upper-righthand limit */ -VAR int Rotation VALUE(0); /* Page rotation */ -VAR int ScalingType VALUE(-1); /* Type of scaling (-1 for none) */ -VAR float Scaling1[2], /* Lower-lefthand user limit */ - Scaling2[2]; /* Upper-righthand user limit */ -VAR float Transform[2][3]; /* Transform matrix */ -VAR int PageRotation VALUE(0); /* Page/plot rotation */ - -VAR char StringTerminator VALUE('\003'); /* Terminator for labels */ -VAR font_t StandardFont, /* Standard font */ - AlternateFont; /* Alternate font */ -VAR float PenPosition[2] VALUE2(0.0f, 0.0f), - /* Current pen position */ - PenScaling VALUE(1.0f), /* Pen width scaling factor */ - PenWidth VALUE(1.0f); /* Default pen width */ -VAR pen_t Pens[MAX_PENS]; /* State of each pen */ -VAR int PenMotion VALUE(0), /* 0 = absolute, 1 = relative */ - PenValid VALUE(0), /* 1 = valid position, 0 = undefined */ - PenNumber VALUE(0), /* Current pen number */ - PenCount VALUE(8), /* Number of pens */ - PenDown VALUE(0), /* 0 = pen up, 1 = pen down */ - PolygonMode VALUE(0), /* Drawing polygons? */ - PageCount VALUE(0), /* Number of pages in plot */ - PageDirty VALUE(0), /* Current page written on? */ - WidthUnits VALUE(0); /* 0 = mm, 1 = proportionate */ -VAR float PlotSize[2] VALUE2(2592.0f, 3456.0f); - /* Plot size */ -VAR int PlotSizeSet VALUE(0); /* Plot size set? */ -VAR int CharFillMode VALUE(0), /* Where to draw labels */ - CharPen VALUE(0), /* Pen to use for labels */ - CharFont VALUE(0); /* Font to use for labels */ -VAR float CharHeight[2] VALUE2(11.5f,11.5f); - /* Size of font for labels */ -VAR int FitPlot VALUE(0); /* 1 = fit to page */ -VAR float ColorRange[3][2] /* Range of color values */ -#ifdef _HPGL_MAIN_C_ - = { - { 0.0, 255.0 }, - { 0.0, 255.0 }, - { 0.0, 255.0 } - } -#endif /* _HPGL_MAIN_C_ */ -; - -VAR int LineCap VALUE(0); /* Line capping */ -VAR int LineJoin VALUE(0); /* Line joining */ -VAR float MiterLimit VALUE(3.0f); /* Miter limit at joints */ - - -/* - * Prototypes... - */ - -/* hpgl-input.c */ -extern int ParseCommand(FILE *fp, char *name, param_t **params); -extern void FreeParameters(int num_params, param_t *params); - -/* hpgl-config.c */ -extern void update_transform(void); -extern void BP_begin_plot(int num_params, param_t *params); -extern void DF_default_values(int num_params, param_t *params); -extern void IN_initialize(int num_params, param_t *params); -extern void IP_input_absolute(int num_params, param_t *params); -extern void IR_input_relative(int num_params, param_t *params); -extern void IW_input_window(int num_params, param_t *params); -extern void PG_advance_page(int num_params, param_t *params); -extern void PS_plot_size(int num_params, param_t *params); -extern void RO_rotate(int num_params, param_t *params); -extern void RP_replot(int num_params, param_t *params); -extern void SC_scale(int num_params, param_t *params); - -/* hpgl-vector.c */ -extern void AA_arc_absolute(int num_params, param_t *params); -extern void AR_arc_relative(int num_params, param_t *params); -extern void AT_arc_absolute3(int num_params, param_t *params); -extern void CI_circle(int num_params, param_t *params); -extern void PA_plot_absolute(int num_params, param_t *params); -extern void PD_pen_down(int num_params, param_t *params); -extern void PE_polyline_encoded(int num_params, param_t *params); -extern void PR_plot_relative(int num_params, param_t *params); -extern void PU_pen_up(int num_params, param_t *params); -extern void RT_arc_relative3(int num_params, param_t *params); - -/* hpgl-polygon.c */ -extern void EA_edge_rect_absolute(int num_params, param_t *params); -extern void EP_edge_polygon(int num_params, param_t *params); -extern void ER_edge_rect_relative(int num_params, param_t *params); -extern void EW_edge_wedge(int num_params, param_t *params); -extern void FP_fill_polygon(int num_params, param_t *params); -extern void PM_polygon_mode(int num_params, param_t *params); -extern void RA_fill_rect_absolute(int num_params, param_t *params); -extern void RR_fill_rect_relative(int num_params, param_t *params); -extern void WG_fill_wedge(int num_params, param_t *params); - -/* hpgl-char.c */ -extern void define_font(int f); -extern void AD_define_alternate(int num_params, param_t *params); -extern void CF_character_fill(int num_params, param_t *params); -extern void CP_character_plot(int num_params, param_t *params); -extern void DI_absolute_direction(int num_params, param_t *params); -extern void DR_relative_direction(int num_params, param_t *params); -extern void DT_define_label_term(int num_params, param_t *params); -extern void DV_define_variable_path(int num_params, param_t *params); -extern void ES_extra_space(int num_params, param_t *params); -extern void LB_label(int num_params, param_t *params); -extern void LO_label_origin(int num_params, param_t *params); -extern void SA_select_alternate(int num_params, param_t *params); -extern void SD_define_standard(int num_params, param_t *params); -extern void SI_absolute_size(int num_params, param_t *params); -extern void SL_character_slant(int num_params, param_t *params); -extern void SR_relative_size(int num_params, param_t *params); -extern void SS_select_standard(int num_params, param_t *params); -extern void TD_transparent_data(int num_params, param_t *params); - -/* hpgl-attr.c */ -extern void AC_anchor_corner(int num_params, param_t *params); -extern void CR_color_range(int num_params, param_t *params); -extern void FT_fill_type(int num_params, param_t *params); -extern void LA_line_attributes(int num_params, param_t *params); -extern void LT_line_type(int num_params, param_t *params); -extern void NP_number_pens(int num_params, param_t *params); -extern void PC_pen_color(int num_params, param_t *params); -extern void PW_pen_width(int num_params, param_t *params); -extern void RF_raster_fill(int num_params, param_t *params); -extern void SM_symbol_mode(int num_params, param_t *params); -extern void SP_select_pen(int num_params, param_t *params); -extern void UL_user_line_type(int num_params, param_t *params); -extern void WU_width_units(int num_params, param_t *params); - -/* hpgl-prolog.c */ -extern void OutputProlog(char *title, char *user, int shading); -extern void OutputTrailer(void); -extern int Outputf(const char *format, ...); - -/* - * End of "$Id: hpgltops.h 6649 2007-07-11 21:46:42Z mike $". - */ diff --git a/man/Makefile b/man/Makefile index b12c39a65..9e489b3a2 100644 --- a/man/Makefile +++ b/man/Makefile @@ -3,7 +3,7 @@ # # Man page makefile for the Common UNIX Printing System (CUPS). # -# Copyright 2007-2008 by Apple Inc. +# Copyright 2007-2010 by Apple Inc. # Copyright 1993-2006 by Easy Software Products. # # These coded instructions, statements, and computer programs are the @@ -24,6 +24,7 @@ MAN1 = cancel.$(MAN1EXT) \ cups-config.$(MAN1EXT) \ cupstestdsc.$(MAN1EXT) \ cupstestppd.$(MAN1EXT) \ + ipptest.$(MAN1EXT) \ lp.$(MAN1EXT) \ lpoptions.$(MAN1EXT) \ lppasswd.$(MAN1EXT) \ @@ -40,6 +41,7 @@ MAN5 = classes.conf.$(MAN5EXT) \ client.conf.$(MAN5EXT) \ cups-snmp.conf.$(MAN5EXT) \ cupsd.conf.$(MAN5EXT) \ + ipp.test.$(MAN5EXT) \ mailto.conf.$(MAN5EXT) \ mime.convs.$(MAN5EXT) \ mime.types.$(MAN5EXT) \ diff --git a/man/cupsd.conf.man.in b/man/cupsd.conf.man.in index fc36f5db8..ad4d082b3 100644 --- a/man/cupsd.conf.man.in +++ b/man/cupsd.conf.man.in @@ -3,7 +3,7 @@ .\" .\" cupsd.conf man page for the Common UNIX Printing System (CUPS). .\" -.\" Copyright 2007-2009 by Apple Inc. +.\" Copyright 2007-2010 by Apple Inc. .\" Copyright 1997-2006 by Easy Software Products. .\" .\" These coded instructions, statements, and computer programs are the @@ -12,7 +12,7 @@ .\" which 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" "14 July 2009" "Apple Inc." +.TH cupsd.conf 5 "CUPS" "28 January 2010" "Apple Inc." .SH NAME cupsd.conf \- server configuration file for cups .SH DESCRIPTION @@ -252,10 +252,6 @@ DefaultAuthType Negotiate .br Specifies the default type of authentication to use. .TP 5 -DefaultCharset charset -.br -Specifies the default character set to use for text. -.TP 5 DefaultEncryption Never .TP 5 DefaultEncryption IfRequested diff --git a/man/ipp.test.man b/man/ipp.test.man new file mode 100644 index 000000000..248719964 --- /dev/null +++ b/man/ipp.test.man @@ -0,0 +1,450 @@ +.\" +.\" "$Id$" +.\" +.\" ipp.test 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 ipp.test 5 "CUPS" "23 February 2010" "Apple Inc." +.SH NAME +ipp.test \- ipptest test file format + +.SH DESCRIPTION +The \fIipptest(1)\fR program accepts free-form plain text files that describe +one or more IPP operation tests. Comments start with the "#" character and +continue to the end of the line. Each test 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 + 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 + 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 \fIipptest\fR command-line. +.TP 5 +INCLUDE "filename" +.TP 5 +INCLUDE +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 \fIipptest\fR +include directory. +.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 +\fIipptest\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 \fIipptest\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 +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 \fIipptest\fR program. +.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 +IF-DEFINED variable-name +Makes the EXPECT conditions apply only if the specified variable is defined. +.TP 5 +IF-UNDEFINED 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-UNDEFINED variable-name +Makes the STATUS apply only if the specified variable is not defined. + +.SH OPERATION CODES +Operation codes correspond to the 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-Subscription + 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 + 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 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 \fIipptest\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 \fIipptest\fR with the "-f" option. +.TP 5 +$hostname +Inserts the hostname from the URI provided to \fIipptest\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 \fIipptest\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 \fIipptest\fR. +.TP 5 +$resource +Inserts the resource path from the URI provided to \fIipptest\fR. +.TP 5 +$uri +Inserts the URI provided to \fIipptest\fR. +.TP 5 +$user +Inserts the current user's login name. +.TP 5 +$username +Inserts the username from the URI provided to \fIipptest\fR, if any. + +.SH SEE ALSO +\fIipptest(1)\fR, +.br +http://localhost:631/help + +.SH COPYRIGHT +Copyright 2007-2010 by Apple Inc. +.\" +.\" End of "$Id$". +.\" diff --git a/man/ipptest.man b/man/ipptest.man new file mode 100644 index 000000000..2d1467652 --- /dev/null +++ b/man/ipptest.man @@ -0,0 +1,89 @@ +.\" +.\" "$Id$" +.\" +.\" ipptest 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 ipptest 1 "CUPS" "15 February 2010" "Apple Inc." +.SH NAME +ipptest - perform internet printing protocol tests +.SH SYNOPSIS +.B ipptest +[ -E ] [ -V +.I version +] [ -X ] [ -c ] [ -d +.I name=value +] [ -f +.I filename +] [ -i +.I seconds +] [ -l ] [ -v ] +.I URI +.I filename.test +[ +.I ... filenameN.test +] +.SH DESCRIPTION +\fIipptest\fR sends IPP requests to the specified URI and tests the results. +Each test file contains one or more test requests, including the expected +response status, attributes, and values. Output is either a plain text or XML +report on the standard output, with a non-zero exit status indicating that one +or more tests have failed. The test file format is described in +\fIipp.test(5)\fR. +.SH OPTIONS +The following options are recognized by \fIipptest\fR: +.TP 5 +-E +Forces encryption when connecting to the server. +.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) option. +.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 +-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) test should be repeated at the specified interval. +This option is incompatible with the \fI-X\fR (XML output) option. +.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 +-v +Specifies that all request and response attributes should be output. This is the +default for XML output. +.SH COMPATIBILITY +The \fIipptest\fR program is unique to CUPS. +.SH SEE ALSO +\fIipp.test(5)\fR, +.br +http://localhost:631/help +.SH COPYRIGHT +Copyright 2007-2010 by Apple Inc. +.\" +.\" End of "$Id$". +.\" diff --git a/packaging/cups.list.in b/packaging/cups.list.in index b6eb952b0..adad41785 100644 --- a/packaging/cups.list.in +++ b/packaging/cups.list.in @@ -3,7 +3,7 @@ # # ESP Package Manager (EPM) file list for CUPS. # -# Copyright 2007-2009 by Apple Inc. +# 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 @@ -15,7 +15,7 @@ # Product information %product CUPS -%copyright 2007-2009 by Apple Inc. +%copyright 2007-2010 by Apple Inc. %vendor Apple Inc. #%license LICENSE.txt %readme LICENSE.txt @@ -273,7 +273,6 @@ l 0700 root sys $SERVERBIN/backend/mdns dnssd %endif %system !darwin f 0555 root sys $SERVERBIN/backend/parallel backend/parallel -f 0555 root sys $SERVERBIN/backend/scsi backend/scsi %system all f 0555 root sys $SERVERBIN/backend/serial backend/serial f 0555 root sys $SERVERBIN/backend/snmp backend/snmp @@ -296,7 +295,6 @@ 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 -f 0555 root sys $SERVERBIN/filter/hpgltops filter/hpgltops %if IMGFILTERS f 0555 root sys $SERVERBIN/filter/imagetops filter/imagetops f 0555 root sys $SERVERBIN/filter/imagetoraster filter/imagetoraster @@ -351,6 +349,7 @@ 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/ipptest test/ipptest f 0555 root sys $BINDIR/lp systemv/lp f 0555 root sys $BINDIR/lpoptions systemv/lpoptions f 0555 root sys $BINDIR/lppasswd systemv/lppasswd @@ -465,26 +464,27 @@ 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/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/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/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 +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 - @@ -503,7 +503,6 @@ 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/HPGLprolog data/HPGLprolog f 0444 root sys $DATADIR/data/psglyphs data/psglyphs f 0444 root sys $DATADIR/data/testprint data/testprint @@ -516,6 +515,10 @@ 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/ipptest - +f 0444 root sys $DATADIR/ipptest test/ipp-*.test +f 0444 root sys $DATADIR/ipptest 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 @@ -530,8 +533,8 @@ 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/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 @@ -548,8 +551,11 @@ f 0444 root sys $DATADIR/templates/eu templates/eu/*.tmpl #d 0755 root sys $DATADIR/templates/he #f 0444 root sys $DATADIR/templates/he templates/he/*.tmpl -#d 0755 root sys $DATADIR/templates/it -#f 0444 root sys $DATADIR/templates/it templates/it/*.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 @@ -644,8 +650,8 @@ 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/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 @@ -663,8 +669,11 @@ f 0444 root sys $DOCDIR/eu doc/eu/*.html #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/it -#f 0444 root sys $DOCDIR/it doc/it/*.html +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 @@ -692,6 +701,7 @@ 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/ipptest.$MAN1EXT man/ipptest.$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 @@ -702,6 +712,7 @@ 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/ipp.test.$MAN5EXT man/ipp.test.$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 diff --git a/packaging/cups.spec.in b/packaging/cups.spec.in index 267cac94a..26d0ac8a1 100644 --- a/packaging/cups.spec.in +++ b/packaging/cups.spec.in @@ -5,7 +5,7 @@ # # Original version by Jason McMullan . # -# Copyright 2007-2009 by Apple Inc. +# 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 @@ -185,6 +185,7 @@ rm -rf $RPM_BUILD_ROOT /usr/bin/cancel /usr/bin/cupstestdsc /usr/bin/cupstestppd +/usr/bin/ipptest /usr/bin/lp* %dir /usr/lib/cups %dir /usr/lib/cups/backend @@ -225,6 +226,8 @@ rm -rf $RPM_BUILD_ROOT /usr/share/cups/drv/* %dir /usr/share/cups/fonts /usr/share/cups/fonts/* +%dir /usr/share/cups/ipptest +/usr/share/cups/ipptest/* %dir /usr/share/cups/mime /usr/share/cups/mime/* %dir /usr/share/cups/model @@ -240,6 +243,8 @@ rm -rf $RPM_BUILD_ROOT /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/ja /usr/share/doc/cups/ja/* %dir /usr/share/doc/cups/pl @@ -271,6 +276,7 @@ rm -rf $RPM_BUILD_ROOT /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/ipptest.1.gz /usr/share/man/man1/lp.1.gz /usr/share/man/man1/lpoptions.1.gz /usr/share/man/man1/lppasswd.1.gz @@ -280,6 +286,7 @@ rm -rf $RPM_BUILD_ROOT /usr/share/man/man1/lpstat.1.gz %dir /usr/share/man/man5 /usr/share/man/man5/*.conf.5.gz +/usr/share/man/man5/ipp.test.5.gz /usr/share/man/man5/mime.*.5.gz %dir /usr/share/man/man7 /usr/share/man/man7/drv* diff --git a/ppdc/Makefile b/ppdc/Makefile index 524426541..f58b6f882 100644 --- a/ppdc/Makefile +++ b/ppdc/Makefile @@ -3,7 +3,7 @@ # # Makefile for the CUPS PPD Compiler. # -# Copyright 2007-2009 by Apple Inc. +# Copyright 2007-2010 by Apple Inc. # Copyright 2002-2006 by Easy Software Products. # # These coded instructions, statements, and computer programs are the @@ -143,7 +143,7 @@ install-exec: done if test "x$(SYMROOT)" != "x"; then \ $(INSTALL_DIR) $(SYMROOT); \ - for file in $(EXECTARGETS) $(LIBTARGETS); do \ + for file in $(EXECTARGETS); do \ cp $$file $(SYMROOT); \ done \ fi @@ -237,11 +237,11 @@ framedhelp: # genstrings - generate GNU gettext strings. # -genstrings: genstrings.o libcupsppdc.a ../cups/libcups.a \ +genstrings: genstrings.o libcupsppdc.a ../cups/$(LIBCUPSSTATIC) \ sample.drv ../data/media.defs echo Linking $@... $(CXX) $(ARCHFLAGS) $(LDFLAGS) -o genstrings genstrings.o \ - libcupsppdc.a ../cups/libcups.a $(LIBGSSAPI) $(SSLLIBS) \ + libcupsppdc.a ../cups/$(LIBCUPSSTATIC) $(LIBGSSAPI) $(SSLLIBS) \ $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) echo Generating localization strings... ./genstrings >sample.c @@ -256,10 +256,10 @@ ppdc: ppdc.o $(LIBCUPSPPDC) ../cups/$(LIBCUPS) $(CXX) $(LDFLAGS) -o $@ ppdc.o -L. -lcupsppdc $(LIBS) -ppdc-static: ppdc.o libcupsppdc.a ../cups/libcups.a foo.drv foo-fr.po +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/libcups.a $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) \ + ../cups/$(LIBCUPSSTATIC) $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) \ $(COMMONLIBS) $(LIBZ) echo Testing PPD compiler... ./ppdc-static -l en,fr -I ../data foo.drv @@ -284,10 +284,10 @@ ppdi: ppdi.o $(LIBCUPSPPDC) ../cups/$(LIBCUPS) $(CXX) $(LDFLAGS) -o $@ ppdi.o -L. -lcupsppdc $(LIBS) -ppdi-static: ppdc-static ppdi.o libcupsppdc.a ../cups/libcups.a +ppdi-static: ppdc-static ppdi.o libcupsppdc.a ../cups/$(LIBCUPSSTATIC) echo Linking $@... $(CXX) $(ARCHFLAGS) $(LDFLAGS) -o ppdi-static ppdi.o libcupsppdc.a \ - ../cups/libcups.a $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) \ + ../cups/$(LIBCUPSSTATIC) $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) \ $(COMMONLIBS) $(LIBZ) echo Testing PPD importer... $(RM) -r ppd ppd2 sample-import.drv @@ -324,10 +324,10 @@ ppdpo: ppdpo.o $(LIBCUPSPPDC) ../cups/$(LIBCUPS) # testcatalog, test ppdcCatalog class. # -testcatalog: testcatalog.o libcupsppdc.a ../cups/libcups.a +testcatalog: testcatalog.o libcupsppdc.a ../cups/$(LIBCUPSSTATIC) echo Linking $@... $(CXX) $(LDFLAGS) -o $@ testcatalog.o libcupsppdc.a \ - ../cups/libcups.a $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) \ + ../cups/$(LIBCUPSSTATIC) $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) \ $(COMMONLIBS) $(LIBZ) diff --git a/scheduler/Dependencies b/scheduler/Dependencies index 8a2a20cc7..1a8e7c325 100644 --- a/scheduler/Dependencies +++ b/scheduler/Dependencies @@ -248,5 +248,4 @@ cups-driverd.o: ../cups/ipp-private.h ../cups/ipp.h ../cups/globals.h cups-driverd.o: ../cups/string.h ../cups/cups.h ../cups/i18n.h cups-driverd.o: ../cups/transcode.h ../cups/language.h ../cups/array.h cups-driverd.o: ../cups/debug.h ../cups/dir.h ../cups/transcode.h -cups-driverd.o: ../cups/ppd-private.h ../ppdc/ppdc.h ../cups/string.h -cups-driverd.o: ../cups/file.h +cups-driverd.o: ../cups/ppd-private.h ../ppdc/ppdc.h ../cups/file.h diff --git a/scheduler/Makefile b/scheduler/Makefile index fe8ee6b1d..15292b9c6 100644 --- a/scheduler/Makefile +++ b/scheduler/Makefile @@ -1,9 +1,9 @@ # # "$Id: Makefile 7875 2008-08-27 22:53:31Z mike $" # -# Scheduler Makefile for the Common UNIX Printing System (CUPS). +# Scheduler Makefile for CUPS. # -# Copyright 2007-2009 by Apple Inc. +# 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 @@ -73,14 +73,17 @@ UNITTARGETS = \ testspeed \ testsub -TARGETS = \ - $(LIBTARGETS) \ +DAEMONS = \ cupsd \ cupsfilter \ cups-deviced \ cups-driverd \ cups-lpd \ - cups-polld \ + cups-polld + +TARGETS = \ + $(LIBTARGETS) \ + $(DAEMONS) # @@ -223,7 +226,7 @@ install-exec: $(INSTALL_BIN) cups-polld $(SERVERBIN)/daemon if test "x$(SYMROOT)" != "x"; then \ $(INSTALL_DIR) $(SYMROOT); \ - for file in $(TARGETS); do \ + for file in $(DAEMONS); do \ cp $$file $(SYMROOT); \ done \ fi @@ -374,11 +377,11 @@ cupsd: $(CUPSDOBJS) $(LIBCUPSMIME) ../cups/$(LIBCUPS) $(LIBPAPER) $(LIBMALLOC) $(CUPSDLIBS) $(DNSSDLIBS) $(LIBS) \ $(LIBGSSAPI) $(LIBWRAP) -cupsd-static: $(CUPSDOBJS) libcupsmime.a ../cups/libcups.a +cupsd-static: $(CUPSDOBJS) libcupsmime.a ../cups/$(LIBCUPSSTATIC) echo Linking $@... $(CC) $(LDFLAGS) -o cupsd-static $(CUPSDOBJS) libcupsmime.a \ $(LIBZ) $(SSLLIBS) $(LIBSLP) $(LIBLDAP) $(PAMLIBS) \ - ../cups/libcups.a $(COMMONLIBS) $(LIBZ) $(LIBPAPER) \ + ../cups/$(LIBCUPSSTATIC) $(COMMONLIBS) $(LIBZ) $(LIBPAPER) \ $(LIBMALLOC) $(CUPSDLIBS) $(DNSSDLIBS) $(LIBGSSAPI) \ $(LIBWRAP) @@ -503,9 +506,9 @@ testdirsvc: testdirsvc.o # Make the test program, "testlpd". # -testlpd: testlpd.o ../cups/libcups.a cups-lpd +testlpd: testlpd.o ../cups/$(LIBCUPSSTATIC) cups-lpd echo Linking $@... - $(CC) $(LDFLAGS) -o testlpd testlpd.o ../cups/libcups.a \ + $(CC) $(LDFLAGS) -o testlpd testlpd.o ../cups/$(LIBCUPSSTATIC) \ $(COMMONLIBS) $(LIBZ) $(SSLLIBS) $(DNSSDLIBS) $(LIBGSSAPI) @@ -513,10 +516,10 @@ testlpd: testlpd.o ../cups/libcups.a cups-lpd # testmime # -testmime: testmime.o libcupsmime.a ../cups/libcups.a +testmime: testmime.o libcupsmime.a ../cups/$(LIBCUPSSTATIC) echo Linking $@... $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testmime.o libcupsmime.a \ - ../cups/libcups.a $(COMMONLIBS) $(LIBZ) $(SSLLIBS) \ + ../cups/$(LIBCUPSSTATIC) $(COMMONLIBS) $(LIBZ) $(SSLLIBS) \ $(DNSSDLIBS) $(LIBGSSAPI) echo Running MIME tests... ./testmime @@ -526,9 +529,9 @@ testmime: testmime.o libcupsmime.a ../cups/libcups.a # Make the test program, "testspeed". # -testspeed: testspeed.o ../cups/libcups.a +testspeed: testspeed.o ../cups/$(LIBCUPSSTATIC) echo Linking $@... - $(CC) $(LDFLAGS) -o testspeed testspeed.o ../cups/libcups.a \ + $(CC) $(LDFLAGS) -o testspeed testspeed.o ../cups/$(LIBCUPSSTATIC) \ $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) $(LIBGSSAPI) @@ -536,9 +539,9 @@ testspeed: testspeed.o ../cups/libcups.a # Make the test program, "testsub". # -testsub: testsub.o ../cups/libcups.a +testsub: testsub.o ../cups/$(LIBCUPSSTATIC) echo Linking $@... - $(CC) $(LDFLAGS) -o testsub testsub.o ../cups/libcups.a \ + $(CC) $(LDFLAGS) -o testsub testsub.o ../cups/$(LIBCUPSSTATIC) \ $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) $(LIBGSSAPI) diff --git a/scheduler/cert.c b/scheduler/cert.c index 94449eb46..c34efac0c 100644 --- a/scheduler/cert.c +++ b/scheduler/cert.c @@ -1,10 +1,9 @@ /* * "$Id: cert.c 7673 2008-06-18 22:31:26Z mike $" * - * Authentication certificate routines for the Common UNIX - * Printing System (CUPS). + * Authentication certificate routines for CUPS. * - * Copyright 2007-2009 by Apple Inc. + * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2006 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -390,9 +389,8 @@ cupsdFindCert(const char *certificate) /* I - Certificate */ void cupsdInitCerts(void) { +#ifndef HAVE_ARC4RANDOM cups_file_t *fp; /* /dev/random file */ - unsigned seed; /* Seed for random number generator */ - struct timeval tod; /* Time of day */ /* @@ -402,16 +400,20 @@ cupsdInitCerts(void) 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); - seed = (unsigned)(tod.tv_sec + tod.tv_usec); + 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... @@ -420,12 +422,11 @@ cupsdInitCerts(void) seed = cupsFileGetChar(fp); seed = (seed << 8) | cupsFileGetChar(fp); seed = (seed << 8) | cupsFileGetChar(fp); - seed = (seed << 8) | cupsFileGetChar(fp); + CUPS_SRAND((seed << 8) | cupsFileGetChar(fp)); cupsFileClose(fp); } - - CUPS_SRAND(seed); +#endif /* !HAVE_ARC4RANDOM */ /* * Create a root certificate and return... diff --git a/scheduler/classes.c b/scheduler/classes.c index 77214aba6..fca0d18b1 100644 --- a/scheduler/classes.c +++ b/scheduler/classes.c @@ -3,7 +3,7 @@ * * Printer class routines for the Common UNIX Printing System (CUPS). * - * Copyright 2007-2009 by Apple Inc. + * 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 @@ -117,7 +117,7 @@ cupsdAddPrinterToClass( * 'cupsdDeletePrinterFromClass()' - Delete a printer from a class. */ -void +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 */ @@ -149,13 +149,15 @@ cupsdDeletePrinterFromClass( (c->num_printers - i) * sizeof(cupsd_printer_t *)); } else - return; + return (0); /* * Update the IPP attributes (have to do this for member-names)... */ cupsdSetPrinterAttrs(c); + + return (1); } @@ -163,10 +165,11 @@ cupsdDeletePrinterFromClass( * 'cupsdDeletePrinterFromClasses()' - Delete a printer from all classes. */ -void +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 */ @@ -179,7 +182,7 @@ cupsdDeletePrinterFromClasses( c; c = (cupsd_printer_t *)cupsArrayNext(Printers)) if (c->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT)) - cupsdDeletePrinterFromClass(c, p); + changed |= cupsdDeletePrinterFromClass(c, p); /* * Then clean out any empty implicit classes... @@ -193,7 +196,10 @@ cupsdDeletePrinterFromClasses( cupsdLogMessage(CUPSD_LOG_DEBUG, "Deleting implicit class \"%s\"...", c->name); cupsdDeletePrinter(c, 0); + changed = 1; } + + return (changed); } diff --git a/scheduler/classes.h b/scheduler/classes.h index 68288f69b..e9940ce2b 100644 --- a/scheduler/classes.h +++ b/scheduler/classes.h @@ -3,7 +3,7 @@ * * Printer class definitions for the Common UNIX Printing System (CUPS). * - * Copyright 2007-2008 by Apple Inc. + * 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 @@ -21,9 +21,9 @@ extern cupsd_printer_t *cupsdAddClass(const char *name); extern void cupsdAddPrinterToClass(cupsd_printer_t *c, cupsd_printer_t *p); -extern void cupsdDeletePrinterFromClass(cupsd_printer_t *c, +extern int cupsdDeletePrinterFromClass(cupsd_printer_t *c, cupsd_printer_t *p); -extern void cupsdDeletePrinterFromClasses(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); diff --git a/scheduler/client.c b/scheduler/client.c index 93fbf3419..2400b57fe 100644 --- a/scheduler/client.c +++ b/scheduler/client.c @@ -3,7 +3,7 @@ * * Client routines for the Common UNIX Printing System (CUPS) scheduler. * - * Copyright 2007-2009 by Apple Inc. + * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * This file contains Kerberos support code, copyright 2006 by @@ -1131,8 +1131,8 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ *ptr = '\0'; } else - snprintf(locale, sizeof(locale), "%s.%s", - con->http.fields[HTTP_FIELD_ACCEPT_LANGUAGE], DefaultCharset); + snprintf(locale, sizeof(locale), "%s.UTF-8", + con->http.fields[HTTP_FIELD_ACCEPT_LANGUAGE]); con->language = cupsLangGet(locale); } @@ -2192,6 +2192,15 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ return; } } + else if (filestats.st_size == 0) + { + /* + * Don't allow empty file... + */ + + unlink(con->filename); + cupsdClearString(&con->filename); + } if (con->command) { diff --git a/scheduler/conf.c b/scheduler/conf.c index abcb0f183..bc83cc11c 100644 --- a/scheduler/conf.c +++ b/scheduler/conf.c @@ -3,7 +3,7 @@ * * Configuration routines for the Common UNIX Printing System (CUPS). * - * Copyright 2007-2009 by Apple Inc. + * 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 @@ -108,7 +108,6 @@ static const cupsd_var_t variables[] = { "ClassifyOverride", &ClassifyOverride, CUPSD_VARTYPE_BOOLEAN }, { "ConfigFilePerm", &ConfigFilePerm, CUPSD_VARTYPE_INTEGER }, { "DataDir", &DataDir, CUPSD_VARTYPE_STRING }, - { "DefaultCharset", &DefaultCharset, CUPSD_VARTYPE_STRING }, { "DefaultLanguage", &DefaultLanguage, CUPSD_VARTYPE_STRING }, { "DefaultLeaseDuration", &DefaultLeaseDuration, CUPSD_VARTYPE_INTEGER }, { "DefaultPaperSize", &DefaultPaperSize, CUPSD_VARTYPE_STRING }, @@ -132,7 +131,6 @@ static const cupsd_var_t variables[] = { "KeepAlive", &KeepAlive, CUPSD_VARTYPE_BOOLEAN }, #ifdef HAVE_LAUNCHD { "LaunchdTimeout", &LaunchdTimeout, CUPSD_VARTYPE_INTEGER }, - { "LaunchdConf", &LaunchdConf, CUPSD_VARTYPE_STRING }, #endif /* HAVE_LAUNCHD */ { "LimitRequestBody", &MaxRequestSize, CUPSD_VARTYPE_INTEGER }, { "ListenBackLog", &ListenBackLog, CUPSD_VARTYPE_INTEGER }, @@ -540,8 +538,6 @@ cupsdReadConfiguration(void) else cupsdSetString(&DefaultLanguage, language->language); - cupsdSetString(&DefaultCharset, _cupsEncodingName(language->encoding)); - cupsdClearString(&DefaultPaperSize); cupsdSetString(&RIPCache, "8m"); @@ -692,7 +688,6 @@ cupsdReadConfiguration(void) #ifdef HAVE_LAUNCHD LaunchdTimeout = DEFAULT_TIMEOUT + 10; - cupsdSetString(&LaunchdConf, CUPS_DEFAULT_LAUNCHD_CONF); #endif /* HAVE_LAUNCHD */ #ifdef __APPLE__ @@ -910,7 +905,7 @@ cupsdReadConfiguration(void) * Set the default locale using the language and charset... */ - cupsdSetStringf(&DefaultLocale, "%s.%s", DefaultLanguage, DefaultCharset); + cupsdSetStringf(&DefaultLocale, "%s.UTF-8", DefaultLanguage); /* * Update all relative filenames to include the full path from ServerRoot... diff --git a/scheduler/conf.h b/scheduler/conf.h index c30f97a5e..1084bc2af 100644 --- a/scheduler/conf.h +++ b/scheduler/conf.h @@ -1,8 +1,7 @@ /* * "$Id: conf.h 7935 2008-09-11 01:54:11Z mike $" * - * Configuration file definitions for the Common UNIX Printing System (CUPS) - * scheduler. + * Configuration file definitions for CUPS. * * Copyright 2007-2009 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. @@ -136,8 +135,6 @@ VAR char *AccessLog VALUE(NULL), /* Data file directory */ *DefaultLanguage VALUE(NULL), /* Default language encoding */ - *DefaultCharset VALUE(NULL), - /* Default charset */ *DefaultLocale VALUE(NULL), /* Default locale */ *DefaultPaperSize VALUE(NULL), @@ -253,8 +250,6 @@ VAR int SSLOptions VALUE(CUPSD_SSL_NONE); #ifdef HAVE_LAUNCHD VAR int LaunchdTimeout VALUE(DEFAULT_KEEPALIVE); /* Time after which an idle cupsd will exit */ -VAR char *LaunchdConf VALUE(NULL); - /* launchd(8) configuration file */ #endif /* HAVE_LAUNCHD */ #ifdef __APPLE__ diff --git a/scheduler/cups-driverd.cxx b/scheduler/cups-driverd.cxx index 0d776a637..b34f6616f 100644 --- a/scheduler/cups-driverd.cxx +++ b/scheduler/cups-driverd.cxx @@ -1991,7 +1991,8 @@ load_drv(const char *filename, /* I - Actual filename */ type = PPD_TYPE_PDF; } - for (product = (ppdcAttr *)d->attrs->first(), products_found = 0; + for (product = (ppdcAttr *)d->attrs->first(), products_found = 0, + ppd = NULL; product; product = (ppdcAttr *)d->attrs->next()) if (!strcmp(product->name->value, "Product")) diff --git a/scheduler/ipp.c b/scheduler/ipp.c index a2595d90e..ced835f29 100644 --- a/scheduler/ipp.c +++ b/scheduler/ipp.c @@ -3,7 +3,7 @@ * * IPP routines for the Common UNIX Printing System (CUPS) scheduler. * - * Copyright 2007-2009 by Apple Inc. + * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * This file contains Kerberos support code, copyright 2006 by @@ -390,7 +390,7 @@ cupsdProcessIPPRequest( charset->values[0].string.text); else ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_CHARSET, - "attributes-charset", NULL, DefaultCharset); + "attributes-charset", NULL, "utf-8"); if (language) ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, @@ -904,6 +904,9 @@ accept_jobs(cupsd_client_t *con, /* I - Client connection */ cupsdAddPrinterHistory(printer); + cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, printer, NULL, + "Now accepting jobs."); + if (dtype & CUPS_PRINTER_CLASS) { cupsdMarkDirty(CUPSD_DIRTY_CLASSES); @@ -1102,7 +1105,8 @@ add_class(cupsd_client_t *con, /* I - Client connection */ cupsdSetString(&pclass->info, attr->values[0].string.text); if ((attr = ippFindAttribute(con->request, "printer-is-accepting-jobs", - IPP_TAG_BOOLEAN)) != NULL) + IPP_TAG_BOOLEAN)) != NULL && + attr->values[0].boolean != pclass->accepting) { cupsdLogMessage(CUPSD_LOG_INFO, "Setting %s printer-is-accepting-jobs to %d (was %d.)", @@ -1110,6 +1114,9 @@ add_class(cupsd_client_t *con, /* I - Client connection */ pclass->accepting = attr->values[0].boolean; cupsdAddPrinterHistory(pclass); + + cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, pclass, NULL, "%s accepting jobs.", + pclass->accepting ? "Now" : "No longer"); } if ((attr = ippFindAttribute(con->request, "printer-is-shared", @@ -1154,6 +1161,9 @@ add_class(cupsd_client_t *con, /* I - Client connection */ strlcpy(pclass->state_message, attr->values[0].string.text, sizeof(pclass->state_message)); cupsdAddPrinterHistory(pclass); + + cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, pclass, NULL, "%s", + pclass->state_message); } if ((attr = ippFindAttribute(con->request, "member-uris", IPP_TAG_URI)) != NULL) @@ -1232,9 +1242,9 @@ add_class(cupsd_client_t *con, /* I - Client connection */ if (modify) { - cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED, pclass, NULL, - "Class \"%s\" modified by \"%s\".", pclass->name, - get_username(con)); + cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED | CUPSD_EVENT_PRINTER_CONFIG, + 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)); @@ -1243,9 +1253,9 @@ add_class(cupsd_client_t *con, /* I - Client connection */ { cupsdAddPrinterHistory(pclass); - cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, pclass, NULL, - "New class \"%s\" added by \"%s\".", pclass->name, - get_username(con)); + cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED | CUPSD_EVENT_PRINTER_CONFIG, + 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)); @@ -1332,7 +1342,6 @@ add_job(cupsd_client_t *con, /* I - Client connection */ *auth_info; /* auth-info attribute */ const char *val; /* Default option value */ int priority; /* Job priority */ - char *title; /* Job name/title */ cupsd_job_t *job; /* Current job */ char job_uri[HTTP_MAX_URI]; /* Job URI */ int kbytes; /* Size of print file */ @@ -2202,6 +2211,9 @@ add_job_subscriptions( 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) @@ -2604,7 +2616,8 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ } if ((attr = ippFindAttribute(con->request, "printer-is-accepting-jobs", - IPP_TAG_BOOLEAN)) != NULL) + IPP_TAG_BOOLEAN)) != NULL && + attr->values[0].boolean != printer->accepting) { cupsdLogMessage(CUPSD_LOG_INFO, "Setting %s printer-is-accepting-jobs to %d (was %d.)", @@ -2612,6 +2625,10 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ printer->accepting = attr->values[0].boolean; cupsdAddPrinterHistory(printer); + + cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, printer, NULL, + "%s accepting jobs.", + printer->accepting ? "Now" : "No longer"); } if ((attr = ippFindAttribute(con->request, "printer-is-shared", @@ -2656,6 +2673,9 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ strlcpy(printer->state_message, attr->values[0].string.text, sizeof(printer->state_message)); cupsdAddPrinterHistory(printer); + + cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, printer, NULL, "%s", + printer->state_message); } if ((attr = ippFindAttribute(con->request, "printer-state-reasons", @@ -2697,6 +2717,9 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ 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); @@ -2936,9 +2959,9 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ if (modify) { - cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED, printer, NULL, - "Printer \"%s\" modified by \"%s\".", printer->name, - get_username(con)); + cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED | CUPSD_EVENT_PRINTER_CONFIG, + 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)); @@ -2947,9 +2970,9 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ { cupsdAddPrinterHistory(printer); - cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, printer, NULL, - "New printer \"%s\" added by \"%s\".", printer->name, - get_username(con)); + cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED | CUPSD_EVENT_PRINTER_CONFIG, + 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)); @@ -6431,7 +6454,9 @@ delete_printer(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" deleted by \"%s\".", printer->name, get_username(con)); - cupsdDeletePrinter(printer, 0); + if (cupsdDeletePrinter(printer, 0)) + cupsdMarkDirty(CUPSD_DIRTY_CLASSES); + cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); } @@ -9034,6 +9059,9 @@ reject_jobs(cupsd_client_t *con, /* I - Client connection */ cupsdAddPrinterHistory(printer); + cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, printer, NULL, + "No longer accepting jobs."); + if (dtype & CUPS_PRINTER_CLASS) { cupsdMarkDirty(CUPSD_DIRTY_CLASSES); @@ -10186,7 +10214,7 @@ send_ipp_status(cupsd_client_t *con, /* I - Client connection */ if (ippFindAttribute(con->response, "attributes-charset", IPP_TAG_ZERO) == NULL) ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_CHARSET, - "attributes-charset", NULL, DefaultCharset); + "attributes-charset", NULL, "utf-8"); if (ippFindAttribute(con->response, "attributes-natural-language", IPP_TAG_ZERO) == NULL) diff --git a/scheduler/job.c b/scheduler/job.c index 4442cacc7..91a017b75 100644 --- a/scheduler/job.c +++ b/scheduler/job.c @@ -4291,16 +4291,16 @@ update_job(cupsd_job_t *job) /* I - Job to check */ break; } - if (event & CUPSD_EVENT_PRINTER_STATE) + if (event & CUPSD_EVENT_JOB_PROGRESS) + cupsdAddEvent(CUPSD_EVENT_JOB_PROGRESS, job->printer, job, + "%s", job->printer->state_message); + else 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 (event & CUPSD_EVENT_JOB_PROGRESS) - cupsdAddEvent(CUPSD_EVENT_JOB_PROGRESS, job->printer, job, - "%s", job->printer->state_message); if (ptr == NULL && !job->status_buffer->bufused) { diff --git a/scheduler/listen.c b/scheduler/listen.c index 2b4f9e0fd..85c807166 100644 --- a/scheduler/listen.c +++ b/scheduler/listen.c @@ -250,7 +250,8 @@ cupsdStartListening(void) unlink(lis->address.un.sun_path); /* - * Save the curent umask and set it to 0... + * Save the current umask and set it to 0 so that all users can access + * the domain socket... */ mask = umask(0); diff --git a/scheduler/main.c b/scheduler/main.c index 60e97d095..9dfb38966 100644 --- a/scheduler/main.c +++ b/scheduler/main.c @@ -1450,7 +1450,7 @@ static void launchd_checkin(void) { size_t i, /* Looping var */ - count; /* Numebr of listeners */ + count; /* Number of listeners */ int portnum; /* Port number */ launch_data_t ld_msg, /* Launch data message */ ld_resp, /* Launch data response */ diff --git a/scheduler/printers.c b/scheduler/printers.c index 1e615ebe0..876231d45 100644 --- a/scheduler/printers.c +++ b/scheduler/printers.c @@ -3,7 +3,7 @@ * * Printer routines for the Common UNIX Printing System (CUPS). * - * Copyright 2007-2009 by Apple Inc. + * 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 @@ -430,7 +430,7 @@ cupsdCreateCommonData(void) /* charset-configured */ ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_CHARSET | IPP_TAG_COPY, - "charset-configured", NULL, DefaultCharset); + "charset-configured", NULL, "utf-8"); /* charset-supported */ ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_CHARSET | IPP_TAG_COPY, @@ -450,8 +450,8 @@ cupsdCreateCommonData(void) ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_TEXT | IPP_TAG_COPY, "cups-version", NULL, CUPS_SVERSION + 6); - /* generated-natural-language-supported */ - ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE | IPP_TAG_COPY, + /* 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 */ @@ -534,8 +534,8 @@ cupsdCreateCommonData(void) ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "multiple-operation-time-out", MultipleOperationTimeout); - /* natural-language-configured */ - ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE | IPP_TAG_COPY, + /* natural-language-configured (no IPP_TAG_COPY) */ + ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE, "natural-language-configured", NULL, DefaultLanguage); /* notify-attributes-supported */ @@ -655,12 +655,13 @@ cupsdDeleteAllPrinters(void) * 'cupsdDeletePrinter()' - Delete a printer from the system. */ -void +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 */ + int i, /* Looping var */ + changed = 0; /* Class changed? */ #ifdef __sgi char filename[1024]; /* Interface script filename */ #endif /* __sgi */ @@ -771,7 +772,7 @@ cupsdDeletePrinter( if (!(p->type & CUPS_PRINTER_IMPLICIT)) { - cupsdDeletePrinterFromClasses(p); + changed = cupsdDeletePrinterFromClasses(p); /* * Deregister from any browse protocols... @@ -848,6 +849,8 @@ cupsdDeletePrinter( */ cupsArrayRestore(Printers); + + return (changed); } @@ -2771,6 +2774,12 @@ cupsdSetPrinterState( 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" + }; /* @@ -2794,9 +2803,9 @@ cupsdSetPrinterState( { cupsdAddEvent(s == IPP_PRINTER_STOPPED ? CUPSD_EVENT_PRINTER_STOPPED : CUPSD_EVENT_PRINTER_STATE, p, NULL, - "%s \"%s\" state changed.", + "%s \"%s\" state changed to %s.", (p->type & CUPS_PRINTER_CLASS) ? "Class" : "Printer", - p->name); + p->name, printer_states[p->state]); /* * Let the browse code know this needs to be updated... diff --git a/scheduler/printers.h b/scheduler/printers.h index 713539941..327909240 100644 --- a/scheduler/printers.h +++ b/scheduler/printers.h @@ -140,7 +140,7 @@ extern void cupsdAddPrinterUser(cupsd_printer_t *p, const char *username); extern void cupsdCreateCommonData(void); extern void cupsdDeleteAllPrinters(void); -extern void cupsdDeletePrinter(cupsd_printer_t *p, int update); +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, diff --git a/standards/Makefile b/standards/Makefile index 53b2c1f98..d6ddb8353 100644 --- a/standards/Makefile +++ b/standards/Makefile @@ -1,9 +1,9 @@ # # "$Id: Makefile 7871 2008-08-27 21:12:43Z mike $" # -# Standards makefile for the Common UNIX Printing System (CUPS). +# Standards makefile for CUPS. # -# Copyright 2007-2009 by Apple Inc. +# Copyright 2007-2010 by Apple Inc. # Copyright 2006 by Easy Software Products. # # These coded instructions, statements, and computer programs are the @@ -153,8 +153,8 @@ uninstall: # rfctohtml - make html versions of RFCs... # -rfctohtml: rfctohtml.o ../cups/libcups.a - $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ rfctohtml.o ../cups/libcups.a \ +rfctohtml: rfctohtml.o ../cups/$(LIBCUPSSTATIC) + $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ rfctohtml.o ../cups/$(LIBCUPSSTATIC) \ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) 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 + To: Ned Freed + 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 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 := + + 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 + To: Ned Freed + 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: + 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: + 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: + 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: + 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: + 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: + Content-Type: multipart/alternative; boundary=42 + Content-ID: + + --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: + + --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: + + --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: + + 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 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/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/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 + ). 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 "€". 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 + 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 .) + + 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 C'est la vie. 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 + , 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, . + + [record-jar] Raymond, E., "The Art of Unix Programming", 2003, + . + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +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/systemv/Dependencies b/systemv/Dependencies index f0b180813..32aa60e0e 100644 --- a/systemv/Dependencies +++ b/systemv/Dependencies @@ -44,12 +44,13 @@ lpoptions.o: ../cups/string.h ../config.h ../cups/cups.h ../cups/ipp.h lpoptions.o: ../cups/http.h ../cups/versioning.h ../cups/ppd.h lpoptions.o: ../cups/array.h ../cups/file.h ../cups/language.h ../cups/i18n.h lpoptions.o: ../cups/transcode.h -lppasswd.o: ../cups/string.h ../config.h ../cups/cups.h ../cups/ipp.h -lppasswd.o: ../cups/http.h ../cups/versioning.h ../cups/ppd.h ../cups/array.h -lppasswd.o: ../cups/file.h ../cups/language.h ../cups/i18n.h -lppasswd.o: ../cups/transcode.h ../cups/md5.h -lpstat.o: ../cups/http-private.h ../config.h ../cups/http.h -lpstat.o: ../cups/versioning.h ../cups/md5.h ../cups/ipp-private.h -lpstat.o: ../cups/ipp.h ../cups/string.h ../cups/cups.h ../cups/ppd.h -lpstat.o: ../cups/array.h ../cups/file.h ../cups/language.h ../cups/i18n.h -lpstat.o: ../cups/transcode.h ../cups/debug.h +lppasswd.o: ../cups/globals.h ../cups/string.h ../config.h +lppasswd.o: ../cups/http-private.h ../cups/http.h ../cups/versioning.h +lppasswd.o: ../cups/md5.h ../cups/ipp-private.h ../cups/ipp.h ../cups/cups.h +lppasswd.o: ../cups/ppd.h ../cups/array.h ../cups/file.h ../cups/language.h +lppasswd.o: ../cups/i18n.h ../cups/transcode.h ../cups/md5.h +lpstat.o: ../cups/globals.h ../cups/string.h ../config.h +lpstat.o: ../cups/http-private.h ../cups/http.h ../cups/versioning.h +lpstat.o: ../cups/md5.h ../cups/ipp-private.h ../cups/ipp.h ../cups/cups.h +lpstat.o: ../cups/ppd.h ../cups/array.h ../cups/file.h ../cups/language.h +lpstat.o: ../cups/i18n.h ../cups/transcode.h ../cups/debug.h diff --git a/systemv/Makefile b/systemv/Makefile index 0df674a0f..ae5f5a063 100644 --- a/systemv/Makefile +++ b/systemv/Makefile @@ -1,9 +1,9 @@ # # "$Id: Makefile 7929 2008-09-10 22:23:59Z mike $" # -# System V commands makefile for the Common UNIX Printing System (CUPS). +# System V commands makefile for CUPS. # -# Copyright 2007-2009 by Apple Inc. +# 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 @@ -212,10 +212,10 @@ cupstestppd: cupstestppd.o ../cups/$(LIBCUPS) ../filter/$(LIBCUPSIMAGE) echo Linking $@... $(CC) $(LDFLAGS) -o $@ cupstestppd.o $(LINKCUPSIMAGE) $(IMGLIBS) $(LIBS) -cupstestppd-static: cupstestppd.o ../cups/libcups.a ../filter/libcupsimage.a +cupstestppd-static: cupstestppd.o ../cups/$(LIBCUPSSTATIC) ../filter/libcupsimage.a echo Linking $@... $(CC) $(LDFLAGS) -o $@ cupstestppd.o ../filter/libcupsimage.a \ - ../cups/libcups.a $(IMGLIBS) $(LIBGSSAPI) $(LIBS) $(LIBZ) + ../cups/$(LIBCUPSSTATIC) $(IMGLIBS) $(LIBGSSAPI) $(LIBS) $(LIBZ) # diff --git a/systemv/lppasswd.c b/systemv/lppasswd.c index 5dfeb48a3..cd51014b5 100644 --- a/systemv/lppasswd.c +++ b/systemv/lppasswd.c @@ -1,9 +1,9 @@ /* * "$Id: lppasswd.c 6649 2007-07-11 21:46:42Z mike $" * - * MD5 password program for the Common UNIX Printing System (CUPS). + * MD5 password program for CUPS. * - * Copyright 2007-2009 by Apple Inc. + * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2006 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -31,9 +31,7 @@ #include #include -#include -#include -#include +#include #include #ifndef WIN32 @@ -79,7 +77,6 @@ main(int argc, /* I - Number of command-line arguments */ groupline[17], /* Group from line */ md5line[33], /* MD5-sum from line */ md5new[33]; /* New MD5 sum */ - const char *root; /* CUPS server root directory */ char passwdmd5[1024], /* passwd.md5 file */ passwdold[1024], /* passwd.old file */ passwdnew[1024]; /* passwd.tmp file */ @@ -88,12 +85,15 @@ main(int argc, /* I - Number of command-line arguments */ 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... @@ -113,18 +113,11 @@ main(int argc, /* I - Number of command-line arguments */ /* * Find the server directory... - * - * We use the CUPS_SERVERROOT environment variable when we are running - * as root or when lppasswd is not setuid... */ - if ((root = getenv("CUPS_SERVERROOT")) == NULL || - (getuid() != geteuid() && getuid())) - root = CUPS_SERVERROOT; - - snprintf(passwdmd5, sizeof(passwdmd5), "%s/passwd.md5", root); - snprintf(passwdold, sizeof(passwdold), "%s/passwd.old", root); - snprintf(passwdnew, sizeof(passwdnew), "%s/passwd.new", root); + 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... @@ -220,7 +213,8 @@ main(int argc, /* I - Number of command-line arguments */ if (op != DELETE) { - if ((passwd = cupsGetPassword(_("Enter password:"))) == NULL) + if ((passwd = cupsGetPassword( + _cupsLangString(lang, _("Enter password:")))) == NULL) return (1); if ((newpass = strdup(passwd)) == NULL) @@ -231,7 +225,8 @@ main(int argc, /* I - Number of command-line arguments */ return (1); } - if ((passwd = cupsGetPassword(_("Enter password again:"))) == NULL) + if ((passwd = cupsGetPassword( + _cupsLangString(lang, _("Enter password again:")))) == NULL) return (1); if (strcmp(passwd, newpass) != 0) diff --git a/systemv/lpstat.c b/systemv/lpstat.c index e98aaa70d..5f4e0b47a 100644 --- a/systemv/lpstat.c +++ b/systemv/lpstat.c @@ -1,9 +1,9 @@ /* * "$Id: lpstat.c 7921 2008-09-10 15:42:24Z mike $" * - * "lpstat" command for the Common UNIX Printing System (CUPS). + * "lpstat" command for CUPS. * - * Copyright 2007-2009 by Apple Inc. + * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2006 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -34,10 +34,7 @@ #include #include #include -#include -#include -#include -#include +#include #include @@ -1518,7 +1515,7 @@ show_printers(const char *printers, /* I - Destinations */ char printer_uri[HTTP_MAX_URI], /* Printer URI */ printer_state_time[255];/* Printer state time */ - const char *root; /* Server root directory... */ + _cups_globals_t *cg = _cupsGlobals(); /* Global data */ static const char *pattrs[] = /* Attributes we need for printers... */ { "printer-name", @@ -1543,9 +1540,6 @@ show_printers(const char *printers, /* I - Destinations */ DEBUG_printf(("show_printers(printers=\"%s\", num_dests=%d, dests=%p, " "long_status=%d)\n", printers, num_dests, dests, long_status)); - if ((root = getenv("CUPS_SERVERROOT")) == NULL) - root = CUPS_SERVERROOT; - if (printers != NULL && !strcmp(printers, "all")) printers = NULL; @@ -1820,10 +1814,11 @@ show_printers(const char *printers, /* I - Destinations */ if (make_model && strstr(make_model, "System V Printer")) _cupsLangPrintf(stdout, _("\tInterface: %s/interfaces/%s\n"), - root, printer); + cg->cups_serverroot, printer); else if (make_model && !strstr(make_model, "Raw Printer")) _cupsLangPrintf(stdout, - _("\tInterface: %s/ppd/%s.ppd\n"), root, printer); + _("\tInterface: %s/ppd/%s.ppd\n"), + cg->cups_serverroot, printer); } _cupsLangPuts(stdout, _("\tOn fault: no alert\n")); _cupsLangPuts(stdout, _("\tAfter fault: continue\n")); @@ -1933,10 +1928,11 @@ show_printers(const char *printers, /* I - Destinations */ if (make_model && strstr(make_model, "System V Printer")) _cupsLangPrintf(stdout, _("\tInterface: %s/interfaces/%s\n"), - root, printer); + cg->cups_serverroot, printer); else if (make_model && !strstr(make_model, "Raw Printer")) _cupsLangPrintf(stdout, - _("\tInterface: %s/ppd/%s.ppd\n"), root, printer); + _("\tInterface: %s/ppd/%s.ppd\n"), + cg->cups_serverroot, printer); } _cupsLangPuts(stdout, _("\tOn fault: no alert\n")); _cupsLangPuts(stdout, _("\tAfter fault: continue\n")); diff --git a/templates/add-class.tmpl b/templates/add-class.tmpl index 0bb15f18d..eaf52d73d 100644 --- a/templates/add-class.tmpl +++ b/templates/add-class.tmpl @@ -3,6 +3,7 @@

Add Class

+ diff --git a/templates/add-printer.tmpl b/templates/add-printer.tmpl index 7f375078a..361958b67 100644 --- a/templates/add-printer.tmpl +++ b/templates/add-printer.tmpl @@ -3,6 +3,7 @@

Add Printer

+ diff --git a/templates/add-rss-subscription.tmpl b/templates/add-rss-subscription.tmpl index 810fb3a50..e0727835b 100644 --- a/templates/add-rss-subscription.tmpl +++ b/templates/add-rss-subscription.tmpl @@ -1,4 +1,5 @@ +

Add RSS Subscription

diff --git a/templates/admin.tmpl b/templates/admin.tmpl index bbf9db7cd..da89d54e2 100644 --- a/templates/admin.tmpl +++ b/templates/admin.tmpl @@ -4,16 +4,16 @@

Printers

- -
+
+
-{have_samba?
:} +{have_samba?
:}

Classes

-
+

@@ -28,7 +28,7 @@

Server

-
+
@@ -38,6 +38,7 @@

{SETTINGS_ERROR}
: + {ADVANCEDSETTINGS?

Server Settings\:

@@ -95,7 +96,7 @@

RSS Subscriptions

- +

diff --git a/templates/choose-device.tmpl b/templates/choose-device.tmpl index a4877ca63..c5ab251b5 100644 --- a/templates/choose-device.tmpl +++ b/templates/choose-device.tmpl @@ -3,6 +3,7 @@

{op=modify-printer?Modify {printer_name}:Add Printer}

{CUPS_GET_DEVICES_DONE? + {printer_name?:} diff --git a/templates/choose-make.tmpl b/templates/choose-make.tmpl index e2731dea3..65096ad9a 100644 --- a/templates/choose-make.tmpl +++ b/templates/choose-make.tmpl @@ -3,6 +3,7 @@

{op=modify-printer?Modify {printer_name}:Add Printer}

+ {printer_name?:} diff --git a/templates/choose-model.tmpl b/templates/choose-model.tmpl index 33282fb15..992cd01fd 100644 --- a/templates/choose-model.tmpl +++ b/templates/choose-model.tmpl @@ -3,6 +3,7 @@

{op=modify-printer?Modify {printer_name}:Add Printer}

+ {printer_name?:} diff --git a/templates/choose-serial.tmpl b/templates/choose-serial.tmpl index d714779b3..56a14a4cb 100644 --- a/templates/choose-serial.tmpl +++ b/templates/choose-serial.tmpl @@ -3,6 +3,7 @@

{op=modify-printer?Modify {printer_name}:Add Printer}

+ {printer_name?:} diff --git a/templates/choose-uri.tmpl b/templates/choose-uri.tmpl index 907c02aca..e62ea1e13 100644 --- a/templates/choose-uri.tmpl +++ b/templates/choose-uri.tmpl @@ -3,6 +3,7 @@

{op=modify-printer?Modify {printer_name}:Add Printer}

+ {printer_name?:} diff --git a/templates/class-confirm.tmpl b/templates/class-confirm.tmpl index c14d35482..5f0277cb5 100644 --- a/templates/class-confirm.tmpl +++ b/templates/class-confirm.tmpl @@ -5,6 +5,6 @@

Warning: Are you sure you want to delete class {printer_name}?

-

+

diff --git a/templates/class.tmpl b/templates/class.tmpl index 535af64a6..9987062d2 100644 --- a/templates/class.tmpl +++ b/templates/class.tmpl @@ -5,6 +5,7 @@ {server_is_sharing_printers=0?Not:{printer_is_shared=0?Not:}} Shared{default_name={printer_name}?, Server Default:}) +
diff --git a/templates/de/add-printer.tmpl b/templates/de/add-printer.tmpl index 42d18fe0e..15380b97b 100644 --- a/templates/de/add-printer.tmpl +++ b/templates/de/add-printer.tmpl @@ -3,6 +3,7 @@

Drucker hinzufügen

+ diff --git a/templates/de/add-rss-subscription.tmpl b/templates/de/add-rss-subscription.tmpl index 264457de0..cef109ca9 100644 --- a/templates/de/add-rss-subscription.tmpl +++ b/templates/de/add-rss-subscription.tmpl @@ -1,4 +1,5 @@ +

>RSS Subskription hinzufügen

diff --git a/templates/de/admin.tmpl b/templates/de/admin.tmpl index a3445479c..1ad132691 100644 --- a/templates/de/admin.tmpl +++ b/templates/de/admin.tmpl @@ -4,16 +4,16 @@

Drucker

- -
+
+
-{have_samba?
:} +{have_samba?
:}

Klassen

-
+

@@ -28,7 +28,7 @@

Server

-
+
@@ -38,6 +38,7 @@

{SETTINGS_ERROR}
: + {ADVANCEDSETTINGS?

Erweiterte Servereinstellungen\:

@@ -95,7 +96,7 @@

RSS Subskriptionen

- +

@@ -104,6 +105,6 @@ {[notify_subscription_id] } + }
NameEreignisWarteschlange
{notify_recipient_name}
-
 
{notify_events} {notify_printer_name?{notify_printer_name}:Alle Warteschlangen}
{notify_events} {notify_printer_name?{notify_printer_name}:Alle Warteschlangen}
:} diff --git a/templates/de/choose-device.tmpl b/templates/de/choose-device.tmpl index c292f0a37..3be8a350c 100644 --- a/templates/de/choose-device.tmpl +++ b/templates/de/choose-device.tmpl @@ -6,6 +6,7 @@ ALT="Busy Indicator"> Suche nach Druckern...

}
+ {printer_name?:} diff --git a/templates/de/choose-make.tmpl b/templates/de/choose-make.tmpl index 96b32e309..6d572a6b2 100644 --- a/templates/de/choose-make.tmpl +++ b/templates/de/choose-make.tmpl @@ -3,6 +3,7 @@

{op=modify-printer?{printer_name} ändern:Drucker hinzufügen}

+ {printer_name?:} diff --git a/templates/de/choose-model.tmpl b/templates/de/choose-model.tmpl index 0b651fcbb..2f5bb18d8 100644 --- a/templates/de/choose-model.tmpl +++ b/templates/de/choose-model.tmpl @@ -3,6 +3,7 @@

{op=modify-printer?{printer_name} ändern:Drucker hinzufügen}

+ {printer_name?:} @@ -45,7 +46,7 @@ Diesen Drucker {?printer_is_shared=?nicht:{?printer_is_shared=0?nicht:}} freigeb ->Oder stellen Sie eine PPD Datei bereit: +Oder stellen Sie eine PPD Datei bereit: diff --git a/templates/de/choose-serial.tmpl b/templates/de/choose-serial.tmpl index 7fab7ca94..a6f0044b5 100644 --- a/templates/de/choose-serial.tmpl +++ b/templates/de/choose-serial.tmpl @@ -3,6 +3,7 @@

{op=modify-printer?{printer_name} ändern:Drucker hinzufügen}

+ {printer_name?:} diff --git a/templates/de/choose-uri.tmpl b/templates/de/choose-uri.tmpl index 6d2244f58..073b0d824 100644 --- a/templates/de/choose-uri.tmpl +++ b/templates/de/choose-uri.tmpl @@ -3,6 +3,7 @@

{op=modify-printer?{printer_name} ändern:Drucker hinzufügen}

+ {printer_name?:} diff --git a/templates/de/class-confirm.tmpl b/templates/de/class-confirm.tmpl index 20cd6db2d..5e0223cff 100644 --- a/templates/de/class-confirm.tmpl +++ b/templates/de/class-confirm.tmpl @@ -5,6 +5,6 @@

Warnung: Sind Sie sicher, dass Sie die Klasse {printer_name} löschen wollen?

-

+

diff --git a/templates/de/class.tmpl b/templates/de/class.tmpl index da72bc44c..a64a2daef 100644 --- a/templates/de/class.tmpl +++ b/templates/de/class.tmpl @@ -5,6 +5,7 @@ {server_is_sharing_printers=0?Nicht:{printer_is_shared=0?Nicht:}} Freigegeben{default_name={printer_name}?, Standarddrucker:})
+ diff --git a/templates/de/job-move.tmpl b/templates/de/job-move.tmpl index 90cc98e7a..67c57dd31 100644 --- a/templates/de/job-move.tmpl +++ b/templates/de/job-move.tmpl @@ -1,6 +1,7 @@
+ {job_id?:} diff --git a/templates/de/jobs.tmpl b/templates/de/jobs.tmpl index 3a524bb58..94a60b0aa 100644 --- a/templates/de/jobs.tmpl +++ b/templates/de/jobs.tmpl @@ -17,18 +17,18 @@ "{job_printer_state_message}":} {job_preserved>0?{job_state>5? - + :}:} {job_state=4? -
+
:} {job_state=3? -
+
:} {job_state<7? -
+
-
:} +
:}   } diff --git a/templates/de/list-available-printers.tmpl b/templates/de/list-available-printers.tmpl index 9ca2b5377..08a04522a 100644 --- a/templates/de/list-available-printers.tmpl +++ b/templates/de/list-available-printers.tmpl @@ -4,7 +4,7 @@ {#device_uri=0?

Keine Drucker gefunden.

:
    {[device_uri] -
  • +
  • {device_make_and_model} ({device_info})
  • }
} diff --git a/templates/de/modify-class.tmpl b/templates/de/modify-class.tmpl index 1db4a3fd5..2e0bae80d 100644 --- a/templates/de/modify-class.tmpl +++ b/templates/de/modify-class.tmpl @@ -3,6 +3,7 @@

Klasse {printer_name} ändern

+ diff --git a/templates/de/modify-printer.tmpl b/templates/de/modify-printer.tmpl index a44da2bea..d128471d7 100644 --- a/templates/de/modify-printer.tmpl +++ b/templates/de/modify-printer.tmpl @@ -3,6 +3,7 @@

{printer_name} ändern

+ diff --git a/templates/de/printer-confirm.tmpl b/templates/de/printer-confirm.tmpl index 3bbe1fb34..030f6524a 100644 --- a/templates/de/printer-confirm.tmpl +++ b/templates/de/printer-confirm.tmpl @@ -5,6 +5,6 @@

Warnung: Sind Sie sicher, dass Sie den Drucker {printer_name} löschen wollen?

-

+

diff --git a/templates/de/printer.tmpl b/templates/de/printer.tmpl index e3e1ebc4a..ffc58e919 100644 --- a/templates/de/printer.tmpl +++ b/templates/de/printer.tmpl @@ -6,6 +6,7 @@ {server_is_sharing_printers=0?Nicht:{printer_is_shared=0?Nicht:}} freigegeben{default_name={printer_name}?, Standarddrucker:})
+

Drucker für Samba freigeben

diff --git a/templates/de/set-printer-options-header.tmpl b/templates/de/set-printer-options-header.tmpl index b4187e321..75f9f4ff2 100644 --- a/templates/de/set-printer-options-header.tmpl +++ b/templates/de/set-printer-options-header.tmpl @@ -3,6 +3,7 @@

Standardeinstellungen für {printer_name} festlegen

+ {HAVE_AUTOCONFIGURE?:} diff --git a/templates/de/users.tmpl b/templates/de/users.tmpl index acb889272..0704e8754 100644 --- a/templates/de/users.tmpl +++ b/templates/de/users.tmpl @@ -1,6 +1,7 @@
+ {IS_CLASS?:} diff --git a/templates/edit-config.tmpl b/templates/edit-config.tmpl index ea45d81f5..8947382b1 100644 --- a/templates/edit-config.tmpl +++ b/templates/edit-config.tmpl @@ -10,7 +10,7 @@ function reset_config()

Edit Configuration File

- + diff --git a/templates/es/add-class.tmpl b/templates/es/add-class.tmpl index bc2db61ed..f7e79fa89 100644 --- a/templates/es/add-class.tmpl +++ b/templates/es/add-class.tmpl @@ -3,6 +3,7 @@

Añadir clase

+ diff --git a/templates/es/add-printer.tmpl b/templates/es/add-printer.tmpl index 9e65a93b9..eedc3db40 100644 --- a/templates/es/add-printer.tmpl +++ b/templates/es/add-printer.tmpl @@ -3,6 +3,7 @@

Añadir impresora

+ diff --git a/templates/es/add-rss-subscription.tmpl b/templates/es/add-rss-subscription.tmpl index 89d77ced6..8fb7f3da0 100644 --- a/templates/es/add-rss-subscription.tmpl +++ b/templates/es/add-rss-subscription.tmpl @@ -1,4 +1,5 @@ +

Añadir subscripción RSS

diff --git a/templates/es/admin.tmpl b/templates/es/admin.tmpl index 81a92ba18..53e5d34d8 100644 --- a/templates/es/admin.tmpl +++ b/templates/es/admin.tmpl @@ -4,16 +4,16 @@

Impresoras

- -
+
+
-{have_samba?
:} +{have_samba?
:}

Clases

-
+

@@ -28,7 +28,7 @@

Servidor

-
+
@@ -38,6 +38,7 @@

{SETTINGS_ERROR}
: + {ADVANCEDSETTINGS?

Configuración del servidor\:

@@ -95,7 +96,7 @@

Subscripciones RSS

- +

@@ -104,6 +105,6 @@ {[notify_subscription_id] } + }
NombreEventosNombre de la cola
{notify_recipient_name}
-
 
{notify_events} {notify_printer_name?{notify_printer_name}:Todas las colas}
{notify_events} {notify_printer_name?{notify_printer_name}:Todas las colas}
:} diff --git a/templates/es/choose-device.tmpl b/templates/es/choose-device.tmpl index 79ac4942d..9f314fdf6 100644 --- a/templates/es/choose-device.tmpl +++ b/templates/es/choose-device.tmpl @@ -6,6 +6,7 @@ ALT="Busy Indicator"> Buscando impresoras...

}
+ {printer_name?:} diff --git a/templates/es/choose-make.tmpl b/templates/es/choose-make.tmpl index 370db237d..c846de4df 100644 --- a/templates/es/choose-make.tmpl +++ b/templates/es/choose-make.tmpl @@ -3,6 +3,7 @@

{op=modify-printer?Modificar {printer_name}:Añadir impresora}

+ {printer_name?:} diff --git a/templates/es/choose-model.tmpl b/templates/es/choose-model.tmpl index 8338da27d..497d4b1d1 100644 --- a/templates/es/choose-model.tmpl +++ b/templates/es/choose-model.tmpl @@ -3,6 +3,7 @@

{op=modify-printer?Modificar {printer_name}:Añadir impresora}

+ {printer_name?:} diff --git a/templates/es/choose-serial.tmpl b/templates/es/choose-serial.tmpl index 513d0a20d..e296fb95f 100644 --- a/templates/es/choose-serial.tmpl +++ b/templates/es/choose-serial.tmpl @@ -3,6 +3,7 @@

{op=modify-printer?Modificar {printer_name}:Añadir impresora}

+ {printer_name?:} diff --git a/templates/es/choose-uri.tmpl b/templates/es/choose-uri.tmpl index a7ff12d2c..c02577395 100644 --- a/templates/es/choose-uri.tmpl +++ b/templates/es/choose-uri.tmpl @@ -3,6 +3,7 @@

{op=modify-printer?Modificar {printer_name}:Añadir impresora}

+ {printer_name?:} diff --git a/templates/es/class-confirm.tmpl b/templates/es/class-confirm.tmpl index f55f1c64b..a30ff726f 100644 --- a/templates/es/class-confirm.tmpl +++ b/templates/es/class-confirm.tmpl @@ -5,6 +5,6 @@

Advertencia: ¿Está seguro de querer borrar la clase {printer_name}?

-

+

diff --git a/templates/es/class.tmpl b/templates/es/class.tmpl index 9b511ae87..f3704380b 100644 --- a/templates/es/class.tmpl +++ b/templates/es/class.tmpl @@ -5,6 +5,7 @@ {server_is_sharing_printers=0?no:{printer_is_shared=0?no:}} compartida{default_name={printer_name}?, predeterminada del servidor:})
+ diff --git a/templates/es/job-move.tmpl b/templates/es/job-move.tmpl index 30919df5d..e6aac39a5 100644 --- a/templates/es/job-move.tmpl +++ b/templates/es/job-move.tmpl @@ -1,6 +1,7 @@
+ {job_id?:} diff --git a/templates/es/jobs.tmpl b/templates/es/jobs.tmpl index 26d1e7adf..e1bc195b5 100644 --- a/templates/es/jobs.tmpl +++ b/templates/es/jobs.tmpl @@ -17,18 +17,18 @@ "{job_printer_state_message}":} {job_preserved>0?{job_state>5? - + :}:} {job_state=4? -
+
:} {job_state=3? -
+
:} {job_state<7? -
+
-
:} +
:}   } diff --git a/templates/es/list-available-printers.tmpl b/templates/es/list-available-printers.tmpl index b4ea626ad..51e0eb982 100644 --- a/templates/es/list-available-printers.tmpl +++ b/templates/es/list-available-printers.tmpl @@ -4,7 +4,7 @@ {#device_uri=0?

No se encuentran impresoras.

:
    {[device_uri] -
  • +
  • {device_make_and_model} ({device_info})
  • }
} diff --git a/templates/es/modify-class.tmpl b/templates/es/modify-class.tmpl index 0dfb4736e..a50b2bb72 100644 --- a/templates/es/modify-class.tmpl +++ b/templates/es/modify-class.tmpl @@ -3,6 +3,7 @@

Modificar clase {printer_name}

+ diff --git a/templates/es/modify-printer.tmpl b/templates/es/modify-printer.tmpl index 944a087bc..3c09da09e 100644 --- a/templates/es/modify-printer.tmpl +++ b/templates/es/modify-printer.tmpl @@ -3,6 +3,7 @@

Modificar {printer_name}

+ diff --git a/templates/es/printer-confirm.tmpl b/templates/es/printer-confirm.tmpl index bd97f50d9..1de104a63 100644 --- a/templates/es/printer-confirm.tmpl +++ b/templates/es/printer-confirm.tmpl @@ -5,6 +5,6 @@

Advertencia: ¿Está seguro de querer borrar la impresora {printer_name}?

-

+

diff --git a/templates/es/printer.tmpl b/templates/es/printer.tmpl index 2a1ad0955..f7642ac0c 100644 --- a/templates/es/printer.tmpl +++ b/templates/es/printer.tmpl @@ -6,6 +6,7 @@ {server_is_sharing_printers=0?no:{printer_is_shared=0?no:}} compartida{default_name={printer_name}?, predeterminada del servidor:})
+

Exportar impresoras a Samba

diff --git a/templates/es/set-printer-options-header.tmpl b/templates/es/set-printer-options-header.tmpl index fed45926d..8a2740b3b 100644 --- a/templates/es/set-printer-options-header.tmpl +++ b/templates/es/set-printer-options-header.tmpl @@ -3,6 +3,7 @@

Establecer opciones predeterminadas de {printer_name}

+ {HAVE_AUTOCONFIGURE?:} diff --git a/templates/es/users.tmpl b/templates/es/users.tmpl index 1b3084278..a8a645e6f 100644 --- a/templates/es/users.tmpl +++ b/templates/es/users.tmpl @@ -1,6 +1,7 @@
+ {IS_CLASS?:} diff --git a/templates/eu/add-class.tmpl b/templates/eu/add-class.tmpl index a17ce9852..bd7436ae2 100644 --- a/templates/eu/add-class.tmpl +++ b/templates/eu/add-class.tmpl @@ -3,6 +3,7 @@

Gehitu klasea

+ diff --git a/templates/eu/add-printer.tmpl b/templates/eu/add-printer.tmpl index 853d052ff..312da1e6e 100644 --- a/templates/eu/add-printer.tmpl +++ b/templates/eu/add-printer.tmpl @@ -3,6 +3,7 @@

Gehitu inprimagailua

+ diff --git a/templates/eu/add-rss-subscription.tmpl b/templates/eu/add-rss-subscription.tmpl index 01421c455..b81b5b22f 100644 --- a/templates/eu/add-rss-subscription.tmpl +++ b/templates/eu/add-rss-subscription.tmpl @@ -1,4 +1,5 @@ +

Gehitu RSS harpidetza

diff --git a/templates/eu/admin.tmpl b/templates/eu/admin.tmpl index 5f13fe21e..8b5ecddcb 100644 --- a/templates/eu/admin.tmpl +++ b/templates/eu/admin.tmpl @@ -4,16 +4,16 @@

Inprimagailuak

- -
+
+
-{have_samba?
:} +{have_samba?
:}

Klaseak

-
+

@@ -28,7 +28,7 @@

Zerbitzaria

-
+
@@ -38,6 +38,7 @@

{SETTINGS_ERROR}
: + {ADVANCEDSETTINGS?

Zerbitzariaren ezarpenak\:

@@ -95,7 +96,7 @@

RSS harpidetzak

- +

@@ -104,6 +105,6 @@ {[notify_subscription_id] } + }
IzenaGertaerakIlararen izena
{notify_recipient_name}
-
 
{notify_events} {notify_printer_name?{notify_printer_name}:Ilara guztiak}
{notify_events} {notify_printer_name?{notify_printer_name}:Ilara guztiak}
:} diff --git a/templates/eu/choose-device.tmpl b/templates/eu/choose-device.tmpl index e2e9b26b1..36b7b86b7 100644 --- a/templates/eu/choose-device.tmpl +++ b/templates/eu/choose-device.tmpl @@ -6,6 +6,7 @@ ALT="Busy Indicator"> Inprimagailuak bilatzen...

}
+ {printer_name?:} diff --git a/templates/eu/choose-make.tmpl b/templates/eu/choose-make.tmpl index 4e61c1577..9fb389764 100644 --- a/templates/eu/choose-make.tmpl +++ b/templates/eu/choose-make.tmpl @@ -3,6 +3,7 @@

{op=modify-printer?Aldatu {printer_name}:Gehitu inprimagailua}

+ {printer_name?:} diff --git a/templates/eu/choose-model.tmpl b/templates/eu/choose-model.tmpl index d89fe8eab..5824932b7 100644 --- a/templates/eu/choose-model.tmpl +++ b/templates/eu/choose-model.tmpl @@ -3,6 +3,7 @@

{op=modify-printer?Aldatu {printer_name}:Gehitu inprimagailua}

+ {printer_name?:} diff --git a/templates/eu/choose-serial.tmpl b/templates/eu/choose-serial.tmpl index 1cea7c0b8..a4dbba2e5 100644 --- a/templates/eu/choose-serial.tmpl +++ b/templates/eu/choose-serial.tmpl @@ -3,6 +3,7 @@

{op=modify-printer?Aldatu {printer_name}:Gehitu inprimagailua}

+ {printer_name?:} diff --git a/templates/eu/choose-uri.tmpl b/templates/eu/choose-uri.tmpl index dfecf4f71..2c7d0f270 100644 --- a/templates/eu/choose-uri.tmpl +++ b/templates/eu/choose-uri.tmpl @@ -3,6 +3,7 @@

{op=modify-printer?Aldatu {printer_name}:Gehitu inprimagailua}

+ {printer_name?:} diff --git a/templates/eu/class-confirm.tmpl b/templates/eu/class-confirm.tmpl index 30e9be0c8..f4a1a6f40 100644 --- a/templates/eu/class-confirm.tmpl +++ b/templates/eu/class-confirm.tmpl @@ -4,6 +4,6 @@

Abisua: ziur zaude {printer_name} klasea ezabatu nahi duzula?

-

+

diff --git a/templates/eu/class.tmpl b/templates/eu/class.tmpl index d569f2049..17e8c2694 100644 --- a/templates/eu/class.tmpl +++ b/templates/eu/class.tmpl @@ -5,6 +5,7 @@ {default_name={printer_name}?, zerbitzariaren lehenetsiak:} partekatuta {server_is_sharing_printers=0?ez:{printer_is_shared=0?ez:}} daude)
+ diff --git a/templates/eu/job-move.tmpl b/templates/eu/job-move.tmpl index d1cb5e7f9..f337353b2 100644 --- a/templates/eu/job-move.tmpl +++ b/templates/eu/job-move.tmpl @@ -1,6 +1,7 @@
+ {job_id?:} diff --git a/templates/eu/jobs.tmpl b/templates/eu/jobs.tmpl index 9aabce2d2..3071f6d40 100644 --- a/templates/eu/jobs.tmpl +++ b/templates/eu/jobs.tmpl @@ -17,18 +17,18 @@ "{job_printer_state_message}":} {job_preserved>0?{job_state>5? - + :}:} {job_state=4? -
+
:} {job_state=3? -
+
:} {job_state<7? -
+
-
:} +
:}   } diff --git a/templates/eu/list-available-printers.tmpl b/templates/eu/list-available-printers.tmpl index 0431c8ac1..c8a397f3e 100644 --- a/templates/eu/list-available-printers.tmpl +++ b/templates/eu/list-available-printers.tmpl @@ -4,7 +4,7 @@ {#device_uri=0?

Ez da inprimagailurik aurkitu.

:
    {[device_uri] -
  • +
  • {device_make_and_model} ({device_info})
  • }
} diff --git a/templates/eu/modify-class.tmpl b/templates/eu/modify-class.tmpl index dfd1322ea..bce650341 100644 --- a/templates/eu/modify-class.tmpl +++ b/templates/eu/modify-class.tmpl @@ -3,6 +3,7 @@

Aldatu {printer_name} klasea

+ diff --git a/templates/eu/modify-printer.tmpl b/templates/eu/modify-printer.tmpl index 23f308b66..9b0417a54 100644 --- a/templates/eu/modify-printer.tmpl +++ b/templates/eu/modify-printer.tmpl @@ -3,6 +3,7 @@

Aldatu {printer_name}

+ diff --git a/templates/eu/printer-confirm.tmpl b/templates/eu/printer-confirm.tmpl index 29ff12bcc..d72d24010 100644 --- a/templates/eu/printer-confirm.tmpl +++ b/templates/eu/printer-confirm.tmpl @@ -4,6 +4,6 @@

Abisua: ziur zaude {printer_name} inprimagailua ezabatzea nahi duzula?

-

+

diff --git a/templates/eu/printer.tmpl b/templates/eu/printer.tmpl index e1ec7c7c9..ac984ebd0 100644 --- a/templates/eu/printer.tmpl +++ b/templates/eu/printer.tmpl @@ -6,6 +6,7 @@ {default_name={printer_name}?, Zerbitzariaren lehenetsia:} partekatuta {server_is_sharing_printers=0?ez:{printer_is_shared=0?ez:}} dago)
+

Esportatu inprimagailuak Samba-ra

diff --git a/templates/eu/set-printer-options-header.tmpl b/templates/eu/set-printer-options-header.tmpl index d84e91c2d..89b548b2f 100644 --- a/templates/eu/set-printer-options-header.tmpl +++ b/templates/eu/set-printer-options-header.tmpl @@ -3,6 +3,7 @@

Ezarri {printer_name}(r)en aukera lehenetsiak

+ {HAVE_AUTOCONFIGURE?:} diff --git a/templates/eu/users.tmpl b/templates/eu/users.tmpl index fb4ef638d..ba0ee968b 100644 --- a/templates/eu/users.tmpl +++ b/templates/eu/users.tmpl @@ -1,6 +1,7 @@
+ {IS_CLASS?:} diff --git a/templates/id/add-class.tmpl b/templates/id/add-class.tmpl index b64af5d6c..55f90ad2e 100644 --- a/templates/id/add-class.tmpl +++ b/templates/id/add-class.tmpl @@ -3,6 +3,7 @@

Tambah Kelas

+ diff --git a/templates/id/add-printer.tmpl b/templates/id/add-printer.tmpl index 92529565c..5c7c7ccdd 100644 --- a/templates/id/add-printer.tmpl +++ b/templates/id/add-printer.tmpl @@ -3,6 +3,7 @@

Add Printer

+ {?current_make!?:} {?current_make_and_model!?:} diff --git a/templates/id/add-rss-subscription.tmpl b/templates/id/add-rss-subscription.tmpl index ac9e3d403..3d5ae7d70 100644 --- a/templates/id/add-rss-subscription.tmpl +++ b/templates/id/add-rss-subscription.tmpl @@ -1,4 +1,5 @@ +

Tambah Subskripsi RSS

diff --git a/templates/id/admin.tmpl b/templates/id/admin.tmpl index d7ea6a623..9106d6518 100644 --- a/templates/id/admin.tmpl +++ b/templates/id/admin.tmpl @@ -4,16 +4,16 @@

Pencetak

- -
+
+
-{have_samba?
:} +{have_samba?
:}

Kelas

-
+

@@ -28,7 +28,7 @@

Server

-
+
@@ -38,6 +38,7 @@

{SETTINGS_ERROR}
: + {ADVANCEDSETTINGS?

Pengaturan Server\:

@@ -95,7 +96,7 @@

Subskripsi RSS

- +

@@ -104,6 +105,6 @@ {[notify_subscription_id] } + }
NamaKejadianNama Antrian
{notify_recipient_name}
-
 
{notify_events} {notify_printer_name?{notify_printer_name}:Semua Antrian}
{notify_events} {notify_printer_name?{notify_printer_name}:Semua Antrian}
:} diff --git a/templates/id/choose-device.tmpl b/templates/id/choose-device.tmpl index 6bd91bd14..8f812a5e4 100644 --- a/templates/id/choose-device.tmpl +++ b/templates/id/choose-device.tmpl @@ -6,6 +6,7 @@ ALT="Busy Indicator"> Mencari pencetak...

}
+ {printer_name?:} diff --git a/templates/id/choose-make.tmpl b/templates/id/choose-make.tmpl index 3362738de..d04338fcc 100644 --- a/templates/id/choose-make.tmpl +++ b/templates/id/choose-make.tmpl @@ -3,6 +3,7 @@

{op=modify-printer?Ubah {printer_name}:Tambah Pencetak}

+ {printer_name?:} diff --git a/templates/id/choose-model.tmpl b/templates/id/choose-model.tmpl index d294a3b25..c4cfdb9d0 100644 --- a/templates/id/choose-model.tmpl +++ b/templates/id/choose-model.tmpl @@ -3,6 +3,7 @@

{op=modify-printer?Modify {printer_name}:Tambah Pencetak}

+ {printer_name?:} diff --git a/templates/id/choose-serial.tmpl b/templates/id/choose-serial.tmpl index ceb291f8f..19de16c4f 100644 --- a/templates/id/choose-serial.tmpl +++ b/templates/id/choose-serial.tmpl @@ -3,6 +3,7 @@

{op=modify-printer?Modify {printer_name}:Tambah Pencetak}

+ {printer_name?:} diff --git a/templates/id/choose-uri.tmpl b/templates/id/choose-uri.tmpl index 57380f6c4..61dfdfe62 100644 --- a/templates/id/choose-uri.tmpl +++ b/templates/id/choose-uri.tmpl @@ -3,6 +3,7 @@

{op=modify-printer?Modify {printer_name}:Tambah Pencetak}

+ {printer_name?:} diff --git a/templates/id/class-confirm.tmpl b/templates/id/class-confirm.tmpl index 23bec54ff..3805b9177 100644 --- a/templates/id/class-confirm.tmpl +++ b/templates/id/class-confirm.tmpl @@ -5,6 +5,6 @@

Peringatan: Anda yakin untuk menghapus kelas {printer_name}?

-

+

diff --git a/templates/id/class.tmpl b/templates/id/class.tmpl index ab85b1f88..6cb78c99a 100644 --- a/templates/id/class.tmpl +++ b/templates/id/class.tmpl @@ -5,6 +5,7 @@ {server_is_sharing_printers=0?Jangan:{printer_is_shared=0?Jangan:}} Berbagi{default_name={printer_name}?, Server Baku:})
+ diff --git a/templates/id/job-move.tmpl b/templates/id/job-move.tmpl index 91fdbc421..9ec881a04 100644 --- a/templates/id/job-move.tmpl +++ b/templates/id/job-move.tmpl @@ -1,6 +1,7 @@
+ {job_id?:} diff --git a/templates/id/jobs.tmpl b/templates/id/jobs.tmpl index 5670d6d22..1cd13a0ec 100644 --- a/templates/id/jobs.tmpl +++ b/templates/id/jobs.tmpl @@ -17,18 +17,17 @@ "{job_printer_state_message}":} {job_preserved>0?{job_state>5? - -:}:} +
:}:} {job_state=4? -
+
:} {job_state=3? -
+
:} {job_state<7? -
+
-
:} +
:}   } diff --git a/templates/id/list-available-printers.tmpl b/templates/id/list-available-printers.tmpl index 3c8884c2b..f3ca39fd9 100644 --- a/templates/id/list-available-printers.tmpl +++ b/templates/id/list-available-printers.tmpl @@ -4,7 +4,7 @@ {#device_uri=0?

Tidak ada pencetak.

:
    {[device_uri] -
  • +
  • {device_make_and_model} ({device_info})
  • }
} diff --git a/templates/id/modify-class.tmpl b/templates/id/modify-class.tmpl index ad8f3113a..db2d65e26 100644 --- a/templates/id/modify-class.tmpl +++ b/templates/id/modify-class.tmpl @@ -3,6 +3,7 @@

Ubah Kelas {printer_name}

+ diff --git a/templates/id/modify-printer.tmpl b/templates/id/modify-printer.tmpl index ffe1203df..9bdb0c4f1 100644 --- a/templates/id/modify-printer.tmpl +++ b/templates/id/modify-printer.tmpl @@ -3,6 +3,7 @@

Ubah {printer_name}

+ diff --git a/templates/id/printer-confirm.tmpl b/templates/id/printer-confirm.tmpl index de668e741..e6d89d616 100644 --- a/templates/id/printer-confirm.tmpl +++ b/templates/id/printer-confirm.tmpl @@ -5,6 +5,6 @@

Peringatan: Anda yakin untuk menghapus {printer_name}?

-

+

diff --git a/templates/id/printer.tmpl b/templates/id/printer.tmpl index 68e0a3981..4c56b6761 100644 --- a/templates/id/printer.tmpl +++ b/templates/id/printer.tmpl @@ -6,6 +6,7 @@ {server_is_sharing_printers=0?Tidak:{printer_is_shared=0?Tidak:}} Berbagi{default_name={printer_name}?, Server Baku:})
+

Ekspor Pencetak ke Samba

diff --git a/templates/id/set-printer-options-header.tmpl b/templates/id/set-printer-options-header.tmpl index 12386dc29..017e2c475 100644 --- a/templates/id/set-printer-options-header.tmpl +++ b/templates/id/set-printer-options-header.tmpl @@ -3,6 +3,7 @@

Atur Opsi Baku untuk {printer_name}

+ {HAVE_AUTOCONFIGURE?:} diff --git a/templates/id/users.tmpl b/templates/id/users.tmpl index 3795d694a..fe9107050 100644 --- a/templates/id/users.tmpl +++ b/templates/id/users.tmpl @@ -1,6 +1,7 @@
+ {IS_CLASS?:} diff --git a/templates/it/add-class.tmpl b/templates/it/add-class.tmpl index 91130b02a..cff0d45bc 100644 --- a/templates/it/add-class.tmpl +++ b/templates/it/add-class.tmpl @@ -3,6 +3,7 @@

Aggiungi classe

+ diff --git a/templates/it/add-printer.tmpl b/templates/it/add-printer.tmpl index bfd208020..3bf0906fa 100644 --- a/templates/it/add-printer.tmpl +++ b/templates/it/add-printer.tmpl @@ -3,6 +3,7 @@

Aggiungi stampante

+ {?current_make!?:} {?current_make_and_model!?:} diff --git a/templates/it/add-rss-subscription.tmpl b/templates/it/add-rss-subscription.tmpl index 69f658b15..ba33c14fd 100644 --- a/templates/it/add-rss-subscription.tmpl +++ b/templates/it/add-rss-subscription.tmpl @@ -1,4 +1,5 @@ +

Aggiungi iscrizione RSS

diff --git a/templates/it/admin.tmpl b/templates/it/admin.tmpl index 5ffa0019d..355c51fcc 100644 --- a/templates/it/admin.tmpl +++ b/templates/it/admin.tmpl @@ -4,16 +4,16 @@

Stampanti

- -
+
+
-{have_samba?
:} +{have_samba?
:}

Classi

-
+

@@ -28,7 +28,7 @@

Server

-
+
@@ -38,6 +38,7 @@

{SETTINGS_ERROR}
: + {ADVANCEDSETTINGS?

Impostazioni del server\:

@@ -95,7 +96,7 @@

Iscrizioni RSS

- +

@@ -104,6 +105,6 @@ {[notify_subscription_id] } + }
NomeEventiNome coda
{notify_recipient_name}
-
 
{notify_events} {notify_printer_name?{notify_printer_name}:Tutte le code}
{notify_events} {notify_printer_name?{notify_printer_name}:Tutte le code}
:} diff --git a/templates/it/choose-device.tmpl b/templates/it/choose-device.tmpl index f02a680fb..3420fdfe1 100644 --- a/templates/it/choose-device.tmpl +++ b/templates/it/choose-device.tmpl @@ -6,6 +6,7 @@ ALT="Busy Indicator"> Ricerca stampanti...

}
+ {printer_name?:} diff --git a/templates/it/choose-make.tmpl b/templates/it/choose-make.tmpl index 12c596176..3bb4c78c4 100644 --- a/templates/it/choose-make.tmpl +++ b/templates/it/choose-make.tmpl @@ -3,6 +3,7 @@

{op=modify-printer?Modify {printer_name}:Aggiungi stampante}

+ {printer_name?:} diff --git a/templates/it/choose-model.tmpl b/templates/it/choose-model.tmpl index aa9e0efea..d7e935769 100644 --- a/templates/it/choose-model.tmpl +++ b/templates/it/choose-model.tmpl @@ -3,6 +3,7 @@

{op=modify-printer?Modify {printer_name}:Aggiungi stampante}

+ {printer_name?:} diff --git a/templates/it/choose-serial.tmpl b/templates/it/choose-serial.tmpl index a17eb0574..106393adb 100644 --- a/templates/it/choose-serial.tmpl +++ b/templates/it/choose-serial.tmpl @@ -3,6 +3,7 @@

{op=modify-printer?Modifica {printer_name}:Aggiungi stampante}

+ {printer_name?:} diff --git a/templates/it/choose-uri.tmpl b/templates/it/choose-uri.tmpl index fe4f8c325..8a4b68584 100644 --- a/templates/it/choose-uri.tmpl +++ b/templates/it/choose-uri.tmpl @@ -3,6 +3,7 @@

{op=modify-printer?Modifica {printer_name}:Aggiungi stampante}

+ {printer_name?:} diff --git a/templates/it/class-confirm.tmpl b/templates/it/class-confirm.tmpl index f05657f13..4e99f4574 100644 --- a/templates/it/class-confirm.tmpl +++ b/templates/it/class-confirm.tmpl @@ -5,6 +5,6 @@

Warning: Sei sicuro di voler eliminare la classe {printer_name}?

-

+

diff --git a/templates/it/class.tmpl b/templates/it/class.tmpl index fd5b3e83b..06a768acf 100644 --- a/templates/it/class.tmpl +++ b/templates/it/class.tmpl @@ -5,6 +5,7 @@ {server_is_sharing_printers=0?Not:{printer_is_shared=0?Not:}} Shared{default_name={printer_name}?, Server Default:})
+ diff --git a/templates/it/job-move.tmpl b/templates/it/job-move.tmpl index 2ddc44a90..0a52ba2f2 100644 --- a/templates/it/job-move.tmpl +++ b/templates/it/job-move.tmpl @@ -1,6 +1,7 @@
+ {job_id?:} diff --git a/templates/it/jobs.tmpl b/templates/it/jobs.tmpl index 4c0ac244d..494c1eebd 100644 --- a/templates/it/jobs.tmpl +++ b/templates/it/jobs.tmpl @@ -17,18 +17,18 @@ "{job_printer_state_message}":} {job_preserved>0?{job_state>5? - + :}:} {job_state=4? -
+
:} {job_state=3? -
+
:} {job_state<7? -
+
-
:} +
:}   } diff --git a/templates/it/list-available-printers.tmpl b/templates/it/list-available-printers.tmpl index 3245f5909..147d6103c 100644 --- a/templates/it/list-available-printers.tmpl +++ b/templates/it/list-available-printers.tmpl @@ -4,7 +4,7 @@ {#device_uri=0?

Nessuna stampante trovata.

:
    {[device_uri] -
  • +
  • {device_make_and_model} ({device_info})
  • }
} diff --git a/templates/it/modify-class.tmpl b/templates/it/modify-class.tmpl index f62169545..065f2b91a 100644 --- a/templates/it/modify-class.tmpl +++ b/templates/it/modify-class.tmpl @@ -3,6 +3,7 @@

Modifica classe {printer_name}

+ diff --git a/templates/it/modify-printer.tmpl b/templates/it/modify-printer.tmpl index 4d1c97b7f..a6303f298 100644 --- a/templates/it/modify-printer.tmpl +++ b/templates/it/modify-printer.tmpl @@ -3,6 +3,7 @@

Modifica {printer_name}

+ diff --git a/templates/it/printer-confirm.tmpl b/templates/it/printer-confirm.tmpl index b9c009d80..e23071c9f 100644 --- a/templates/it/printer-confirm.tmpl +++ b/templates/it/printer-confirm.tmpl @@ -5,6 +5,6 @@

Avviso: Sei sicuro di voler eliminare la stampante {printer_name}?

-

+

diff --git a/templates/it/printer.tmpl b/templates/it/printer.tmpl index b7a38278e..78fc08bea 100644 --- a/templates/it/printer.tmpl +++ b/templates/it/printer.tmpl @@ -6,6 +6,7 @@ {server_is_sharing_printers=0?Not:{printer_is_shared=0?Not:}} Shared{default_name={printer_name}?, Server Default:})
+

Esporta stampanti a Samba

diff --git a/templates/it/set-printer-options-header.tmpl b/templates/it/set-printer-options-header.tmpl index 735341c16..b0867cedb 100644 --- a/templates/it/set-printer-options-header.tmpl +++ b/templates/it/set-printer-options-header.tmpl @@ -3,6 +3,7 @@

Imposta opzioni predefinite per {printer_name}

+ {HAVE_AUTOCONFIGURE?:} diff --git a/templates/it/users.tmpl b/templates/it/users.tmpl index f547e414a..34d8adb10 100644 --- a/templates/it/users.tmpl +++ b/templates/it/users.tmpl @@ -1,6 +1,7 @@
+ {IS_CLASS?:} diff --git a/templates/ja/add-class.tmpl b/templates/ja/add-class.tmpl index b40954fa4..11108ccfe 100644 --- a/templates/ja/add-class.tmpl +++ b/templates/ja/add-class.tmpl @@ -3,6 +3,7 @@

クラスの追加

+ diff --git a/templates/ja/add-printer.tmpl b/templates/ja/add-printer.tmpl index c98424679..f054254aa 100644 --- a/templates/ja/add-printer.tmpl +++ b/templates/ja/add-printer.tmpl @@ -3,6 +3,7 @@

新しいプリンターの追加

+ diff --git a/templates/ja/add-rss-subscription.tmpl b/templates/ja/add-rss-subscription.tmpl index a2ba7538b..70203c1f9 100644 --- a/templates/ja/add-rss-subscription.tmpl +++ b/templates/ja/add-rss-subscription.tmpl @@ -1,4 +1,5 @@ +

RSS 購読を追加

diff --git a/templates/ja/admin.tmpl b/templates/ja/admin.tmpl index f2904cb44..e1e022951 100644 --- a/templates/ja/admin.tmpl +++ b/templates/ja/admin.tmpl @@ -4,16 +4,16 @@

プリンター

- -
+
+
-{have_samba?
:} +{have_samba?
:}

クラス

-
+

@@ -28,7 +28,7 @@

サーバー

-
+
@@ -38,6 +38,7 @@

{SETTINGS_ERROR}
: + {ADVANCEDSETTINGS?

サーバー設定\:

@@ -95,7 +96,7 @@

RSS 購読

- +

@@ -104,6 +105,6 @@ {[notify_subscription_id] } + }
名前イベントキュー名
{notify_recipient_name}
-
 
{notify_events} {notify_printer_name?{notify_printer_name}:すべてのキュー}
{notify_events} {notify_printer_name?{notify_printer_name}:すべてのキュー}
:} diff --git a/templates/ja/choose-device.tmpl b/templates/ja/choose-device.tmpl index a4a8efa51..05700c3c7 100644 --- a/templates/ja/choose-device.tmpl +++ b/templates/ja/choose-device.tmpl @@ -6,6 +6,7 @@ ALT="Busy Indicator"> プリンターを探しています...

}
+ {printer_name?:} diff --git a/templates/ja/choose-make.tmpl b/templates/ja/choose-make.tmpl index 0a1eb79bc..c800d9818 100644 --- a/templates/ja/choose-make.tmpl +++ b/templates/ja/choose-make.tmpl @@ -3,6 +3,7 @@

{op=modify-printer?{printer_name}の変更:プリンターの追加}

+ {printer_name?:} diff --git a/templates/ja/choose-model.tmpl b/templates/ja/choose-model.tmpl index 90d5cf45b..20011b4d5 100644 --- a/templates/ja/choose-model.tmpl +++ b/templates/ja/choose-model.tmpl @@ -3,6 +3,7 @@

{op=modify-printer?{printer_name}の追加:プリンターの追加}

+ {printer_name?:} diff --git a/templates/ja/choose-serial.tmpl b/templates/ja/choose-serial.tmpl index c8c4542f4..924b84a74 100644 --- a/templates/ja/choose-serial.tmpl +++ b/templates/ja/choose-serial.tmpl @@ -3,6 +3,7 @@

{op=modify-printer?{printer_name}の変更:プリンターの追加}

+ {printer_name?:} diff --git a/templates/ja/choose-uri.tmpl b/templates/ja/choose-uri.tmpl index 893da3ec1..bc8c0bc03 100644 --- a/templates/ja/choose-uri.tmpl +++ b/templates/ja/choose-uri.tmpl @@ -3,6 +3,7 @@

{op=modify-printer?{printer_name}の変更:プリンターの追加}

+ {printer_name?:} diff --git a/templates/ja/class-confirm.tmpl b/templates/ja/class-confirm.tmpl index 20ff73f38..e50b6a90a 100644 --- a/templates/ja/class-confirm.tmpl +++ b/templates/ja/class-confirm.tmpl @@ -5,6 +5,6 @@

警告: 本当にクラス {printer_name} を削除しても良いですか?

-

+

diff --git a/templates/ja/class.tmpl b/templates/ja/class.tmpl index 82b753d32..2ee45eea1 100644 --- a/templates/ja/class.tmpl +++ b/templates/ja/class.tmpl @@ -5,6 +5,7 @@ {server_is_sharing_printers=0?非:{printer_is_shared=0?非:}}共有{default_name={printer_name}?, デフォルトプリンター:})
+ diff --git a/templates/ja/job-move.tmpl b/templates/ja/job-move.tmpl index 2acd2c51f..54da7e038 100644 --- a/templates/ja/job-move.tmpl +++ b/templates/ja/job-move.tmpl @@ -1,6 +1,7 @@
+ {job_id?:} diff --git a/templates/ja/jobs.tmpl b/templates/ja/jobs.tmpl index e0d917c25..bff543aea 100644 --- a/templates/ja/jobs.tmpl +++ b/templates/ja/jobs.tmpl @@ -17,18 +17,18 @@ "{job_printer_state_message}":} {job_preserved>0?{job_state>5? - + :}:} {job_state=4? -
+
:} {job_state=3? -
+
:} {job_state<7? -
+
-
:} +
:}   } diff --git a/templates/ja/list-available-printers.tmpl b/templates/ja/list-available-printers.tmpl index 554270ad6..f70b5aac0 100644 --- a/templates/ja/list-available-printers.tmpl +++ b/templates/ja/list-available-printers.tmpl @@ -4,7 +4,7 @@ {#device_uri=0?

プリンターが見つかりません。

:
    {[device_uri] -
  • +
  • {device_make_and_model} ({device_info})
  • }
} diff --git a/templates/ja/modify-class.tmpl b/templates/ja/modify-class.tmpl index c5fe07d5e..a41010f3f 100644 --- a/templates/ja/modify-class.tmpl +++ b/templates/ja/modify-class.tmpl @@ -3,6 +3,7 @@

クラス {printer_name} の変更

+ diff --git a/templates/ja/modify-printer.tmpl b/templates/ja/modify-printer.tmpl index ff14b400b..d8ef5f04b 100644 --- a/templates/ja/modify-printer.tmpl +++ b/templates/ja/modify-printer.tmpl @@ -3,6 +3,7 @@

プリンター {printer_name} の変更

+ diff --git a/templates/ja/printer-confirm.tmpl b/templates/ja/printer-confirm.tmpl index e6430b2cb..6fdb52cab 100644 --- a/templates/ja/printer-confirm.tmpl +++ b/templates/ja/printer-confirm.tmpl @@ -4,6 +4,6 @@

警告: 本当にプリンター {printer_name} を削除してよいですか?

-

+

diff --git a/templates/ja/printer.tmpl b/templates/ja/printer.tmpl index 209abaa3c..fbd9c5ad0 100644 --- a/templates/ja/printer.tmpl +++ b/templates/ja/printer.tmpl @@ -6,6 +6,7 @@ {server_is_sharing_printers=0?非:{printer_is_shared=0?非:}}共有{default_name={printer_name}?, デフォルトプリンター:})
+

プリンターを Samba にエクスポート

diff --git a/templates/ja/set-printer-options-header.tmpl b/templates/ja/set-printer-options-header.tmpl index dd8746104..b5896f071 100644 --- a/templates/ja/set-printer-options-header.tmpl +++ b/templates/ja/set-printer-options-header.tmpl @@ -3,6 +3,7 @@

{printer_name} のデフォルトオプション変更

+ {HAVE_AUTOCONFIGURE?:} diff --git a/templates/ja/users.tmpl b/templates/ja/users.tmpl index 8097cdc7a..b998c6b2b 100644 --- a/templates/ja/users.tmpl +++ b/templates/ja/users.tmpl @@ -1,6 +1,7 @@
+ {IS_CLASS?:} diff --git a/templates/job-move.tmpl b/templates/job-move.tmpl index 96b309006..6ef0ff12e 100644 --- a/templates/job-move.tmpl +++ b/templates/job-move.tmpl @@ -1,6 +1,7 @@
+ {job_id?:} diff --git a/templates/jobs.tmpl b/templates/jobs.tmpl index 9e77556bf..9c56b3f94 100644 --- a/templates/jobs.tmpl +++ b/templates/jobs.tmpl @@ -17,18 +17,17 @@ "{job_printer_state_message}":} {job_preserved>0?{job_state>5? - -:}:} +
:}:} {job_state=4? -
+
:} {job_state=3? -
+
:} {job_state<7? -
+
-
:} +
:}   } diff --git a/templates/list-available-printers.tmpl b/templates/list-available-printers.tmpl index 8b325fdac..a594439ee 100644 --- a/templates/list-available-printers.tmpl +++ b/templates/list-available-printers.tmpl @@ -4,7 +4,7 @@ {#device_uri=0?

No printers found.

:
    {[device_uri] -
  • +
  • {device_make_and_model} ({device_info})
  • }
} diff --git a/templates/modify-class.tmpl b/templates/modify-class.tmpl index 6d2655463..31f7b9ce3 100644 --- a/templates/modify-class.tmpl +++ b/templates/modify-class.tmpl @@ -3,6 +3,7 @@

Modify Class {printer_name}

+ diff --git a/templates/modify-printer.tmpl b/templates/modify-printer.tmpl index f0a8ea874..bdf3df604 100644 --- a/templates/modify-printer.tmpl +++ b/templates/modify-printer.tmpl @@ -3,6 +3,7 @@

Modify {printer_name}

+ diff --git a/templates/pl/add-class.tmpl b/templates/pl/add-class.tmpl index af5c69ff1..d1f4b66bf 100644 --- a/templates/pl/add-class.tmpl +++ b/templates/pl/add-class.tmpl @@ -3,6 +3,7 @@

Dodawanie klasy

+ diff --git a/templates/pl/add-printer.tmpl b/templates/pl/add-printer.tmpl index 9fa76ca62..45b50a0d4 100644 --- a/templates/pl/add-printer.tmpl +++ b/templates/pl/add-printer.tmpl @@ -3,6 +3,7 @@

Dodawanie drukarki

+ diff --git a/templates/pl/add-rss-subscription.tmpl b/templates/pl/add-rss-subscription.tmpl index 0523454b6..bff170705 100644 --- a/templates/pl/add-rss-subscription.tmpl +++ b/templates/pl/add-rss-subscription.tmpl @@ -1,4 +1,5 @@ +

Dodawanie subskrypcji RSS

diff --git a/templates/pl/admin.tmpl b/templates/pl/admin.tmpl index 387f05360..16840361f 100644 --- a/templates/pl/admin.tmpl +++ b/templates/pl/admin.tmpl @@ -4,16 +4,16 @@

Drukarki

- -
+
+
-{have_samba?
:} +{have_samba?
:}

Klasy

-
+

@@ -28,7 +28,7 @@

Serwery

-
+
@@ -38,6 +38,7 @@

{SETTINGS_ERROR}
: + {ADVANCEDSETTINGS?

Ustawienia serwera\:

@@ -95,7 +96,7 @@

Subskrypcje RSS

- +

@@ -104,6 +105,6 @@ {[notify_subscription_id] } + }
NameZdarzeniaNazwa kolejki
{notify_recipient_name}
-
 
{notify_events} {notify_printer_name?{notify_printer_name}:Wszystkie kolejki}
{notify_events} {notify_printer_name?{notify_printer_name}:Wszystkie kolejki}
:} diff --git a/templates/pl/choose-device.tmpl b/templates/pl/choose-device.tmpl index 7fc06ded4..445745624 100644 --- a/templates/pl/choose-device.tmpl +++ b/templates/pl/choose-device.tmpl @@ -6,6 +6,7 @@ ALT="Busy Indicator"> Wyszukiwanie drukarek...

}
+ {printer_name?:} diff --git a/templates/pl/choose-make.tmpl b/templates/pl/choose-make.tmpl index d632619d0..c0ec622a7 100644 --- a/templates/pl/choose-make.tmpl +++ b/templates/pl/choose-make.tmpl @@ -3,6 +3,7 @@

{op=modify-printer?Modify {printer_name}:Dodawanie drukarki}

+ {printer_name?:} diff --git a/templates/pl/choose-model.tmpl b/templates/pl/choose-model.tmpl index 6a7cbb672..9438cee56 100644 --- a/templates/pl/choose-model.tmpl +++ b/templates/pl/choose-model.tmpl @@ -3,6 +3,7 @@

{op=modify-printer?Modyfikowanie {printer_name}:Dodawanie drukarki}

+ {printer_name?:} diff --git a/templates/pl/choose-serial.tmpl b/templates/pl/choose-serial.tmpl index 5c42b2434..8bbf8c8c2 100644 --- a/templates/pl/choose-serial.tmpl +++ b/templates/pl/choose-serial.tmpl @@ -3,6 +3,7 @@

{op=modify-printer?Modyfikowanie {printer_name}:Dodawanie drukarki}

+ {printer_name?:} diff --git a/templates/pl/choose-uri.tmpl b/templates/pl/choose-uri.tmpl index 5c87dbbb2..8d06e103a 100644 --- a/templates/pl/choose-uri.tmpl +++ b/templates/pl/choose-uri.tmpl @@ -3,6 +3,7 @@

{op=modify-printer?Modyfikowanie {printer_name}:Dodawanie drukarki}

+ {printer_name?:} diff --git a/templates/pl/class-confirm.tmpl b/templates/pl/class-confirm.tmpl index 7c38b894b..55cb5ed4e 100644 --- a/templates/pl/class-confirm.tmpl +++ b/templates/pl/class-confirm.tmpl @@ -5,6 +5,6 @@

Ostrzeżenie: Usunąć klasę {printer_name}?

-

+

diff --git a/templates/pl/class.tmpl b/templates/pl/class.tmpl index 9ba9ff431..6d83981d0 100644 --- a/templates/pl/class.tmpl +++ b/templates/pl/class.tmpl @@ -5,6 +5,7 @@ {server_is_sharing_printers=0?Nie:{printer_is_shared=0?Nie:}} Współdzielona{default_name={printer_name}?, Domyślne serwera:})
+ diff --git a/templates/pl/job-move.tmpl b/templates/pl/job-move.tmpl index 666a1509a..bd77beeb2 100644 --- a/templates/pl/job-move.tmpl +++ b/templates/pl/job-move.tmpl @@ -1,6 +1,7 @@
+ {job_id?:} diff --git a/templates/pl/jobs.tmpl b/templates/pl/jobs.tmpl index dbb7fd9bb..665bdffbd 100644 --- a/templates/pl/jobs.tmpl +++ b/templates/pl/jobs.tmpl @@ -17,18 +17,18 @@ "{job_printer_state_message}":} {job_preserved>0?{job_state>5? - + :}:} {job_state=4? -
+
:} {job_state=3? -
+
:} {job_state<7? -
+
-
:} +
:}   } diff --git a/templates/pl/list-available-printers.tmpl b/templates/pl/list-available-printers.tmpl index d5ba1aa13..aad6a49fa 100644 --- a/templates/pl/list-available-printers.tmpl +++ b/templates/pl/list-available-printers.tmpl @@ -4,7 +4,7 @@ {#device_uri=0?

Nie znaleziono drukarek.

:
    {[device_uri] -
  • +
  • {device_make_and_model} ({device_info})
  • }
} diff --git a/templates/pl/modify-class.tmpl b/templates/pl/modify-class.tmpl index 483cd0603..b8a213076 100644 --- a/templates/pl/modify-class.tmpl +++ b/templates/pl/modify-class.tmpl @@ -3,6 +3,7 @@

Modyfikowanie klasy {printer_name}

+ diff --git a/templates/pl/modify-printer.tmpl b/templates/pl/modify-printer.tmpl index 30b2c14ec..a63f4781c 100644 --- a/templates/pl/modify-printer.tmpl +++ b/templates/pl/modify-printer.tmpl @@ -3,6 +3,7 @@

Modyfikowanie {printer_name}

+ diff --git a/templates/pl/printer-confirm.tmpl b/templates/pl/printer-confirm.tmpl index 2e9ab7e41..73f860128 100644 --- a/templates/pl/printer-confirm.tmpl +++ b/templates/pl/printer-confirm.tmpl @@ -5,6 +5,6 @@

Ostrzeżenie: usunąć drukarkę {printer_name}?

-

+

diff --git a/templates/pl/printer.tmpl b/templates/pl/printer.tmpl index 43d18ef2d..c62b857a0 100644 --- a/templates/pl/printer.tmpl +++ b/templates/pl/printer.tmpl @@ -6,6 +6,7 @@ {server_is_sharing_printers=0?Nie:{printer_is_shared=0?Nie:}} Współdzielona{default_name={printer_name}?, Domyślne serwera:})
+

Eksportowanie drukarek do Samby

diff --git a/templates/pl/set-printer-options-header.tmpl b/templates/pl/set-printer-options-header.tmpl index 206a5bbe7..d128d7d50 100644 --- a/templates/pl/set-printer-options-header.tmpl +++ b/templates/pl/set-printer-options-header.tmpl @@ -3,6 +3,7 @@

Ustawianie domyślnych opcji dla {printer_name}

+ {HAVE_AUTOCONFIGURE?:} diff --git a/templates/pl/users.tmpl b/templates/pl/users.tmpl index 7907c7abb..5cb754952 100644 --- a/templates/pl/users.tmpl +++ b/templates/pl/users.tmpl @@ -1,6 +1,7 @@
+ {IS_CLASS?:} diff --git a/templates/printer-confirm.tmpl b/templates/printer-confirm.tmpl index db16d691b..fce9e3494 100644 --- a/templates/printer-confirm.tmpl +++ b/templates/printer-confirm.tmpl @@ -5,6 +5,6 @@

Warning: Are you sure you want to delete printer {printer_name}?

-

+

diff --git a/templates/printer.tmpl b/templates/printer.tmpl index b7a38278e..78fc08bea 100644 --- a/templates/printer.tmpl +++ b/templates/printer.tmpl @@ -6,6 +6,7 @@ {server_is_sharing_printers=0?Not:{printer_is_shared=0?Not:}} Shared{default_name={printer_name}?, Server Default:})
+ diff --git a/templates/ru/add-printer.tmpl b/templates/ru/add-printer.tmpl index 59d6e2193..2d040189c 100644 --- a/templates/ru/add-printer.tmpl +++ b/templates/ru/add-printer.tmpl @@ -3,6 +3,7 @@

Добавление принтера

+ diff --git a/templates/ru/add-rss-subscription.tmpl b/templates/ru/add-rss-subscription.tmpl index 90e2c80ec..4c9925fb7 100644 --- a/templates/ru/add-rss-subscription.tmpl +++ b/templates/ru/add-rss-subscription.tmpl @@ -1,4 +1,5 @@ +

Добавление подписки по RSS

diff --git a/templates/ru/admin.tmpl b/templates/ru/admin.tmpl index 9362f428c..22d9de064 100644 --- a/templates/ru/admin.tmpl +++ b/templates/ru/admin.tmpl @@ -4,16 +4,16 @@

Принтеры

- -
+
+
-{have_samba?
:} +{have_samba?
:}

Группы

-
+

@@ -28,7 +28,7 @@

Сервер

-
+
@@ -38,6 +38,7 @@

{SETTINGS_ERROR}
: + {ADVANCEDSETTINGS?

Параметры сервера\:

@@ -95,7 +96,7 @@

Подписка по RSS

- +

@@ -104,6 +105,6 @@ {[notify_subscription_id] } + }
НазваниеСобытияОчередь
{notify_recipient_name}
-
 
{notify_events} {notify_printer_name?{notify_printer_name}:Все очереди}
{notify_events} {notify_printer_name?{notify_printer_name}:Все очереди}
:} diff --git a/templates/ru/choose-device.tmpl b/templates/ru/choose-device.tmpl index 0aee24f1d..3df36db86 100644 --- a/templates/ru/choose-device.tmpl +++ b/templates/ru/choose-device.tmpl @@ -6,6 +6,7 @@ ALT="Busy Indicator"> Поиск принтеров...

}
+ {printer_name?:} diff --git a/templates/ru/choose-make.tmpl b/templates/ru/choose-make.tmpl index d400356f0..a87d6bf27 100644 --- a/templates/ru/choose-make.tmpl +++ b/templates/ru/choose-make.tmpl @@ -3,6 +3,7 @@

{op=modify-printer?Изменение {printer_name}:Добавление принтера}

+ {printer_name?:} diff --git a/templates/ru/choose-model.tmpl b/templates/ru/choose-model.tmpl index a6e2e0ef6..9d434f1c3 100644 --- a/templates/ru/choose-model.tmpl +++ b/templates/ru/choose-model.tmpl @@ -3,6 +3,7 @@

{op=modify-printer?Изменение {printer_name}:Добавление принтера}

+ {printer_name?:} diff --git a/templates/ru/choose-serial.tmpl b/templates/ru/choose-serial.tmpl index cba02600a..21e4bf87f 100644 --- a/templates/ru/choose-serial.tmpl +++ b/templates/ru/choose-serial.tmpl @@ -3,6 +3,7 @@

{op=modify-printer?Изменение {printer_name}:Добавление принтера}

+ {printer_name?:} diff --git a/templates/ru/choose-uri.tmpl b/templates/ru/choose-uri.tmpl index 3672f4428..812f2db88 100644 --- a/templates/ru/choose-uri.tmpl +++ b/templates/ru/choose-uri.tmpl @@ -3,6 +3,7 @@

{op=modify-printer?Изменение {printer_name}:Добавление принтера}

+ {printer_name?:} diff --git a/templates/ru/class-confirm.tmpl b/templates/ru/class-confirm.tmpl index c4337ecdc..5bef5bf07 100644 --- a/templates/ru/class-confirm.tmpl +++ b/templates/ru/class-confirm.tmpl @@ -5,6 +5,6 @@

Предупреждение: вы действительно хотите удалить группу «{printer_name}»?

-

+

diff --git a/templates/ru/class.tmpl b/templates/ru/class.tmpl index 36e674a68..d486b43e2 100644 --- a/templates/ru/class.tmpl +++ b/templates/ru/class.tmpl @@ -5,6 +5,7 @@ {server_is_sharing_printers=0?нет совместного доступа:{printer_is_shared=0?нет совместного доступа:разрешен совместный доступ}})
+ diff --git a/templates/ru/job-move.tmpl b/templates/ru/job-move.tmpl index 69bfdeb5a..598e4db74 100644 --- a/templates/ru/job-move.tmpl +++ b/templates/ru/job-move.tmpl @@ -1,6 +1,7 @@
+ {job_id?:} diff --git a/templates/ru/jobs.tmpl b/templates/ru/jobs.tmpl index a94b1429f..c2226f67e 100644 --- a/templates/ru/jobs.tmpl +++ b/templates/ru/jobs.tmpl @@ -17,18 +17,18 @@ "{job_printer_state_message}":} {job_preserved>0?{job_state>5? - + :}:} {job_state=4? -
+
:} {job_state=3? -
+
:} {job_state<7? -
+
-
:} +
:}   } diff --git a/templates/ru/list-available-printers.tmpl b/templates/ru/list-available-printers.tmpl index 72b6d445a..161562845 100644 --- a/templates/ru/list-available-printers.tmpl +++ b/templates/ru/list-available-printers.tmpl @@ -4,7 +4,7 @@ {#device_uri=0?

Не обнаружено ни одного принтера.

:
    {[device_uri] -
  • +
  • {device_make_and_model} ({device_info})
  • }
} diff --git a/templates/ru/modify-class.tmpl b/templates/ru/modify-class.tmpl index d596c9b3f..a85698a52 100644 --- a/templates/ru/modify-class.tmpl +++ b/templates/ru/modify-class.tmpl @@ -3,6 +3,7 @@

Изменение группы {printer_name}

+ diff --git a/templates/ru/modify-printer.tmpl b/templates/ru/modify-printer.tmpl index 74ea27c3b..6277b5d6f 100644 --- a/templates/ru/modify-printer.tmpl +++ b/templates/ru/modify-printer.tmpl @@ -3,6 +3,7 @@

Изменение принтера {printer_name}

+ diff --git a/templates/ru/printer-confirm.tmpl b/templates/ru/printer-confirm.tmpl index 6776a5742..c57356d07 100644 --- a/templates/ru/printer-confirm.tmpl +++ b/templates/ru/printer-confirm.tmpl @@ -5,6 +5,6 @@

Предупреждение: вы действительно хотите удалить принтер «{printer_name}»?

-

+

diff --git a/templates/ru/printer.tmpl b/templates/ru/printer.tmpl index da4a0898d..5128d004c 100644 --- a/templates/ru/printer.tmpl +++ b/templates/ru/printer.tmpl @@ -6,6 +6,7 @@ {server_is_sharing_printers=0?нет совместного доступа:{printer_is_shared=0?нет совместного доступа:разрешен совместный доступ}})
+

Экспорт принтеров в Samba

diff --git a/templates/ru/set-printer-options-header.tmpl b/templates/ru/set-printer-options-header.tmpl index a250a9f52..e5c79dd44 100644 --- a/templates/ru/set-printer-options-header.tmpl +++ b/templates/ru/set-printer-options-header.tmpl @@ -3,6 +3,7 @@

Установить параметры по умолчанию для {printer_name}

+ {HAVE_AUTOCONFIGURE?:} diff --git a/templates/ru/users.tmpl b/templates/ru/users.tmpl index 12672a250..c5b357501 100644 --- a/templates/ru/users.tmpl +++ b/templates/ru/users.tmpl @@ -1,6 +1,7 @@
+ {IS_CLASS?:} diff --git a/templates/samba-export.tmpl b/templates/samba-export.tmpl index 92a291f1e..6515a4d3a 100644 --- a/templates/samba-export.tmpl +++ b/templates/samba-export.tmpl @@ -10,6 +10,7 @@ function select_printers() { --> +

Export Printers to Samba

diff --git a/templates/set-printer-options-header.tmpl b/templates/set-printer-options-header.tmpl index 462bccf20..3e7db4669 100644 --- a/templates/set-printer-options-header.tmpl +++ b/templates/set-printer-options-header.tmpl @@ -3,6 +3,7 @@

Set Default Options for {printer_name}

+ {HAVE_AUTOCONFIGURE?:} diff --git a/templates/users.tmpl b/templates/users.tmpl index 5f9f71f8d..0889f3f31 100644 --- a/templates/users.tmpl +++ b/templates/users.tmpl @@ -1,6 +1,7 @@
+ {IS_CLASS?:} diff --git a/test/Dependencies b/test/Dependencies index a395277e9..266f7f2fe 100644 --- a/test/Dependencies +++ b/test/Dependencies @@ -1,6 +1,7 @@ # DO NOT DELETE THIS LINE -- make depend depends on it. -ipptest.o: ../cups/string.h ../config.h ../cups/cups.h ../cups/ipp.h -ipptest.o: ../cups/http.h ../cups/versioning.h ../cups/ppd.h ../cups/array.h -ipptest.o: ../cups/file.h ../cups/language.h ../cups/language.h -ipptest.o: ../cups/http-private.h ../cups/md5.h ../cups/ipp-private.h +ipptest.o: ../cups/globals.h ../cups/string.h ../config.h +ipptest.o: ../cups/http-private.h ../cups/http.h ../cups/versioning.h +ipptest.o: ../cups/md5.h ../cups/ipp-private.h ../cups/ipp.h ../cups/cups.h +ipptest.o: ../cups/ppd.h ../cups/array.h ../cups/file.h ../cups/language.h +ipptest.o: ../cups/i18n.h ../cups/transcode.h diff --git a/test/Makefile b/test/Makefile index dfb008801..60d72fcd5 100644 --- a/test/Makefile +++ b/test/Makefile @@ -1,9 +1,9 @@ # # "$Id: Makefile 7871 2008-08-27 21:12:43Z mike $" # -# IPP test makefile for the Common UNIX Printing System (CUPS). +# IPP test makefile for CUPS. # -# Copyright 2007-2009 by Apple Inc. +# 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 @@ -16,11 +16,25 @@ include ../Makedefs +# +# Sample test files. +# + +TESTFILES = \ + ipp-1.1.test \ + ipp-2.0.test \ + ipp-2.1.test \ + testfile.jpg \ + testfile.pdf \ + testfile.ps \ + testfile.txt + + # # Make all targets... # -all: ipptest +all: ipptest ipptest-static # @@ -42,7 +56,7 @@ unittests: # clean: - $(RM) ipptest ipptest.o + $(RM) ipptest ipptest.o ipptest-static # @@ -65,6 +79,11 @@ install: all install-data install-headers install-libs install-exec # install-data: + echo Installing sample ipptest files in $(DATADIR)/ipptest... + $(INSTALL_DIR) -m 755 $(DATADIR)/ipptest + for file in $(TESTFILES); do \ + $(INSTALL_DATA) $$file $(DATADIR)/ipptest; \ + done # @@ -72,6 +91,13 @@ install-data: # install-exec: + echo Installing ipptest in $(BINDIR)... + $(INSTALL_DIR) -m 755 $(BINDIR) + $(INSTALL_BIN) ipptest $(BINDIR) + if test "x$(SYMROOT)" != "x"; then \ + $(INSTALL_DIR) $(SYMROOT); \ + cp ipptest $(SYMROOT); \ + fi # @@ -99,9 +125,18 @@ uninstall: # ipptest # -ipptest: ipptest.o ../cups/libcups.a +ipptest: ipptest.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ ipptest.o $(LIBS) + + +# +# ipptest-static +# + +ipptest-static: ipptest.o ../cups/$(LIBCUPSSTATIC) echo Linking $@... - $(CC) $(LDFLAGS) -o ipptest ipptest.o ../cups/libcups.a \ + $(CC) $(LDFLAGS) -o $@ ipptest.o ../cups/$(LIBCUPSSTATIC) \ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) diff --git a/test/ipp-1.1.test b/test/ipp-1.1.test new file mode 100644 index 000000000..bdc1fd610 --- /dev/null +++ b/test/ipp-1.1.test @@ -0,0 +1,742 @@ +# +# "$Id$" +# +# 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: +# +# ./ipptest -f filename 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 + 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 + # Not requiring 0x0004 Validate-Job since it is deprecated + 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 +{ + 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 10 + + 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 +} + + +# 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$". +# diff --git a/test/ipp-2.0.test b/test/ipp-2.0.test new file mode 100644 index 000000000..0c6778804 --- /dev/null +++ b/test/ipp-2.0.test @@ -0,0 +1,107 @@ +# +# "$Id$" +# +# 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: +# +# ./ipptest -V 2.0 -f filename 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" + + +# 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 + + # Job template attributes + 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 IN-GROUP printer-attributes-tag COUNT 1 WITH-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 + # Not requiring 0x0004 Validate-Job since it is deprecated + 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 +} + + +# +# End of "$Id$". +# diff --git a/test/ipp-2.1.test b/test/ipp-2.1.test new file mode 100644 index 000000000..d35eab0aa --- /dev/null +++ b/test/ipp-2.1.test @@ -0,0 +1,105 @@ +# +# "$Id$" +# +# 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: +# +# ./ipptest -V 2.1 -f filename printer-uri ipp-2.0.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 ?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 IN-GROUP printer-attributes-tag COUNT 1 WITH-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 + # Not requiring 0x0004 Validate-Job since it is deprecated + 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 +} + + +# +# End of "$Id$". +# diff --git a/test/ipptest.c b/test/ipptest.c index 28404388d..e94f06f36 100644 --- a/test/ipptest.c +++ b/test/ipptest.c @@ -1,9 +1,9 @@ /* - * "$Id: ipptest.c 7847 2008-08-19 04:22:14Z mike $" + * "$Id: ipptest.c 9000 2010-02-24 06:29:38Z mike $" * * IPP test command for the Common UNIX Printing System (CUPS). * - * Copyright 2007-2009 by Apple Inc. + * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2007 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -14,13 +14,28 @@ * * Contents: * - * main() - Parse options and do tests. - * do_tests() - Do tests as specified in the test file. - * expect_matches() - Return true if the tag matches the specification. - * get_token() - Get a token from a file. - * print_attr() - Print an attribute on the screen. - * print_col() - Print a collection attribute on the screen. - * usage() - Show program usage. + * 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. + * print_attr() - Print an attribute on the screen. + * print_col() - Print a collection attribute on the screen. + * print_fatal_error() - Print a fatal error message. + * 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. + * usage() - Show program usage. + * validate_attr() - Determine whether an attribute is valid. + * with_value() - Test a WITH-VALUE predicate. */ /* @@ -29,13 +44,11 @@ #include #include -#include #include #include +#include -#include -#include -#include +#include #ifndef O_BINARY # define O_BINARY 0 #endif /* !O_BINARY */ @@ -45,35 +58,122 @@ * Types... */ +typedef enum /**** 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 struct _cups_expect_s /**** Expected attribute info ****/ { - int 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 */ + 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_undefined, /* Only required if variable is not defined */ + *with_value; /* Attribute must include this 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_undefined; /* 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? */ + cups_array_t *vars; /* Array of variables */ +} _cups_vars_t; + /* * Globals... */ -int Chunking = 0; /* Use chunked requests */ -int Verbosity = 0; /* Show all attributes? */ +_cups_transfer_t Transfer = _CUPS_TRANSFER_AUTO; + /* How to transfer requests */ +int Verbosity = 0, /* Show all attributes? */ + Version = 11, /* Default IPP version */ + XML = 0, /* Produce XML output? */ + XMLHeader = 0; /* 1 if header is written */ +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 do_tests(const char *uri, const char *testfile); +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 void print_attr(ipp_attribute_t *attr); static void print_col(ipp_t *col); +static void print_fatal_error(const char *s, ...) +#ifdef __GNUC__ +__attribute__ ((__format__ (__printf__, 1, 2))) +#endif /* __GNUC__ */ +; +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 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); /* @@ -84,21 +184,32 @@ 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 */ - const char *uri, /* URI to use */ - *testfile; /* Test file to use */ - int interval; /* Test interval */ + int i; /* Looping var */ + int status; /* Status of tests... */ + char *opt, /* Current option */ + name[1024], /* Name/value buffer */ + *value; /* Pointer to value */ + const char *testfile; /* Test file to use */ + int interval; /* Test interval */ + _cups_vars_t vars; /* Variables */ + http_uri_status_t uri_status; /* URI separation status */ + + + /* + * Initialize the locale and variables... + */ + + _cupsSetLocale(argv); + memset(&vars, 0, sizeof(vars)); + vars.vars = cupsArrayNew((cups_array_func_t)compare_vars, NULL); /* * We need at least: * - * testipp URL testfile + * ipptest URI testfile */ - uri = NULL; testfile = NULL; status = 0; interval = 0; @@ -111,8 +222,58 @@ main(int argc, /* I - Number of command-line args */ { switch (*opt) { + case 'E' : /* Encrypt */ +#ifdef HAVE_SSL + vars.encryption = HTTP_ENCRYPT_REQUIRED; +#else + _cupsLangPrintf(stderr, + _("%s: Sorry, no encryption support compiled in\n"), + argv[0]); +#endif /* HAVE_SSL */ + break; + + case 'V' : /* Set IPP version */ + i ++; + + if (i >= argc) + { + _cupsLangPuts(stderr, + _("ipptest: Missing version for \"-V\".\n")); + 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, + _("ipptest: Bad version %s for \"-V\".\n"), + argv[i]); + usage(); + } + break; + + case 'X' : /* Produce XML output */ + XML = 1; + + if (interval) + { + _cupsLangPuts(stderr, _("ipptest: \"-i\" is incompatible with " + "\"-x\".\n")); + usage(); + } + break; + case 'c' : /* Enable HTTP chunking */ - Chunking = 1; + Transfer = _CUPS_TRANSFER_CHUNKED; break; case 'd' : /* Define a variable */ @@ -120,11 +281,31 @@ main(int argc, /* I - Number of command-line args */ if (i >= argc) { - fputs("ipptest: Missing name=value for \"-d\"!\n", stderr); + _cupsLangPuts(stderr, + _("ipptest: Missing name=value for \"-d\".\n")); usage(); } + + strlcpy(name, argv[i], sizeof(name)); + if ((value = strchr(name, '=')) != NULL) + *value++ = '\0'; else - putenv(argv[i]); + value = name + strlen(name); + + set_variable(&vars, name, value); + break; + + case 'f' : /* Set the default test filename */ + i ++; + + if (i >= argc) + { + _cupsLangPuts(stderr, + _("ipptest: Missing filename for \"-f\".\n")); + usage(); + } + + vars.filename = argv[i]; break; case 'i' : /* Test every N seconds */ @@ -132,19 +313,32 @@ main(int argc, /* I - Number of command-line args */ if (i >= argc) { - fputs("ipptest: Missing seconds for \"-i\"!\n", stderr); + _cupsLangPuts(stderr, + _("ipptest: Missing seconds for \"-i\".\n")); usage(); } else interval = atoi(argv[i]); + + if (XML && interval) + { + _cupsLangPuts(stderr, _("ipptest: \"-i\" is incompatible with " + "\"-x\".\n")); + usage(); + } break; + case 'l' : /* Disable HTTP chunking */ + Transfer = _CUPS_TRANSFER_LENGTH; + break; + case 'v' : /* Be verbose */ Verbosity ++; break; default : - fprintf(stderr, "ipptest: Unknown option \"-%c\"!\n", *opt); + _cupsLangPrintf(stderr, _("ipptest: Unknown option \"-%c\".\n"), + *opt); usage(); break; } @@ -158,15 +352,34 @@ main(int argc, /* I - Number of command-line args */ * Set URI... */ - if (!testfile && uri) + if (vars.uri) { - fputs("ipptest: May only specify a single URI before a test!\n", - stderr); + _cupsLangPuts(stderr, _("ipptest: May only specify a single URI.\n")); usage(); } - uri = argv[i]; - testfile = NULL; + 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, _("ipptest: Bad URI - %s.\n"), + URIStatusStrings[uri_status - HTTP_URI_OVERFLOW]); + return (1); + } + + if (strcmp(vars.scheme, "http") && strcmp(vars.scheme, "https") && + strcmp(vars.scheme, "ipp")) + { + _cupsLangPuts(stderr, _("ipptest: Only http, https, and ipp URIs are " + "supported.")); + return (1); + } } else { @@ -174,26 +387,34 @@ main(int argc, /* I - Number of command-line args */ * Run test... */ + if (!vars.uri) + { + _cupsLangPuts(stderr, _("ipptest: URI required before test file.")); + usage(); + } + testfile = argv[i]; - if (!do_tests(uri, testfile)) - status ++; + if (!do_tests(&vars, testfile)) + status = 1; } } - if (!uri || !testfile) + if (!vars.uri || !testfile) usage(); /* * Loop if the interval is set... */ - if (interval) + if (XML) + print_xml_trailer(!status, NULL); + else if (interval) { for (;;) { sleep(interval); - do_tests(uri, testfile); + do_tests(&vars, testfile); } } @@ -204,50 +425,59 @@ main(int argc, /* I - Number of command-line args */ 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 (strcasecmp(a->name, b->name)); +} + + /* * 'do_tests()' - Do tests as specified in the test file. */ static int /* 1 = success, 0 = failure */ -do_tests(const char *uri, /* I - URI to connect on */ - const char *testfile) /* I - Test file to use */ +do_tests(_cups_vars_t *vars, /* I - Variables */ + const char *testfile) /* I - Test file to use */ { - int i; /* Looping var */ - int linenum; /* Current line number */ - int version; /* IPP version number to use */ - http_t *http; /* HTTP connection to server */ - char scheme[HTTP_MAX_URI], /* URI scheme */ - userpass[HTTP_MAX_URI], /* username:password */ - server[HTTP_MAX_URI], /* Server */ - resource[HTTP_MAX_URI]; /* Resource path */ - int port; /* Port number */ - FILE *fp; /* Test file */ - char token[1024], /* Token from file */ + int i, /* Looping var */ + linenum, /* Current line number */ + pass, /* Did we pass the test? */ + request_id; /* Current request ID */ + 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 */ - *tempptr; /* Pointer into temp string */ - ipp_t *request; /* IPP request */ - ipp_t *response; /* IPP response */ + 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 */ - char attr[128]; /* Attribute name */ - int num_statuses; /* Number of valid status codes */ - ipp_status_t statuses[100]; /* Valid status codes */ - int num_expects; /* Number of expected attributes */ - _cups_expect_t expects[100], /* Expected attributes */ + *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 */ + 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; /* Number of displayed attributes */ + int num_displayed = 0; /* Number of displayed attributes */ char *displayed[100]; /* Displayed attributes */ - char name[1024]; /* Name of test */ - char filename[1024]; /* Filename */ - int pass; /* Did we pass the test? */ - int job_id; /* Job ID from last operation */ - int subscription_id; /* Subscription ID from last operation */ /* @@ -256,35 +486,37 @@ do_tests(const char *uri, /* I - URI to connect on */ if ((fp = fopen(testfile, "r")) == NULL) { - printf("Unable to open test file %s - %s\n", testfile, strerror(errno)); - return (0); + print_fatal_error("Unable to open test file %s - %s", testfile, + strerror(errno)); + goto test_error; } /* * Connect to the server... */ - httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), userpass, - sizeof(userpass), server, sizeof(server), &port, resource, - sizeof(resource)); - if ((http = httpConnect(server, port)) == NULL) + if ((http = httpConnectEncrypt(vars->hostname, vars->port, + vars->encryption)) == NULL) { - printf("Unable to connect to %s on port %d - %s\n", server, port, - strerror(errno)); - fclose(fp); - return (0); + print_fatal_error("Unable to connect to %s on port %d - %s", vars->hostname, + vars->port, strerror(errno)); + goto test_error; } /* * Loop on tests... */ - printf("\"%s\":\n", testfile); - pass = 1; - job_id = 0; - subscription_id = 0; - version = 11; - linenum = 1; + if (XML) + print_xml_header(); + else + printf("\"%s\":\n", testfile); + + CUPS_SRAND(time(NULL)); + + pass = 1; + linenum = 1; + request_id = (CUPS_RAND() % 1000) * 137 + 1; while (get_token(fp, token, sizeof(token), &linenum) != NULL) { @@ -292,32 +524,134 @@ do_tests(const char *uri, /* I - URI to connect on */ * Expect an open brace... */ - if (strcmp(token, "{")) + 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); + goto test_error; + } + + continue; + } + else if (!strcmp(token, "INCLUDE")) + { + /* + * INCLUDE "filename" + * INCLUDE + */ + + 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)))) + goto test_error; + } + else + { + print_fatal_error("Missing INCLUDE filename on line %d.", linenum); + goto test_error; + } + + 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); + goto test_error; + } + } + else + { + print_fatal_error("Missing TRANSFER value on line %d.", linenum); + goto test_error; + } + + 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); + goto test_error; + } + } + else + { + print_fatal_error("Missing VERSION number on line %d.", linenum); + goto test_error; + } + + continue; + } + else if (strcmp(token, "{")) { - printf("Unexpected token %s seen on line %d - aborting test!\n", token, - linenum); - httpClose(http); - return (0); + print_fatal_error("Unexpected token %s seen on line %d.", token, linenum); + goto test_error; } /* * Initialize things... */ - httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), userpass, - sizeof(userpass), server, sizeof(server), &port, resource, - sizeof(resource)); + strlcpy(resource, vars->resource, sizeof(resource)); + request_id ++; request = ippNew(); op = (ipp_op_t)0; group = IPP_TAG_ZERO; - num_statuses = 0; - num_expects = 0; - num_displayed = 0; last_expect = NULL; + last_status = NULL; filename[0] = '\0'; + version = Version; + transfer = Transfer; - strcpy(name, testfile); + strlcpy(name, testfile, sizeof(name)); if (strrchr(name, '.') != NULL) *strrchr(name, '.') = '\0'; @@ -327,14 +661,86 @@ do_tests(const char *uri, /* I - URI to connect on */ while (get_token(fp, token, sizeof(token), &linenum) != NULL) { - if (strcasecmp(token, "EXPECT") && + if (strcasecmp(token, "COUNT") && strcasecmp(token, "IF-DEFINED") && + strcasecmp(token, "IF-UNDEFINED") && + strcasecmp(token, "IN-GROUP") && strcasecmp(token, "OF-TYPE") && - strcasecmp(token, "SAME-COUNT-AS")) + strcasecmp(token, "SAME-COUNT-AS") && + strcasecmp(token, "WITH-VALUE")) last_expect = NULL; + if (strcasecmp(token, "IF-DEFINED") && + strcasecmp(token, "IF-UNDEFINED")) + 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); + goto test_error; + } + + 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 + goto test_error; + } + 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); + goto test_error; + } + } else if (!strcasecmp(token, "NAME")) { /* @@ -343,26 +749,87 @@ do_tests(const char *uri, /* I - URI to connect on */ get_token(fp, name, sizeof(name), &linenum); } - else if (!strcasecmp(token, "VERSION")) + else if (!strcmp(token, "REQUEST-ID")) { /* - * IPP version number for test... + * REQUEST-ID # + * REQUEST-ID random */ - int major, minor; /* Major/minor IPP version */ - + if (get_token(fp, temp, sizeof(temp), &linenum)) + { + if (isdigit(temp[0] & 255)) + request_id = atoi(temp); + else if (!strcasecmp(temp, "random")) + request_id = (CUPS_RAND() % 1000) * 137 + 1; + else + { + print_fatal_error("Bad REQUEST-ID value \"%s\" on line %d.", temp, + linenum); + goto test_error; + } + } + else + { + print_fatal_error("Missing REQUEST-ID value on line %d.", linenum); + goto test_error; + } + } + else if (!strcmp(token, "TRANSFER")) + { + /* + * TRANSFER auto + * TRANSFER chunked + * TRANSFER length + */ - get_token(fp, temp, sizeof(temp), &linenum); - if (sscanf(temp, "%d.%d", &major, &minor) == 2 && - major >= 0 && minor >= 0 && minor < 10) - version = major * 10 + minor; + 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); + goto test_error; + } + } + else + { + print_fatal_error("Missing TRANSFER value on line %d.", linenum); + goto test_error; + } + } + else if (!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); + goto test_error; + } + } else { - printf("Bad version %s seen on line %d - aborting test!\n", token, - linenum); - httpClose(http); - ippDelete(request); - return (0); + print_fatal_error("Missing VERSION number on line %d.", linenum); + goto test_error; } } else if (!strcasecmp(token, "RESOURCE")) @@ -371,7 +838,11 @@ do_tests(const char *uri, /* I - URI to connect on */ * Resource name... */ - get_token(fp, resource, sizeof(resource), &linenum); + if (!get_token(fp, resource, sizeof(resource), &linenum)) + { + print_fatal_error("Missing RESOURCE path on line %d.", linenum); + goto test_error; + } } else if (!strcasecmp(token, "OPERATION")) { @@ -379,8 +850,18 @@ do_tests(const char *uri, /* I - URI to connect on */ * Operation... */ - get_token(fp, token, sizeof(token), &linenum); - op = ippOpValue(token); + if (!get_token(fp, token, sizeof(token), &linenum)) + { + print_fatal_error("Missing OPERATION code on line %d.", linenum); + goto test_error; + } + + if ((op = ippOpValue(token)) < 0) + { + print_fatal_error("Bad OPERATION code \"%s\" on line %d.", token, + linenum); + goto test_error; + } } else if (!strcasecmp(token, "GROUP")) { @@ -388,8 +869,17 @@ do_tests(const char *uri, /* I - URI to connect on */ * Attribute group... */ - get_token(fp, token, sizeof(token), &linenum); - value = ippTagValue(token); + if (!get_token(fp, token, sizeof(token), &linenum)) + { + print_fatal_error("Missing GROUP tag on line %d.", linenum); + goto test_error; + } + + if ((value = ippTagValue(token)) < 0) + { + print_fatal_error("Bad GROUP tag \"%s\" on line %d.", token, linenum); + goto test_error; + } if (value == group) ippAddSeparator(request); @@ -404,8 +894,19 @@ do_tests(const char *uri, /* I - URI to connect on */ int delay; - get_token(fp, token, sizeof(token), &linenum); - if ((delay = atoi(token)) > 0) + if (!get_token(fp, token, sizeof(token), &linenum)) + { + print_fatal_error("Missing DELAY value on line %d.", linenum); + goto test_error; + } + + if ((delay = atoi(token)) <= 0) + { + print_fatal_error("Bad DELAY value \"%s\" on line %d.", token, + linenum); + goto test_error; + } + else sleep(delay); } else if (!strcasecmp(token, "ATTR")) @@ -414,102 +915,34 @@ do_tests(const char *uri, /* I - URI to connect on */ * Attribute... */ - get_token(fp, token, sizeof(token), &linenum); - value = ippTagValue(token); - get_token(fp, attr, sizeof(attr), &linenum); - get_token(fp, temp, sizeof(temp), &linenum); + if (!get_token(fp, token, sizeof(token), &linenum)) + { + print_fatal_error("Missing ATTR value tag on line %d.", linenum); + goto test_error; + } - token[sizeof(token) - 1] = '\0'; + if ((value = ippTagValue(token)) < 0) + { + print_fatal_error("Bad ATTR value tag \"%s\" on line %d.", token, + linenum); + goto test_error; + } - for (tempptr = temp, tokenptr = token; - *tempptr && tokenptr < (token + sizeof(token) - 1);) - if (*tempptr == '$') - { - /* - * Substitute a string/number... - */ + printf("%d: value=%s\n", linenum, ippTagString(value)); - if (!strncasecmp(tempptr + 1, "uri", 3)) - { - strlcpy(tokenptr, uri, sizeof(token) - (tokenptr - token)); - tempptr += 4; - } - else if (!strncasecmp(tempptr + 1, "scheme", 6) || - !strncasecmp(tempptr + 1, "method", 6)) - { - strlcpy(tokenptr, scheme, sizeof(token) - (tokenptr - token)); - tempptr += 7; - } - else if (!strncasecmp(tempptr + 1, "username", 8)) - { - strlcpy(tokenptr, userpass, sizeof(token) - (tokenptr - token)); - tempptr += 9; - } - else if (!strncasecmp(tempptr + 1, "hostname", 8)) - { - strlcpy(tokenptr, server, sizeof(token) - (tokenptr - token)); - tempptr += 9; - } - else if (!strncasecmp(tempptr + 1, "port", 4)) - { - snprintf(tokenptr, sizeof(token) - (tokenptr - token), - "%d", port); - tempptr += 5; - } - else if (!strncasecmp(tempptr + 1, "resource", 8)) - { - strlcpy(tokenptr, resource, sizeof(token) - (tokenptr - token)); - tempptr += 9; - } - else if (!strncasecmp(tempptr + 1, "job-id", 6)) - { - snprintf(tokenptr, sizeof(token) - (tokenptr - token), - "%d", job_id); - tempptr += 7; - } - else if (!strncasecmp(tempptr + 1, "notify-subscription-id", 22)) - { - snprintf(tokenptr, sizeof(token) - (tokenptr - token), - "%d", subscription_id); - tempptr += 23; - } - else if (!strncasecmp(tempptr + 1, "user", 4)) - { - strlcpy(tokenptr, cupsUser(), sizeof(token) - (tokenptr - token)); - tempptr += 5; - } - else if (!strncasecmp(tempptr + 1, "ENV[", 4)) - { - char *end; /* End of $ENV[name] */ + if (!get_token(fp, attr, sizeof(attr), &linenum)) + { + print_fatal_error("Missing ATTR name on line %d.", linenum); + goto test_error; + } + if (!get_token(fp, temp, sizeof(temp), &linenum)) + { + print_fatal_error("Missing ATTR value on line %d.", linenum); + goto test_error; + } - if ((end = strchr(tempptr + 5, ']')) != NULL) - { - *end++ = '\0'; - strlcpy(tokenptr, - getenv(tempptr + 5) ? getenv(tempptr + 5) : tempptr + 5, - sizeof(token) - (tokenptr - token)); - tempptr = end; - } - else - { - *tokenptr++ = *tempptr++; - *tokenptr = '\0'; - } - } - else - { - *tokenptr++ = *tempptr++; - *tokenptr = '\0'; - } - - tokenptr += strlen(tokenptr); - } - else - { - *tokenptr++ = *tempptr++; - *tokenptr = '\0'; - } + expand_variables(vars, token, temp, sizeof(token)); switch (value) { @@ -526,11 +959,74 @@ do_tests(const char *uri, /* I - URI to connect on */ break; case IPP_TAG_RESOLUTION : - puts(" ERROR: resolution tag not yet supported!"); + { + int xres, /* X resolution */ + yres; /* Y resolution */ + char units[6]; /* Units */ + + if (sscanf(token, "%dx%d%5s", &xres, &yres, units) != 3 || + (strcasecmp(units, "dpi") && strcasecmp(units, "dpc") && + strcasecmp(units, "other"))) + { + print_fatal_error("Bad resolution value \"%s\" on line %d.", + token, linenum); + goto test_error; + } + + if (!strcasecmp(units, "dpi")) + ippAddResolution(request, group, attr, xres, yres, + IPP_RES_PER_INCH); + else if (!strcasecmp(units, "dpc")) + ippAddResolution(request, group, attr, xres, yres, + IPP_RES_PER_CM); + else + ippAddResolution(request, group, attr, xres, yres, + (ipp_res_t)0); + } break; case IPP_TAG_RANGE : - puts(" ERROR: range tag not yet supported!"); + { + 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 test_error; + } + + 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); + else + goto test_error; + } + else + { + print_fatal_error("Bad ATTR collection value on line %d.", + linenum); + goto test_error; + } break; default : @@ -569,18 +1065,45 @@ do_tests(const char *uri, /* I - URI to connect on */ * File... */ - get_token(fp, filename, sizeof(filename), &linenum); + if (!get_token(fp, temp, sizeof(temp), &linenum)) + { + print_fatal_error("Missing FILE filename on line %d.", linenum); + goto test_error; + } + + expand_variables(vars, token, temp, sizeof(token)); + get_filename(testfile, filename, token, sizeof(filename)); } - else if (!strcasecmp(token, "STATUS") && - num_statuses < (int)(sizeof(statuses) / sizeof(statuses[0]))) + else if (!strcasecmp(token, "STATUS")) { /* * Status... */ - get_token(fp, token, sizeof(token), &linenum); - statuses[num_statuses] = ippErrorValue(token); + if (num_statuses >= (int)(sizeof(statuses) / sizeof(statuses[0]))) + { + print_fatal_error("Too many STATUS's on line %d.", linenum); + goto test_error; + } + + if (!get_token(fp, token, sizeof(token), &linenum)) + { + print_fatal_error("Missing STATUS code on line %d.", linenum); + goto test_error; + } + + if ((statuses[num_statuses].status = ippErrorValue(token)) < 0) + { + print_fatal_error("Bad STATUS code \"%s\" on line %d.", token, + linenum); + goto test_error; + } + + last_status = statuses + num_statuses; num_statuses ++; + + last_status->if_defined = NULL; + last_status->if_undefined = NULL; } else if (!strcasecmp(token, "EXPECT")) { @@ -590,99 +1113,218 @@ do_tests(const char *uri, /* I - URI to connect on */ if (num_expects >= (int)(sizeof(expects) / sizeof(expects[0]))) { - fprintf(stderr, "ipptest: Too many EXPECT's on line %d\n", linenum); - httpClose(http); - ippDelete(request); - return (0); + print_fatal_error("Too many EXPECT's on line %d.", linenum); + goto test_error; } - get_token(fp, token, sizeof(token), &linenum); + if (!get_token(fp, token, sizeof(token), &linenum)) + { + print_fatal_error("Missing EXPECT name on line %d.", linenum); + goto test_error; + } 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 + else if (token[0] == '?') { - last_expect->not_expect = 0; - last_expect->name = strdup(token); + last_expect->optional = 1; + last_expect->name = strdup(token + 1); + } + else + last_expect->name = strdup(token); + } + else if (!strcasecmp(token, "COUNT")) + { + if (!get_token(fp, token, sizeof(token), &linenum)) + { + print_fatal_error("Missing COUNT number on line %d.", linenum); + goto test_error; + } + + if ((i = atoi(token)) <= 0) + { + print_fatal_error("Bad COUNT \"%s\" on line %d.", token, linenum); + goto test_error; } - last_expect->of_type = NULL; - last_expect->same_count_as = NULL; - last_expect->if_defined = NULL; + if (last_expect) + last_expect->count = i; + else + { + print_fatal_error("COUNT without a preceding EXPECT on line %d.", + linenum); + goto test_error; + } } else if (!strcasecmp(token, "OF-TYPE")) { - get_token(fp, token, sizeof(token), &linenum); + if (!get_token(fp, token, sizeof(token), &linenum)) + { + print_fatal_error("Missing OF-TYPE value tag(s) on line %d.", + linenum); + goto test_error; + } if (last_expect) last_expect->of_type = strdup(token); else { - fprintf(stderr, - "ipptest: OF-TYPE without a preceding EXPECT on line %d\n", - linenum); - httpClose(http); - ippDelete(request); - return (0); + print_fatal_error("OF-TYPE without a preceding EXPECT on line %d.", + linenum); + goto test_error; + } + } + else if (!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); + goto test_error; + } + + 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); + goto test_error; } } else if (!strcasecmp(token, "SAME-COUNT-AS")) { - get_token(fp, token, sizeof(token), &linenum); + if (!get_token(fp, token, sizeof(token), &linenum)) + { + print_fatal_error("Missing SAME-COUNT-AS name on line %d.", linenum); + goto test_error; + } if (last_expect) last_expect->same_count_as = strdup(token); else { - fprintf(stderr, - "ipptest: SAME-COUNT-AS without a preceding EXPECT on line " - "%d\n", linenum); - httpClose(http); - ippDelete(request); - return (0); + print_fatal_error("SAME-COUNT-AS without a preceding EXPECT on line " + "%d.", linenum); + goto test_error; } } else if (!strcasecmp(token, "IF-DEFINED")) { - get_token(fp, token, sizeof(token), &linenum); + if (!get_token(fp, token, sizeof(token), &linenum)) + { + print_fatal_error("Missing IF-DEFINED name on line %d.", linenum); + goto test_error; + } 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); + goto test_error; + } + } + else if (!strcasecmp(token, "IF-UNDEFINED")) + { + if (!get_token(fp, token, sizeof(token), &linenum)) + { + print_fatal_error("Missing IF-UNDEFINED name on line %d.", linenum); + goto test_error; + } + + if (last_expect) + last_expect->if_undefined = strdup(token); + else if (last_status) + last_status->if_undefined = strdup(token); + else + { + print_fatal_error("IF-UNDEFINED without a preceding EXPECT or STATUS " + "on line %d.", linenum); + goto test_error; + } + } + else if (!strcasecmp(token, "WITH-VALUE")) + { + if (!get_token(fp, token, sizeof(token), &linenum)) + { + print_fatal_error("Missing WITH-VALUE value on line %d.", linenum); + goto test_error; + } + + if (last_expect) + { + 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 { - fprintf(stderr, - "ipptest: IF-DEFINED without a preceding EXPECT on line %d\n", - linenum); - httpClose(http); - ippDelete(request); - return (0); + print_fatal_error("WITH-VALUE without a preceding EXPECT on line %d.", + linenum); + goto test_error; } } - else if (!strcasecmp(token, "DISPLAY") && - num_displayed < (int)(sizeof(displayed) / sizeof(displayed[0]))) + else if (!strcasecmp(token, "DISPLAY")) { /* * Display attributes... */ - get_token(fp, token, sizeof(token), &linenum); + if (num_displayed >= (int)(sizeof(displayed) / sizeof(displayed[0]))) + { + print_fatal_error("Too many DISPLAY's on line %d", linenum); + goto test_error; + } + + if (!get_token(fp, token, sizeof(token), &linenum)) + { + print_fatal_error("Missing DISPLAY name on line %d.", linenum); + goto test_error; + } + displayed[num_displayed] = strdup(token); num_displayed ++; } else { - fprintf(stderr, - "ipptest: Unexpected token %s seen on line %d - aborting " - "test!\n", token, linenum); - httpClose(http); - ippDelete(request); - return (0); + print_fatal_error("Unexpected token %s seen on line %d.", token, + linenum); + goto test_error; } } @@ -693,21 +1335,42 @@ do_tests(const char *uri, /* I - URI to connect on */ 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 = 1; + request->request.op.request_id = request_id; - if (Verbosity) + if (XML) { - printf(" %s:\n", ippOpString(op)); - + puts(""); + puts("Name"); + print_xml_string("string", name); + puts("Operation"); + print_xml_string("string", ippOpString(op)); + puts("RequestAttributes"); + puts(""); for (attrptr = request->attrs; attrptr; attrptr = attrptr->next) print_attr(attrptr); + puts(""); } + else + { + if (Verbosity) + { + printf(" %s:\n", ippOpString(op)); + + for (attrptr = request->attrs; attrptr; attrptr = attrptr->next) + print_attr(attrptr); + } - printf(" %-60.60s [", name); - fflush(stdout); + printf(" %-69.69s [", name); + fflush(stdout); + } - if (Chunking) + 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]) @@ -716,7 +1379,6 @@ do_tests(const char *uri, /* I - URI to connect on */ 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) @@ -725,7 +1387,12 @@ do_tests(const char *uri, /* I - URI to connect on */ break; } else + { + snprintf(buffer, sizeof(buffer), "%s: %s", filename, strerror(errno)); + _cupsSetError(IPP_INTERNAL_ERROR, buffer, 0); + status = HTTP_ERROR; + } } ippDelete(request); @@ -738,36 +1405,107 @@ do_tests(const char *uri, /* I - URI to connect on */ else if (filename[0]) response = cupsDoFileRequest(http, request, resource, filename); else - response = cupsDoIORequest(http, request, resource, -1, - Verbosity ? 1 : -1); - - if (response == NULL) - { - time_t curtime; + response = cupsDoRequest(http, request, resource); - curtime = time(NULL); + request = NULL; - puts("FAIL]"); - printf(" ERROR %04x (%s) @ %s\n", cupsLastError(), - cupsLastErrorString(), ctime(&curtime)); + if (!response) pass = 0; - } else { if (http->version != HTTP_1_1) pass = 0; + if (response->request.status.version[0] != (version / 10) || + response->request.status.version[1] != (version % 10) || + response->request.status.request_id != request_id) + pass = 0; + if ((attrptr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) != NULL) - job_id = attrptr->values[0].integer; + { + 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) - subscription_id = attrptr->values[0].integer; + { + 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")) + 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")) + 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))) + 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))) + 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) + { + pass = 0; + break; + } + + if (!validate_attr(attrptr, 0)) + { + pass = 0; + break; + } + } for (i = 0; i < num_statuses; i ++) - if (response->request.status.status_code == statuses[i]) + { + if (statuses[i].if_defined && + !get_variable(vars, statuses[i].if_defined)) + continue; + + if (statuses[i].if_undefined && + get_variable(vars, statuses[i].if_undefined)) + continue; + + if (response->request.status.status_code == statuses[i].status) break; + } if (i == num_statuses && num_statuses > 0) pass = 0; @@ -775,18 +1513,37 @@ do_tests(const char *uri, /* I - URI to connect on */ { for (i = num_expects, expect = expects; i > 0; i --, expect ++) { - if (expect->if_defined && !getenv(expect->if_defined)) + if (expect->if_defined && !get_variable(vars, expect->if_defined)) + continue; + + if (expect->if_undefined && get_variable(vars, expect->if_undefined)) continue; found = ippFindAttribute(response, expect->name, IPP_TAG_ZERO); - if ((found == NULL) != expect->not_expect || - (found && !expect_matches(expect, found->value_tag))) + 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)) { pass = 0; break; } + if (found && + !with_value(expect->with_value, expect->with_regex, found)) + { + pass = 0; + break; + } + + if (found && expect->count > 0 && found->num_values != expect->count) + { + pass = 0; + break; + } + if (found && expect->same_count_as) { attrptr = ippFindAttribute(response, expect->same_count_as, @@ -800,106 +1557,284 @@ do_tests(const char *uri, /* I - URI to connect on */ } } } + } + + if (XML) + { + puts("Successful"); + puts(pass ? "" : ""); + puts("StatusCode"); + print_xml_string("string", ippErrorString(cupsLastError())); + puts("ResponseAttributes"); + puts(""); + for (attrptr = response ? response->attrs : NULL; + attrptr; + attrptr = attrptr->next) + print_attr(attrptr); + puts(""); + } + else + { + puts(pass ? "PASS]" : "FAIL]"); - if (pass) + if (Verbosity && response) { - puts("PASS]"); printf(" RECEIVED: %lu bytes in response\n", (unsigned long)ippLength(response)); + printf(" status-code = %x (%s)\n", cupsLastError(), + ippErrorString(cupsLastError())); - if (Verbosity) - { - for (attrptr = response->attrs; - attrptr != NULL; - attrptr = attrptr->next) - { - print_attr(attrptr); - } - } - else if (num_displayed > 0) + for (attrptr = response->attrs; + attrptr != NULL; + attrptr = attrptr->next) { - for (attrptr = response->attrs; - attrptr != NULL; - attrptr = attrptr->next) - { - if (attrptr->name) + print_attr(attrptr); + } + } + } + + if (pass && !XML && !Verbosity && num_displayed > 0) + { + 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)) { - for (i = 0; i < num_displayed; i ++) - { - if (!strcmp(displayed[i], attrptr->name)) - { - print_attr(attrptr); - break; - } - } + print_attr(attrptr); + break; } - } - } + } + else if (!pass) + { + if (XML) + { + puts("Errors"); + puts(""); } + + 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 { - puts("FAIL]"); - printf(" RECEIVED: %lu bytes in response\n", - (unsigned long)ippLength(response)); + if (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 (http->version != HTTP_1_1) - printf(" BAD HTTP VERSION (%d.%d)\n", http->version / 100, - http->version % 100); + 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 (response->request.status.status_code == statuses[i]) + { + if (statuses[i].if_defined && + !get_variable(vars, statuses[i].if_defined)) + continue; + + if (statuses[i].if_undefined && + get_variable(vars, statuses[i].if_undefined)) + continue; + + if (response->request.status.status_code == statuses[i].status) break; + } if (i == num_statuses && num_statuses > 0) - puts(" BAD STATUS"); + { + print_test_error("Bad status-code (%s)", + ippErrorString(cupsLastError())); + print_test_error("status-message=\"%s\"", cupsLastErrorString()); + } - printf(" status-code = %04x (%s)\n", - cupsLastError(), ippErrorString(cupsLastError())); + for (i = num_expects, expect = expects; i > 0; i --, expect ++) + { + if (expect->if_defined && !get_variable(vars, expect->if_defined)) + continue; + + if (expect->if_undefined && get_variable(vars, expect->if_undefined)) + 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)); - for (i = num_expects, expect = expects; i > 0; i --, expect ++) - { - if (expect->if_defined && !getenv(expect->if_defined)) - continue; + 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)); - found = ippFindAttribute(response, expect->name, IPP_TAG_ZERO); + if (!with_value(expect->with_value, expect->with_regex, found)) + { + 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); + } - if ((found == NULL) != expect->not_expect) - { - if (expect->not_expect) - printf(" NOT EXPECTED: %s\n", expect->name); - else - printf(" EXPECTED: %s\n", expect->name); - } - else if (found) - { - if (!expect_matches(expect, found->value_tag)) - printf(" EXPECTED: %s of type %s but got %s\n", - expect->name, expect->of_type, - ippTagString(found->value_tag)); - else if (expect->same_count_as) + 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) - printf(" EXPECTED: %s (%d values) same count as %s " - "(not returned)\n", - expect->name, found->num_values, expect->same_count_as); + 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) - printf(" EXPECTED: %s (%d values) same count as %s " - "(%d values)\n", - expect->name, found->num_values, expect->same_count_as, - attrptr->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); } } - } - - for (attrptr = response->attrs; attrptr != NULL; attrptr = attrptr->next) - print_attr(attrptr); + } } - ippDelete(response); + if (XML) + puts(""); + } + + if (XML) + puts(""); + + 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_undefined) + free(statuses[i].if_undefined); } + num_statuses = 0; for (i = num_expects, expect = expects; i > 0; i --, expect ++) { @@ -910,7 +1845,17 @@ do_tests(const char *uri, /* I - URI to connect on */ free(expect->same_count_as); if (expect->if_defined) free(expect->if_defined); + if (expect->if_undefined) + free(expect->if_undefined); + if (expect->with_value) + free(expect->with_value); } + num_expects = 0; + + for (i = 0; i < num_displayed; i ++) + free(displayed[i]); + num_displayed = 0; + if (!pass) break; } @@ -919,12 +1864,155 @@ do_tests(const char *uri, /* I - URI to connect on */ httpClose(http); return (pass); -} + /* + * If we get here there was a fatal test error... + */ -/* - * 'expect_matches()' - Return true if the tag matches the specification. - */ + test_error: + + 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_undefined) + free(statuses[i].if_undefined); + } + + 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_undefined) + free(expect->if_undefined); + if (expect->with_value) + free(expect->with_value); + } + + for (i = 0; i < num_displayed; i ++) + free(displayed[i]); + + return (0); +} + + +/* + * '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( @@ -933,7 +2021,8 @@ expect_matches( { int match; /* Match? */ char *of_type, /* Type name to match */ - *next; /* Next name to match */ + *next, /* Next name to match */ + sep; /* Separator character */ /* @@ -945,7 +2034,7 @@ expect_matches( /* * Parse the "of_type" value since the string can contain multiple attribute - * types separated by "|"... + * types separated by "," or "|"... */ for (of_type = expect->of_type, match = 0; !match && of_type; of_type = next) @@ -954,7 +2043,9 @@ expect_matches( * Find the next separator, and set it (temporarily) to nul if present. */ - if ((next = strchr(of_type, '|')) != NULL) + for (next = of_type; *next && *next != '|' && *next != ','; next ++); + + if ((sep = *next) != '\0') *next = '\0'; /* @@ -974,14 +2065,299 @@ expect_matches( * Restore the separator if we have one... */ - if (next) - *next++ = '|'; + 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 (!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)) < 0) + { + 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 (!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 || + (strcasecmp(units, "dpi") && strcasecmp(units, "dpc") && + strcasecmp(units, "other"))) + { + print_fatal_error("Bad resolution value \"%s\" on line %d.", + token, *linenum); + goto col_error; + } + + if (!strcasecmp(units, "dpi")) + ippAddResolution(col, IPP_TAG_ZERO, attr, xres, yres, + IPP_RES_PER_INCH); + else if (!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); + 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 to CUPS_DATADIR/ipptest/filename... + */ + + snprintf(dst, dstsize, "%s/ipptest/%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. */ @@ -1019,7 +2395,7 @@ get_token(FILE *fp, /* I - File to read from */ else if (ch == '\'' || ch == '\"') { /* - * Quoted text... + * Quoted text or regular expression... */ quote = ch; @@ -1027,12 +2403,27 @@ get_token(FILE *fp, /* I - File to read from */ bufend = buf + buflen - 1; while ((ch = getc(fp)) != EOF) - if (ch == quote) + { + 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 == '#') @@ -1066,14 +2457,61 @@ get_token(FILE *fp, /* I - File to read from */ 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); +} + + /* * 'print_attr()' - Print an attribute on the screen. */ @@ -1081,87 +2519,161 @@ get_token(FILE *fp, /* I - File to read from */ static void print_attr(ipp_attribute_t *attr) /* I - Attribute to print */ { - int i; /* Looping var */ + int i; /* Looping var */ + ipp_attribute_t *colattr; /* Collection attribute */ - if (attr->name == NULL) + if (XML) { - puts(" -- separator --"); - return; + if (!attr->name) + { + printf("%s\n\n", ippTagString(attr->group_tag)); + return; + } + + print_xml_string("key", attr->name); + if (attr->num_values > 1) + puts(""); } + else + { + if (!attr->name) + { + puts(" -- separator --"); + return; + } - printf(" %s (%s%s) = ", attr->name, - attr->num_values > 1 ? "1setOf " : "", - ippTagString(attr->value_tag)); + 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); + if (XML) + printf("%d\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 (attr->values[i].boolean) - printf("true "); + if (XML) + puts(attr->values[i].boolean ? "" : ""); + else if (attr->values[i].boolean) + fputs("true ", stdout); else - printf("false "); - break; - - case IPP_TAG_NOVALUE : - printf("novalue"); + fputs("false ", stdout); 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); + if (XML) + printf("lower%d" + "upper%d\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 ++) - 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 : + if (XML) + printf("xres%d" + "yres%d" + "units%s\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 (XML) + printf("%s\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 ++) - printf("\"%s\" ", attr->values[i].string.text); + if (XML) + 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 ++) - printf("\"%s\",%s ", attr->values[i].string.text, - attr->values[i].string.charset); + if (XML) + { + fputs("language", stdout); + print_xml_string(NULL, attr->values[i].string.charset); + fputs("string", stdout); + print_xml_string(NULL, attr->values[i].string.text); + puts(""); + } + 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 (i) - putchar(' '); + if (XML) + { + puts(""); + for (colattr = attr->values[i].collection->attrs; + colattr; + colattr = colattr->next) + print_attr(colattr); + puts(""); + } + else + { + if (i) + putchar(' '); - print_col(attr->values[i].collection); + print_col(attr->values[i].collection); + } } break; default : - break; /* anti-compiler-warning-code */ + if (XML) + printf("<<%s>>\n", + ippTagString(attr->value_tag)); + else + fputs(ippTagString(attr->value_tag), stdout); + break; } - putchar('\n'); + if (XML) + { + if (attr->num_values > 1) + puts(""); + } + else + putchar('\n'); } @@ -1176,10 +2688,10 @@ print_col(ipp_t *col) /* I - Collection attribute to print */ ipp_attribute_t *attr; /* Current attribute in collection */ - putchar('{'); + fputs("{ ", stdout); for (attr = col->attrs; attr; attr = attr->next) { - printf("%s(%s%s)=", attr->name, attr->num_values > 1 ? "1setOf " : "", + printf("%s (%s%s) = ", attr->name, attr->num_values > 1 ? "1setOf " : "", ippTagString(attr->value_tag)); switch (attr->value_tag) @@ -1252,6 +2764,187 @@ print_col(ipp_t *col) /* I - Collection attribute to print */ } +/* + * '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 (XML) + { + print_xml_header(); + print_xml_trailer(0, buffer); + } + else + _cupsLangPrintf(stderr, "ipptest: %s\n", 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 (XML) + 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(""); + puts(""); + puts(""); + puts(""); + puts("Transfer"); + printf("%s\n", + Transfer == _CUPS_TRANSFER_AUTO ? "auto" : + Transfer == _CUPS_TRANSFER_CHUNKED ? "chunked" : "length"); + puts("Tests"); + puts(""); + + 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("&", stdout); + else if (*s == '<') + fputs("<", stdout); + else if (*s == '>') + fputs(">", stdout); + else + putchar(*s); + + s ++; + } + + if (element) + printf("\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(""); + puts("Successful"); + puts(success ? "" : ""); + if (message) + { + puts("ErrorMessage"); + print_xml_string("string", message); + } + puts(""); + puts(""); + + 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); + } +} + + /* * 'usage()' - Show program usage. */ @@ -1259,20 +2952,902 @@ print_col(ipp_t *col) /* I - Collection attribute to print */ static void usage(void) { - fputs("Usage: ipptest [options] URL testfile [ ... testfileN ]\n", stderr); - fputs("Options:\n", stderr); - fputs("\n", stderr); - fputs("-c Send requests using chunking.\n", stderr); - fputs("-d name=value Define variable.\n", stderr); - fputs("-i seconds Repeat the last test file with the given interval.\n", - stderr); - fputs("-v Show all attributes in response, even on success.\n", - stderr); + _cupsLangPuts(stderr, + _("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")); exit(1); } /* - * End of "$Id: ipptest.c 7847 2008-08-19 04:22:14Z mike $". + * '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 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; + } + } + } + break; + + case IPP_TAG_BOOLEAN : + for (i = 0; i < attr->num_values; i ++) + { + if (!strcmp(value, "true") == attr->values[i].boolean) + return (1); + } + 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)) + 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); + } + } + break; + + default : + break; + } + + return (0); +} + + +/* + * End of "$Id: ipptest.c 9000 2010-02-24 06:29:38Z mike $". */ diff --git a/test/print-job-media-col.test b/test/print-job-media-col.test new file mode 100644 index 000000000..6c271979b --- /dev/null +++ b/test/print-job-media-col.test @@ -0,0 +1,39 @@ +# 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 media-x-dimension 10160 + MEMBER integer media-y-dimension 15240 + } + } + + 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/str-header.html b/test/str-header.html index a584063e8..84f0d9b73 100644 --- a/test/str-header.html +++ b/test/str-header.html @@ -1,10 +1,10 @@ - - - + + + - CUPS 1.4 Software Test Report + CUPS 1.5 Software Test Report