2

I am attempting to listen for printer state changes (e.g. paper jam, paused...) The following code gives a "Bad notify-recipient-uri" response, then locks on ippReadFile and does not release when the printer is paused/unpaused.

int main()
{
    http_t *http = httpConnectEncrypt(cupsServer(), ippPort(), 
    cupsEncryption());

    ipp_t *request = ippNewRequest(IPP_CREATE_PRINTER_SUBSCRIPTION);

    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
        NULL, "ipp://localhost:631/printers/Generic-text-only");
    ippAddString(request, IPP_TAG_SUBSCRIPTION, IPP_TAG_URI, "notify-recipient-uri",
        NULL, "cups_test://");
    ippAddString(request, IPP_TAG_SUBSCRIPTION, IPP_TAG_KEYWORD, "notify-events",
        NULL, "printer-state-changed");

    ipp_t *response = cupsDoRequest(http, request, "/");

    while (1)
    {
        ipp_state_t state;      
        ipp_t *event = ippNew();

        while ((state = ippReadFile(0, event)) != IPP_DATA)
        {
            printf("%s\n","Got Data");
        }

        printf("%s\n","Repeating");
        ippDelete(event);
    }
}

After sifting through the printers attributes I found a notify-schemes-supported attribute set to "dbus". I was not able to change the attribute with IPP_SET_PRINTER_ATTRIBUTES. Any ideas on how to get this to work?

Kyle Berezin
  • 597
  • 4
  • 20
  • I'm not that familiar with cups, but I noticed you are passing file descriptor 0 as the first argument to `ippReadFile(int fd, ipp_t *ipp)`. File descriptor 0 is standard input. Is there a reason to expect anything to appear on your program's standard input? Otherwise, it is not surprising that it would hang, as you described. What if you used `ippRead(http, event)`? – MassPikeMike Apr 26 '17 at 02:10
  • `ippRead(http, event)` does not lock so it just loops infinitely. I got some if this code from the https://github.com/apple/cups/blob/master/notifier/testnotify.c and https://github.com/apple/cups/blob/master/test/create-printer-subscription.test . It is entirely possible that I am going about this completely wrong, though I don't think that is the case. – Kyle Berezin Apr 26 '17 at 22:50
  • According to a book I have on cups, CUPS: Common UNIX Printing System by Michael Sweet, "Notifiers provide a way for CUPS to notify users or programs about state changes in the server, a printer, or a job. The ippget notification scheme is implemented internally in the CUPS server, whereas all other CUPS notifiers are external programs that receive events on their standard input files." – Kyle Berezin Apr 26 '17 at 23:43
  • "receive events on their standard input" sure makes it sound like your program should be getting something on standard input, so maybe you are on the right track. Good luck. – MassPikeMike Apr 26 '17 at 23:53
  • I'm giving up on this. I've wasted almost a month on this. It is amazing how it only takes 3 lines of code and some googling to figure out how to get printer states, but god forbid you want to lock against it. I'm going make a program that just asks for its state every 10 seconds then I will post that as the answer. – Kyle Berezin Apr 27 '17 at 01:14

1 Answers1

2

A very basic example that does not require any C code is to use ipptool against the create-printer-subscription macro to subscribe an rss URI to the events. This is the approach illustrated by pyipptool.

ipptool usually ships with CUPS, but for modern Ubuntu versions, you may need to install cups-ipp-utils.

First, create an HTTP socket listener that can receive the events...

python -m SimpleHTTPServer 9876

Second, send the events to the socket listener.

ipptool -d recipient=rss://localhost:9876 ipp://localhost:631/printers /usr/share/cups/ipptool/create-printer-subscription.test

Finally, trigger an event such as disabling the printer.

cupsdisable PDFWriter # or some valid printer name
cupsenable PDFWriter

The rss:// URI scheme will use PUT commands against the HTTP socket server. Since SimpleHTTPServer does not have built-in support for the PUT command, 501 errors will occur. You will have to customize the HTTP listener to process these commands, but you will see the events fired.

Note, the default create-printer-subscription macro is configured to send events for printer-config-changed and printer-state-changed but not printer-queue-order-changed which can be adjusted by making a copy of the macro and editing it.

Also, this will leave the subscription active for the default lease duration (defined as 86400 in the source, which should be a day). An additional parameter notify-lease-duration of zero can be specified for an indefinite subscription.

Community
  • 1
  • 1
tresf
  • 7,103
  • 6
  • 40
  • 101