How do I add a System V filter using the cups API?
Pregunta
I need to programmatically add a printer to cups that has a System V filter installed. Right now I am using the following code to create the request to add the printer:
pstRequest = ippNew();
pstRequest->request.op.operation_id = CUPS_ADD_PRINTER;
pstRequest->request.any.request_id = 1;
ippAddString(pstRequest, IPP_TAG_OPERATION, IPP_TAG_CHARSET, "attributes-charset", NULL, "us-ascii");
ippAddString(pstRequest, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, "attributes-natural-language", NULL, "en");
ippAddString(pstRequest, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser());
ippAddString(pstRequest, IPP_TAG_OPERATION, IPP_TAG_URI, "device-uri", NULL, szUri);
ippAddString(pstRequest, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, szPrinterUri);
ippAddInteger(pstRequest, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state", IPP_PRINTER_IDLE);
ippAddBoolean(pstRequest, IPP_TAG_PRINTER, "printer-is-accepting-jobs", true);
For the sake of conversaion:
szUri = "serial:/dev/pts/12?baud=2400+bits=7+parity=none+flow=none";
szPrinterUri = "ipp://localhost/printers/myptr";
This appears to correctly add the printer to the cups system because I can then send print to it using the following command:
lp -d myptr test.print
My first thought was to just copy the file that I wanted to use as the filter into the /etc/cups/interfaces
directory and call it myptr
. I did this, gave it the correct user, group, and permissions, and it didn't seem to work. I even tried sticking a sleep 60
at the front of the script and it never showed up in ps
.
I've tried adding the printer using lpadmin
as follows and it works correctly:
lpadmin -h localhost -p myptr2 -v "serial:/dev/pts/12?baud=2400+bits=7+parity=none+flow=none" -i /tmp/my.serial.filter
I have to call cupsaccept
and cupsenable
afterward, but the printer works and it sends the print through my filter. lpadmin
correctly copies the my.serial.filter
file from /tmp
into /etc/cups/interfaces
and names it myptr2
, just as I did in my program, and, for the life of me, I cannot find any reference to the filter in any of the cups configuration files that makes me think I'm missing a step. Nevertheless, the myptr2
printer that I add with lpadmin
works correctly and the myptr
printer that I add using the API, while it does print, does not print through the filter.
Among the various Google searches I have made, I have read through the CUPS Implementation and the HTTP and IPP APIs Documentation, and the closest that I have come to was that, in the former, there is a comment for the CUPS-Add-Modify-Printer Operationthat reads:
The CUPS-Add-Modify-Printer request can optionally be followed by a PPD file or System V interface script to be used for the printer. The "ppd-name" attribute overrides any file that is attached to the end of the request with a local CUPS PPD file.
This led me to try using
ippAddString(pstRequest, IPP_TAG_PRINTER, IPP_TAG_NAME, "ppd-name", NULL, szFilter);
with szFilter set to both "/tmp/my.serial.filter"
and "/etc/cups/interfaces/myptr"
(in separate tests, of course), but to no avail.
Can anyone tell me where I might be going wrong?
Solución
Okay, I got ahold of the source to lpadmin from the cups source repository and the answer was much easier than I was trying to make it. Apparently, I did not include enough of my source in the initial posting. After the code snippet from above, I was calling the following:
pstHttpServer = httpConnectEncrypt("localhost", ippPort(), cupsEncryption());
pstResponse = cupsDoFileRequest(pstHttpServer, pstRequest, "/admin/", NULL);
ippDelete(pstResponse);
httpClose(pstHttpServer);
(with applicable error checking, of course)
The answer to my question is in the NULL
pointer that I was passing as the fourth argument to cupsDoFileRequest
. As noted above, "[t]he CUPS-Add-Modify-Printer request can optionally be followed by a PPD file or System V interface script." I hadn't tied the two together, but that sentence refers to the fourth argument of cupsDoFileRequest
in which, if I place the path of my filter, "/tmp/my.serial.filter"
, the request succeeds and my.serial.filter
gets correctly copied into /etc/cups/interfaces
as myptr
, after which all of my print to myptr
goes through the filter as expected.
Thus, the final solution is to change the pstResponse
line above as follows:
pstResponse = cupsDoFileRequest(pstHttpServer, pstRequest, "/admin/", "/tmp/my.serial.filter");