Graphics and Media • 56:20
The Common Unix Printing System (CUPS) forms the basis of the Mac OS X printing architecture. Hear how Mac OS X integrates the latest version of CUPS to extend the capabilities and performance of the printing system. Developers of advanced printing applications, printer drivers, and printer management software will not want to miss this information-packed session.
Speaker: Mike Sweet
Unlisted on Apple Developer site
Transcript
This transcript was generated using Whisper, it may have transcription errors.
Well, welcome, everybody. This is the last session of the day, and we're going to talk about Cup today. My name's Michael Sweet. I'm actually the guy behind just about everything in Cups. I have my own company. It's Easy Software Products. And Apple uses me and licenses our technology to make Mac OS printing work as well as it does. I want to start off by saying thank you. Everybody that's ever worked on printing in Mac OS X has given us plenty of feedback. The things that you're doing in printing on Mac OS X are incredible, and the envy of everybody else in the open-source world. So thank you.
To give some background on CUPS before we get into the new stuff that's in the leopard seed, we developed CUPS back in 1997. Basically, we were doing Linux printing and Unix printing for a long time and found that what was there was pretty lacking. You could spool a file and you might be able to do some filtering of that data, but you really didn't have any notion of a document or printer options, and each of the operating systems did their own thing. So there was no commonality there. As a solution vendor, there was just no way for us to support all those different operating systems. So in '97, we just started doing CUPS. IPP, the Internet Printing Protocol, was something that was just coming out. And so we decided to go with IPP and design a really state-of-the-art printing system for Unix. We provide CUPS under the GPL and LGPL. And Apple also licenses it, so you guys can do pretty much anything you want with CUPS. And if you go on the CUPS website, there's a lot of free stuff that you can add to the CUPS that comes with Mac OS X to do things like printer accounting and various other interesting stuff.
Now, if you look at the history of CUPS on Mac OS X, we joined the scene on 10.2 and Jaguar, and there's been a steady progression of new versions as new releases of Mac OS X came out. The Leopard C that you have has the equivalent of CUPS 1.2.1 on it, and I'm sure as we go forward, there'll be newer versions. You can get the latest Mac OS X version of CUPS on the CUPS website. That's something that we produce that Apple doesn't support, but it's available if you want to do some testing, even on Tiger. CUPS, it's worth mentioning, CUPS is the standard printing system on Linux, and it's available on all the commercial Unixes. It's available on the BSDs through the ports system. And just pretty much everybody that really needs to do any kind of printing uses CUPS now. And my company does sell CUPS support, CUPS consulting, driver writing services, and so forth. So if you need something beyond what you get from Apple, we're available to fill the gap.
Now CUPS itself is organized around a scheduler program. If you look in the process list, you'll see user Espen CUPSD. We chose this kind of architecture because it's simple and fast and very portable. On Mac OS X, it started on demand by the launch D service, unless you're sharing printers, in which case it actually has to run to share those printers. And the program itself is very lightweight 'cause it doesn't do a whole lot.
It keeps track of the printers that are on the system and the jobs that have been queued up. But when it actually goes to do any work, it runs other programs to do that for it. Because of various security needs for authentication and so forth, it has to run as a root user, but whenever it can, it runs the other programs, the helper programs, as an unproven user. And on Mac OS X, that's the LP user account. Your applications, whether you know it or not, are talking IPP to the scheduler. So when you go to print a file, It's an IPP request, print job, and it actually spools up the file for printing. Similarly, when you go to show the printer dialog and get the print settings, it uses HTTP to get the PPD file that's associated with that printer. And, you know, as an aside, the printers in Mac OS X and in CUPS use PostScript printer description files, whether it's a PostScript printer or not. It's a de facto standard description format for printers, in the industry. You use it for PostScript printers.
Why not use it for non-PostScript printers too? And we just display all the printer features from that. Thank you. From the architecture, you'll see an application can talk through Cocoa, through the Print Manager API, or to CUPS, and all of that layers through to get through to the scheduler using IPP and HTTP. Both the scheduler and the application use the CUPS API, and if you were to look at the scheduler code, you'll notice that most of the calls it's making are the same calls that your application would be making.
Now, once you submit a job for printing from the print dialog, it gets stored in a spool file on disk in the spool directory for the scheduler, and then it goes out to look what it needs to do to actually print the job. There are several programs that get run for a print job. They're kind of classified as filters, drivers, port monitors, which are something new in CUPS 1.2, and backends that actually communicate with the printer. It runs the programs it needs to get the document file into a format the printer will accept. And once it does that, your file gets actually printed. Once the job's been printed, it removes the spooled job file and moves on to the next one.
For security reasons, we run all the filters, drivers, and port monitors as the LP user, so they can't actually do something to the system. But the back ends sometimes do run as root, because they may need some sort of privileged resource. And we'll get into that a little bit later, is how you can control whether it's run as LP or as root.
Now if we show it graphically, an application submits a document and then CUPS runs a series of filters. So for a PDF document you might see CGPDF to raster or CGPDF to PS that's run to convert that into an intermediate format that the print driver can handle. The print driver is run for printers that need more processing than say a PostScript printer where it could take the PostScript data directly. And then the port monitor does any additional encoding for the interface that you're using. So for example, with a PostScript printer, you might use BCP or TBCP to encode the print data so you can print raw binary data. It could also be used for doing 1284 packet framing and so forth. All that gets piped into the back end, which then communicates with the printer, and the printer starts printing something out. Now in CUPS 1.2, we also have back channel support. So if the printer goes back and says, hey, something's gone wrong, or I'm low on ink, or the paper tray is empty, the back end can feed that data back to the port monitor and the driver. So either one of those can actually handle the back channel data and actually inform the user what's gone wrong.
Now, beyond the local printing scenario, printer sharing is very common. You have a laptop, you have a desktop machine, a wireless network, all that stuff at home. Or in the office environment, you have a centralized print server, and you have all the client machines you want to print to it. CUPS was designed from the ground up to make that simple. Previously, you'd have to manually add remote printers on a client machine. And if you have 1,000 client machines, you've got to do that 1,000 times. We didn't want that to be the user experience with CUPS. So from the very beginning, we've had this idea that a CUPS server, the scheduler, can simply share out its printers, and the clients will automatically see those printers. In CUPS, a server is just any system that's sharing one or more printers. So if you aren't sharing printers, it's not visible to the network.
What happens is the clients will forward the jobs that are printed on the local application to the remote system, wait for it to complete on the remote system, and then remove its local copy. So if something goes wrong on the server, your job isn't lost. It'll just get reprinted when that printer comes back up. And something that's really unique to CUPS is this notion of automatic load balancing and fail-safe printing. If you have more than one server providing access to the same printer or even different printers with the same capabilities, capabilities, CUPS can automatically merge those, or you can do it manually, so that you have a round robin printing approach, printer pooling, that when you print to a particular queue, it goes to the next available printer in that class. And if one of the servers goes down, it automatically switches to another server to get that job printed. So it's very popular among our enterprise customers. Obviously you don't see it too much in the home.
And to show it graphically, the scheduler on the client will run the IPP backend to communicate with the scheduler on the server and get the print job done. And then the scheduler on the server sends back a message to the client saying, "This job is printed," and the IPP backend then informs the scheduler on the client, "This job is completed. You can remove it."
Now, in order to find these printers, we actually have two different sharing protocols that are supported on Mac OS X. The first one's Bonjour. It's a lot newer, and it's available in Tiger. And basically, it allows you to do it on the cheap. You can advertise that you have a resource available, but until somebody asks for that resource, it doesn't actually clutter up the network with any packets. The other real advantage with the Bonjour sharing is it doesn't depend on any infrastructure such as a domain name server. So if you have a home system set up and you're calling it Mac Pro and you have your MacBook, you can look at macpro.local, and it doesn't matter what IP address has been assigned to it. It'll find it, whereas with a traditional managed network, you've got to know the IP address or the fully qualified domain name or that sort of stuff. So Bonjour is really great for the unmanaged network situation, and it's really great when you don't want to have a lot of network traffic. It's a default in Leopard, and please test it out. On the other side of things is our original CUPS protocol. It's what the Bonjour folks would call chatty in that it broadcasts periodically to say, "I have these printers available," and then expects the client systems on that network to pick up on that information and then make it available to the user. It's a default in Tiger. It's still available in Leopard if you need it. It's the only protocol that's supported on non-Mac OS X clients at this time. And we find it most useful when you have managed networks and large numbers of printers because the current Bonjour implementation doesn't scale beyond about 300 printers on a server. And I'll show this a little graphically. The Bonjour printer sharing, the client systems will send out a query, I'm looking for a printer, and then the server system's going to respond, I have these printers.
And then you'd see it in the printer browser and select the printers that you wanted to use. The CUPS printer sharing architecture is a little bit different, where the server system just announces, hey, everybody, I've got all these printers, and then expects anybody that's on that network to listen and to keep track of that information.
Now, when you're supporting non-CUPS printers, you're still back to that old, OK, now I have to point it at the server and set up the remote queue. We do support that, though, because we have a lot of customers that work with legacy clients. On the Windows side, you can print via IPP or Samba, the SMB protocol. Both methods require a Windows printer driver, and we do have a CUPS-specific driver for Windows available on the CUPS website.
And you use several different programs to access that. On the Samba side, you use CUPS@SMB as a command line utility or the new web interface to export your printers to the Windows clients. And for the Windows side, if you're going to use IPP, we actually have a free Windows client that you can download that will use IPP and that same CUPS driver to print.
Uh, for the Samba method, you'll see the Windows Print Service communicate with Samba via SMB, and then Samba via the CUPS API will talk IPP to the scheduler to actually get the job printed. It also does print status, printer, um, lists, and all that sort of stuff via that same API.
For a Unix client, you're going to use the LPD protocol. We have what we call a mini daemon program. It's CUPS LPD. It's normally run from xinetd in the open source world, and that's what you get with Tiger. But in Leopard, we're now using LaunchD, just the nice common server starter for Mac OS X. And basically, it handles all of the LPD protocol stuff and converts it into IPP for the scheduler. Unix clients will typically use an interface script or some other application-defined print driver and send text or postscript, and then the Mac system can interpret that and get it into something the print driver can print. Worth noting here is that the options, because LPD doesn't support passing of options, you have to specify them with the LP options command or in 1.2, the LP admin command so that the defaults are there for whatever you want those users to do. And again, a little graphic. Unix Print Spooler will talk via LPD to the CUPS daemon there for LPD. It will use the CUPS API to talk to the scheduler, get the job printed, show the printer status, all those sorts of things.
So CUPS 1.2 was released earlier this year, and a whole lot of new stuff. And I know past years I've been here in the printing sessions and said, it's just going to be out in a week. It's just going to be out in a month. Well, it's out now. And we've learned a lot from this whole release process. The number one thing is there were too many new features in 1.2 to get it out in a timely fashion. There's over 90 of them. And if you go on the What's New document, you'll actually see all of the different things that were added in. Some of the things are new to Mac OS X. Some of them were in Tiger already that we've merged into the standard cups tree. But it's interesting reading just to see all of the different things you can do now. We've done a lot of performance tuning with cups. Between I want to open the lid on my PowerBook and have it printing available immediately to just handling our commercial customers 10,000 printers, the whole thing just works a whole lot faster and scales a whole lot better. We have almost all of the new features in there. The only one that's not in 1.2 is the Kerberos support, and that is coming in 1.3. And I'll talk a little bit more about that later. Fortunately, everything is 100% binary compatible. So any applications you've done using a CUPS API directly or indirectly will continue to work without change. And as I mentioned before, we do have universal binaries available for Mac OS X Tiger. And that's stuff that we've done, not stuff that Apple's done. Those builds do not contain Bonjour support. So if you're looking for that, you'll need to look at the Subversion repository and not at the builds that we've done.
Now, as a user, there's two main things that you're going to see as improvements in 1.2. The first one is that printer sharing works a whole lot better. Every time you rebooted your system, you'd kind of start from scratch. Your shared printers would appear and disappear, and it just wasn't a great user experience. So you've added a cache to that that keeps those printers available, so you don't have that disappearing printer problem. But if you do change networks, you go to an internet cafe or something, then any of those shared printers from the previous network are going to disappear. On the printer settings side of things, we now support PPD files with multiple languages. So for you driver developers, this means you can ship one PPD to support 20 languages.
And you can have the same PPD support users with reading different languages. So if you have an office, somebody reads French, somebody reads English, somebody does German. You don't have to decide on a common one, English, just because that's the only one that you can all agree on. You can actually all have the language of your choice. The generic PostScript printer, PPD, that's included with the Leopard seed does include languages for all the supported locales.
And whenever you install a printer, you plug it in, it's now going to use the correct language and support all of them rather than just the default language. When you do the options in your driver, you can now provide custom options without writing a custom PDE. The crux of this is basically we have certain developers where you need a passcode or a type in option for a watermark-- and I'll show examples of those in a little bit-- that you don't just want to have a bunch of standard choices, you want to actually have the user type those in. So you can now do that, and the user will now have the ability to select that without having to go to a separate PDE panel.
Now, if you're an administrator, we've added a whole bunch of stuff for you. The biggest one, the number one that we kept getting requests for, was IP version 6 support. It's flung through the whole system. And the only thing that doesn't use IP version 6 right now is the CUPS protocol for browsing.
But if you use the Bonjour, you get IP version 6 there. We also added support for automatic SSL detection. So instead of having a separate port number for your encrypted versus non-encrypted traffic, you can now do it over the same port number. So you get the advantages of the automatic upgrade to encrypted status, whether you're on a web browser or in a CUP's client.
For printer sharing, we now support server-side defaults and timeouts. So when you're configuring your printers on the server, you can actually say, the default for the page label or for the job hold until is now this specific value. That gets out to all the clients, so they immediately will use that as well. Previously, you would have to run LP options on every system and hope that those options would be honored in all applications. The timeout allows you to specify a different browse timeout with the CUPS browsing protocol. And basically, before, you'd have to change the timeout in every client. Now you can just change it on the server to what's appropriate for that server. And the clients will use that timeout when they're figuring out when to get rid of a printer.
The last thing here on the slide is SNMP-based network printer detection. What's in 1.2 is the first attempt. We have a lot of feedback, and I encourage you to provide more feedback if you don't see your point being made in the bug database. But basically now it will find any printer that uses the host MIB and automatically show it in the web interface, in the GUIs, and on the command line when you want to find a printer. We're going to be updating it some more to deal with some edge cases and also to not advertise a printer via both Bonjour and SNMP. Because of that, we're looking at this as a supplement to Bonjour. All the printers don't support it, so we still want to give the user the ability to find their printers easily rather than going to the printer and hitting the test page on the printer to get that. The local device detection all works in with this as well. So basically any new printer that gets added on the network or on a local machine is detected by CUPS now.
So you saw the printer browser on the previous presentation if you were here. Basically, you can now see all the printers for individual protocols or for all protocols. You can filter and search and everything. This is all made possible by all of the infrastructure in CUPS to find devices.
Now, if you're a power user or an administrator that has to manage a lot of different systems, you may have looked at the Web Interface. It's pretty much the one that everybody depends on in the open-source world, but it's something that's available if you're gonna want to use it. I'm gonna show you some of the new features in the Web Interface.
Big things, we have new online help systems, searchable, and you can extend it if you like. All of the pages are searchable, pageable, and you can change the order of things. Because of the new network printer discovery support, we can now support things like add this printer, and it will add the printer.
And over the years, we've gotten the same question from many different people. How do I turn on debugging? How do I allow people to print to my system? How do I enable sharing? Those are now just check boxes that you can do, and will automatically set those things up. And finally, we're now integrated better with Samba. So instead of having to use the command line, you can do it all from the web interface, and you get all the same benefits.
Now, the help system is pretty basic. You have a search bar at the top. You have a topic section on the side. And every time you go into a document, that expands and shows you the current documents table of contents, the current section, what documents are in it, and all the sections that are available.
All of the pages for the printers, jobs, and classes are paged and searchable. So you see a search bar, a sort order and paging bar, so the next, previous, and show me ascending or descending, and then the content area. On the administration page, we've reorganized that completely, and you can control your printers, classes, and jobs on the left, and on the right is all the server controls.
Now, the new button for the printers is a button that says export printer to Samba. And basically, that's the equivalent of the CUPS add SMB command, but through the web interface. Gives you a nice little list of printers, and you can export all of them if you'd like.
There's direct access now via HTTP to the CUPSd.conf file and all the log files. They are also access controlled, so if you want only people that have certain privileges, they will get a challenge for the password and all that stuff, and you can limit it to only your network or particular IPs if you would like to do it that way. Right underneath that is the simple settings, and right now there's five items there. Just to run through them quick, show the printers that are available on other servers. That's a default. Share the printers that I've got. Allow other users to cancel your jobs. Allow remote administration.
So if you want to set up a bunch of servers and have them allow remote administration, you just check that. And then that's the only change you need to do. And then the last one, enable debug logging, allows you to track down problems more easily. And if you're doing tech support for users and they don't know why things aren't working, you can just say, click on this and then we'll look at the log file.
Now, underneath the printers there, you have the standard operations, but then it also shows you when it finds new devices. And the way it does this is it goes out, sees what devices are available, and sees what devices have been added, and then gives you the list of stuff that hasn't been added that actually has a make and model associated with it. Um, each one will have a little button that says, "Add this printer." When you click on that, it takes you right to the make and model, uh, selection, uh, page, and it'll preselect the driver if you have it available. It chooses the best match for the printer. You click "Add Printer," and you get your printer page. So it's very quick to add network printers now. Similar experience in Mac OS X, and we're trying to have feature parity between the GUI, the command line, and the web interface. So I think we're getting a lot closer with that.
As you notice in here, the job information for a particular printer is now searchable and pageable as well. There aren't any jobs in this particular screenshot. And we've also added the ability to show the completed jobs, the active jobs, and all jobs in the system. So as soon as you click on "Show Completed Jobs," it'll show you from the most recent to the least recent. You click on "Active Jobs," it shows you the next job it does so as well.
Now, we've had a lot of requests from people saying, I want to not stop the printer when something goes wrong talking to it. So we've added per-printer error policies. This feature is probably going to be expanded again in CUPS 1.3. We have three basic policies right now. You can stop the printer, the default, and that's what we did before. You can tell it to retry the job, and the way that works is just like with a fax queue. It'll keep retrying for a certain number of times at a certain interval, and when it finally can't get to the printer, it'll give up on it and cancel the job. Or you can just say, "Cancel the job right away. I don't want the queue to fill up." So that's available through the web interface. It's available through the command line, and you can set it to any one of those three right now. There'll be more later.
Another common complaint has been that you can't configure what individual users can do. Over the years, people have gotten in the habit of putting in location lines in their cupc.conf and saying, OK, for this web interface task, to start a printer, I want to have this particular set of permissions. And the problem with that is only applied to the web interface. It didn't affect the command line or the GUI. So what we've done is we've come up with a replacement that mechanism called policies. And what you basically do is you create a policy with a name, and then you use all the same sort of location-based access control lines-- allow, deny, require, and so forth-- for individual IPP operations.
So you can say, I want all users to be able to print and start and stop printers, but I don't want them to be able to add a printer. Now, each printer can have its own policy, and then there's a default policy that's used for the server-level operations, such as adding and deleting printers.
Now, we have a little sample policy, really simple. Only thing we want to do is limit send document to the person that actually created the job. So we don't want somebody piggybacking on somebody else's jobs. But other than that, they can do just about anything they want. So you put this in the CUPSD.com file, which you could do through the web interface, and then select that policy for that particular printer, which you can also do from the web interface.
We get a lot of questions on the CUPS forums about the log messages that they're seeing in the access log in particular. Why do I see a post every five seconds? Uh, you know, any number of things. And you just don't know what's going on there. Well, we extended the access log format a little bit to add the IPP operation and status code from that operation to any posts that are IPP operations. So now if you look in your access log, uh, Git default, um, and, uh, Git printers and so forth, and whatever status they return. So you know kind of what's going on in the system without having to delve into the error log file.
If you're supporting LPD clients, we now support banner pages, and multi-file LPD jobs are now created as a single CUPS or IPP job rather than a series of individual ones. That should make things work a whole lot more consistently within your environment. And that way, too, you don't have people's jobs getting mixed in with others.
And if you're trying to track jobs on multiple servers, we've added two new attributes to handle that. One is the job UUID attribute. It's UUID as defined by the RFC. And... Basically, it gives you a unique ID to track that job throughout the network, over the internet, anywhere the job goes, it's included in any transactions. The other attribute's the job actual printer URI. And the difference between that and the job printer URI is that it actually corresponds to the printer that printed the job versus printing to a class, and then it gets sent off to some other printer or server.
For you CUPS developers, general improvements in all of the APIs, they're all now thread safe. We added thread safety fairly late in the 1.2 development process, but it's been in various states, in Tiger as well, in 1.1. And basically, now whenever you're doing a threaded application, you can feel pretty safe that you're not going to have any issues. The only thing you have to be careful about is if you're sharing data structures between threads, we don't guarantee that thread safety just for function calls and using your own connections and so forth. For URIs, we found that every release we would come out with a new rev for the URI APIs. And we finally came up with a generic enough API that will work for all special cases that we could come up with.
So you want to look at the HTTP assemble URI and separate URI APIs if you're going to be dealing with printer URIs in particular. They handle all of the internationalization issues with doing percent encoding for international characters in the URIs, any specific issues with encoding for you. And when you pull them apart, you can also specify that you want certain parts of the URI encoded or decoded as needed. They also support some error checking. So if you have a URI you're not sure about, you can use the separate URI API to validate that URI. And we use that within CUPS pretty extensively. There's new address APIs to handle all the different address formats.
Previously, we just did IP version 4 throughout. And it was pretty limiting. So we came up with a generic address structure that encapsulated all the formats that we support and the future that we could add. So if you're doing any kind of address manipulation with CUPS, use these APIs. They'll save you a lot of time. They handle IP version 4, version 6, and domain sockets right now. And if in the future we come up with some other network protocol that we need to support, that'll get rolled into that without any changes to your code. We're also in the process of making the HTTP type structure private. In the 1.2, it is still available, but it's historically been marked as a private structure, but just in the public header. Because of the changes we had to make for large file support, while we've been able to keep the structure binary compatible for application developers, as we go forward, we want to make sure that you can just keep coding to the interface and not to the structure. So there's new accessor APIs for all of the data that's in the connection structure. Use those instead of accessing it directly. We've had some problems on the open source side with that, but I think it should be pretty well resolved now. On the IPP side, there's new convenience APIs for creating attributes and requests. If you're doing a lot of attribute creation or request creation, you'll probably find that using those new functions will save you a lot of code. The IPP new request function is part of that. And when we switched to using that within the Cup source we cut down about 1,200 lines of code. So a pretty significant savings. One of the nice things in CUPS 1.2 is now you get an actual error message along with the status code. That's exposed with the CUPS Last Error String API. So any time you do an IPP request, it will set the CUPS Last Error and the CUPS Last Error String value, and you can use that rather than trying to fish through the attributes to find the status message attribute and display an actual error message to the user. Now instead of just "client error not found," you're gonna see "printer foo doesn't exist."
IPP notifications are something that the printer working group has been developing for quite some time. They finally got standardized last year, and basically it was one of the big features that we wanted to get into CUPS 1.2, because it gets away from polling for status to notify me when something has changed.
Excuse me. The way it's implemented in CUPS is that we have a series of notifier helper programs that are run to deliver any event messages to the recipient. We include an email notifier with CUPS 1.2. But because in the Mac OS world, you're typically using some sort of a POP or IMAP account, it's not all that useful unless you have your own mail server. There's a mailto.conf file that you can look at that defines all of the configuration options for that. Once it's configured, it works really well. Because there's no way to use that standard email notification mechanism, there's no user interface exposed in Mac OS X. But a PDE can add the notify events and notify recipient URI attributes in your print settings to actually get a notification created with the print job. This might be used for communicating with your own desktop application that is providing some additional feedback to the user to do manual duplexing or something of that nature. In order to support notifiers, we have two APIs, Notify Subject and Notify Text. They give you a standard message that you can feed to user, based on an event message. And that, combined with writing a little notifier program that goes in the directory called Notifier, you can actually have your own notifiers communicate with the user in various ways-- instant messaging, paging, whatever the case may be.
For the PPD API, and that's now more exposed in the top levels, there's a new function to handle the multi-language PPD files. You run PPD localize, and it localizes the PPD file to your current language preference. And we decided on using UTF-8 throughout because it's nice and compatible with the ISO Latin one and so forth that's normally used in the PPD world. And it's compact enough for what we need it for. For the custom PPD options, there's some new functions to access those. We modeled it off of the custom page size mechanism that's already present in the PPD spec. And you can do integers, reels, curves, dimensions, strings, passcodes, and passwords. Some of those are new. The passcodes, passwords, and curves are nonstandard extensions to the Adobe spec. but basically allow you to have different kinds of input. The curve is just a standard power curve that you could drag and have the user select that way. And then the passcodes and passwords are non-visible text fields, passcodes for numeric stuff, passwords for alphanumeric. What we're recommending to developers is use these in conjunction with standard options.
So for example, a watermark option, you might have draft, confidential and so forth standard options, and then provide a custom option where they can enter their own text. There's new APIs to access the options and the parameters. And each of the options can have one or more parameters associated with it. You'll see that in a sec.
Now, here's an example of a custom option that uses PGL to implement a passcode feature on a printer. Now, as you can see, we have the normal option code in the PPD file for that passcode option, and there's four standard options-- none for no code, and then 1-1-1-1, 2-2-2-2, and 3-3-3-3.
Obviously, users don't necessarily want to use those passcodes because they're not particularly secure, and if everybody's using the same one, then what's the point? So you add the custom JCL passcode option in there to specify the command to run, and if you notice in there, there is a backslash 1 in that code. That's used to substitute the value in for the PGL option. The param custom JCL passcode line just gives you the parameter for this particular option. Since this one, we just need one option. We just have one line.
In code, you just pass it through. It's the option name equals custom.value. So if you have 8675 for the passcode, you'd use JCL_PASSCODE equals custom.8675. And in your CUPS API, you'd add the option or use parse options to grab out a string, say, from the command line and put that into an option string, which then gets passed into a print job. Similar things happen on the print manager side.
For a PostScript custom option, it works a little bit different, because with PostScript options, the values actually get pushed on the stack, and then the code gets executed to pull those options off the stack. It's the same way that the custom page size works, and we just decided to stick with that to be consistent. Here we have a watermark option. You have none and draft are the two standard options. And then you have the custom code, which will pull the string off of the stack and put it into a cup string one page attribute. And then the parameter for that is a text string from 0 to 32 characters.
Again, we use the option name equals custom.value. If you have a value that contains a space, like top space secret, you'd put the value in quotes. So watermark text equals, quote, custom.top space secret, quote. And again, in the application code, it works exactly the same, including the single quotes around the value, and just pass that through in the print job.
Now, a more complex example, and, you know, this is kind of contrived, but say you have a control to control the overall gamma and density of the output to make it lighter, darker, and so forth. You have three standard options here, and then the custom page size, custom code here actually pulls two values off of the stack. We define two parameters. One's called gamma, and one's called density, and the index 1 and index 2 defines the order that they're pushed on the stack. For multivalued options, you actually use curly braces around it, and then you use the named parameter. So you'd use gamma density equals-- gamma equals 1.0, density equals 0.5, and curly braces to specify that compound value. Again, same thing on the CUPS code.
If you're developing a printer driver or a back end that talks to a printer, you can now do back channel data. And the way we've implemented it is as a non-blocking pipe between the back channel and the filters upstream. There's two functions to actually access this information. Back channel read reads the data from the back end into the driver or filter, and back channel write writes it from the back end to the driver or filter. There's a timeout in there, so you can say, if I don't get a response back within one second, then this printer doesn't support back channel data, so I'll use the unidirectional mode of my driver.
If you're doing anything with PostScript or JCL options in your own drivers, there's a PPD emit JCL end, which handles any cleanup PGL that needs to be put out for a particular printer. And then the emit string, which is a more general purpose function for actually collecting all of the options for a particular section and putting them into a string that then you can put in memory or send out to a file or send out to the printer.
We use this with a new PostScript filter in CUPS to better support different page layout options and get things out to the printer correctly. Thank you. If you're doing a raster driver, we've expanded the amount of information that's put in the page header, largely in response to the Gutenprint folks, but this will be useful for everybody, I think. There's a borderless scaling factor attribute that's in there that corresponds to the scaling factor that was used for a borderless print. That comes from Tiger and has been forwarded into the raster format, so now you don't have to guess at what value was used. It's in there. Similarly, we've added floating-point page sizes and imageable areas so that if you have a page size that is not an integral number of points, you can actually get the actual dimensions at a much better resolution. And if you have letter and letter full bleed and the sizes are the same, well, you can get the size name now. It tells you it's letter or letter.fullbleed. There's marker type and rendering intent string options so that you can control that in your driver. You're going to be using a particular set of ANCs, or you're using a particular rendering model. That information can be passed through and would be passed through from a client as well. So you don't have to depend on a PDE for that. And then there's general purpose integer, real, and string attributes that you can use for anything.
In order to support this, we have three new APIs. The first one is most useful if you're doing a RIP. It's CUPS Raster Interpret PPD. It takes the commands and stuff that are in the PPD and the options that the user specified and generates a page header from that that you can use. It also has a callback interface so that if the user is asking for something that the RIP doesn't support, you can say, hey, wait a minute. I need to fix this. And the interpretPPD function then handles that situation for you. The rasterReadHeader2 and rasterWriteHeader2 functions do the new CUPS raster format header so that you get all of the extended page attributes. If you don't use these, the old APIs, readHeader and writeHeader, automatically handle expanding and dropping the data that you don't need.
Something new in CUPS 1.2 is the port monitor interface. Previously, you'd have generic filters, then a print driver filter, and then talk directly to the back end. And if you wanted anything special to happen between that driver and the back end, you had to write a new back end. Now we have a port monitor interface that sticks between the driver and the back end. So that if you need to do any special protocol conversions, such as TBCP or BCP or 1284 packet encoding or anything of that nature, you can put it there. I also recommend if any of your users do any kind of raw printing, that you use this to do printer accounting, ink monitoring, that sort of thing, there rather than in the driver because it'll give you a better user experience. In order to support different port monitors for different interfaces, we have a new attribute you can specify in the PPD, CUPS port monitor. And basically in this example here, you can say when I'm talking via socket connection, I need to use TBCP because it isn't an 8-bit clean channel. But when I'm going via USB, I don't need anything. And we have TBCP and BCP port monitors in CUPS. Thank you.
When you're running as a back-end, previously you always ran as the root user. We've changed that in 1.2. It's probably the only incompatible change from a program standpoint. Basically, if the back-end has world execute privileges, it gets run as LP. If it doesn't, it gets run as root. So if you're shipping a driver right now or a back-end that needs to run as root, just change the driver to have mode 700 in your package, and that will work for both tiger and leopard.
Um, we also now only run the back end once for the entire job. So previously, if you had selected a banner page to be printed with your job, you'd run the back end once to print the banner page and run the back end a second time to--to print the actual document. Um, what could happen then is if somebody else was also printing to that network printer at the same time, you could get your banner, then their print job, and then, uh, your--your print job after that.
So we now just run it once, and that one backend handles the entire print data stream for the whole job, so you won't have that problem anymore. But you might have issues if you're supporting advanced finishing features where the printer itself interprets one continuous print stream as a whole job and then tries to staple it, punch it, fold it, and all that sort of stuff. So just keep that in mind if you have any issues with that. We also now have predefined exit codes for backend. Previously, you returned zero if it was successful, one if it's failed. That hasn't changed, but now that exit code one means use the default error policy. There's also exit codes to abort the job, stop the printer, retry the job, or authenticate the job, which allows us to support proxy authentication without Kerberos support in 1.2. There's a header file, cup/backend.h, that handles all of that for you. Just include it, and then you have you can use when you're exiting or returning a value.
The backends, when you're advertising your device, you can now include the 1284 device ID in your advertisement. This allows for better automatic driver selection. We know that if a printer has a certain device ID, it corresponds to this exact driver on the system. So I encourage you, if you're doing your own backends, add support for that if you can. All of the standard CUPS backends do that now.
And instead of getting a static snapshot of what the devices were when you booted the system or when you first requested the list, we now run the backends every time somebody asks for a list of devices. So in the web interface, you go to the admin page, ask for the devices. You go to add a printer in your printer browser, it asks for devices. So keep in mind that your backend might be run more frequently in the discovery mode than originally. Because we don't keep track of the devices that are available on the system beyond when somebody asks for it, we now only validate that the URI is compliant with the corresponding RFCs, and the scheme is registered as a back end.
We've had requests from many driver developers, including GutenPrint folks again, for supporting things other than static PPD files. We have something new in Cups 1.2 called the Driver Interface, and it basically allows you to provide a program that lists the supported devices for your driver, and then when asked, it can actually produce a PPD file that can be used by the system for that particular device. The print queues still have a static PPD associated with them, So you can't use this to dynamically control what options are available all the time, but it can give you a snapshot when you first add the device. If you're going to update your PPD, you can do that from your port monitor, your backend, or your driver, and enable certain options. It's got the duplexer now or it doesn't have the duplexer and that sort of thing. What we're going to use it for in the GutenPrint drivers is to provide virtual drivers. Basically, the GutenPrint drivers are capable of generating their own PPD files already. We've been doing that for many years now. But generating static files that can then be distributed, now we'll be able to do a driver interface that lists all the drivers in there and then just provide the one that you're actually going to use. So it'll save 50,000 files and many megabytes of disk space that way. You can also use it for grabbing PPD files over the network and doing all sorts of dynamic stuff. It's a very general-purpose interface, and we look forward to seeing what people do with it. There's a helper program called CUPS Driver D. You'll see whenever somebody's asking for the list of PPDs on the system, and it's now responsible for handling the PPD database that used to be managed by the scheduler. So you'll notice that things moved around a little bit that way.
So for CUPS 1.3, which is the next major release, that's where we're gonna get Kerberos support in there. It's scheduled for release in October. So I know I say sometimes, we're going to have a release out in a few weeks or a few months. We've actually changed our whole development process from the lessons we learned in 1.2 to say, we're not gonna try to lump in 90 new features into a minor release. We're gonna do one or two and maybe a few of the little ones there but we get them out more frequently and there's less code churn between them. So as you're upgrading, you're not going to notice sudden huge changes that are going to completely disrupt your lives. So we're going to get the 1.3 out in October and we'll have the Kerberos support. There's actually one of the Samba developers that's doing it as a Google Summer of Code project for us and he did Kerberos support in Samba. So we're very confident that's going to come off very well and that you can actually look at his progress in the CUPS subversion repository. So we want to get your involvement.
We have a web page that handles the bug reports and feature requests for CUPS. And there's a roadmap page there. So if you're at all interested in shaping the future of CUPS, please go to our site. Please provide your feedback. If you're running into problems, feel free to file bug reports with us. If it's something that's really Apple specific, definitely file it with them, but we're interested in knowing about problems as well. We can just keep working like we have been for the last four years and make CUPS even better. - Okay. If you're familiar with the CUPS book that's currently out, it's got a big squid on the front and there were some various allusions in that to printing.
We're coming out with a new CUPS book, something that we're publishing, and no more squids. Just nice clean cover with the CUPS mascot. It's going to cover all of the new stuff in 1.2 and beyond. It's also going to cover the CUPS DDK, ESP Go script, Gutenprint, and so forth. And we've organized it differently so that it's more about, "I want to get this done, so here's the steps to get that done, and then here's why these steps work."
So it's a much more effective, I think, manual for learning how to use CUPS than the previous book. That's also available in October. CUPS resources, you have the website, the forms and mailing lists are available there, the CUPS books are available there, the feature request page is there, and the source code is there. So you can go and download the source code, download the universal package for Mac OS X Tiger, and just have fun.
If you're doing something for Mac OS X specifically, there's the Apple bug reporting page. Make use of it when you find a bug. We can't fix bugs we don't know about. And the printing list, if you have questions, especially if you're developing software, this list is great. I'm there, and a lot of the Apple developers are there, helping out, answering questions about the printing system and how to do things. And finally, the open source printing page, that's where you get the actual copy of this CUPS source code that's included the particular Mac OS X release. And if you want to rebuild it yourself and play around with it, start there because there are differences between the standard CUP software and CUPS.org and what Apple provides, mainly as we're syncing things up. They're a little bit further ahead than we are.
As a developer, there's online documentation now. All the APIs are documented with online help on the web interface, so bookmark that. And we have a driver developer kit. If you're writing a printer driver for CUPS, this is what you should be using, whether you're using it for your actual printer driver or just generating the PPD files. We have utilities now to actually merge multiple single language PPD files into a single multi-language PPD file.
So if you're even not gonna use the PPD compiler the DDK, but you want to do stuff and support Mac OS X more quickly, use this utility. It'll save you a whole bunch of time, and you can move on to more exciting things. There's standard drivers for PCL and Epson printers in the DDK. If you have a multifunction device that just uses one of those standard languages, you can use those drivers freely. They're GPLed and support them without a whole lot of work. You just have to write a little device description file and it'll create a PPD for you and you'll be up and printing. For us, it takes the driver development time from months to a few days.