OpenPrinting / libcups

OpenPrinting CUPS Library Sources
https://openprinting.github.io/cups/cups3.html
Apache License 2.0
35 stars 17 forks source link

Get a 1024 error on send-document after successful create-job #77

Closed jpmsparks closed 7 months ago

jpmsparks commented 7 months ago

Getting a 1024 error from cupsDoFileRequest after a SEND_DOCUMENT ipp request - this after successfully doing a CREATE-JOB.

Steps to reproduce the behavior - this is the code I used to recreate the issue. You would just have to change the printer pointer and filename to reproduce. After I ask for a status code, I get a 1024 error (BAD_FORMAT).

include "C:\Users\778220\GitRepos\CupsTest\cups\cups.h"

int main() { ipp_status_t status; const char filename = "C:\Temp\mytest.txt"; const char filetype = "text/plain"; const char printer = "pd3b005"; char szUri[150] = { 0 }; strcat_s(szUri, sizeof(szUri), "ipp://"); strcat_s(szUri, sizeof(szUri), printer); strcat_s(szUri, sizeof(szUri), "/ipp/print"); http_t http; ipp_t request, response; http = httpConnect(printer, 631, NULL, AF_UNSPEC, HTTP_ENCRYPTION_IF_REQUESTED, 1, 30000, NULL); if (http == NULL) { printf("Could not connect to: %s", printer); return 0; } request = ippNewRequest(IPP_OP_CREATE_JOB); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, szUri); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, "778220"); ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "media", NULL, "na_letter_8.5x11in"); response = cupsDoFileRequest(http, request, "/ipp/print", filename); status = ippGetStatusCode(response); if (status != IPP_STATUS_OK) { printf("Bad response: %d", status); return 0; } int Job_id = ippGetInteger(ippFindAttribute(response, "job-id", IPP_TAG_INTEGER), 0); ippDelete(response); request = ippNewRequest(IPP_OP_SEND_DOCUMENT); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, szUri); ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", Job_id); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, "778220"); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", NULL, filetype); response = cupsDoFileRequest(http, request, "/ipp/print", filename); status = ippGetStatusCode(response); if (status != IPP_STATUS_OK) { printf("Bad response: %d", status); return 0; } ippDelete(response); }

Expected behavior

The code is essentially straight off the "How to use the Internet Printing Protocol" document. I expected an IPP_STATUS_OK status code. When I submit the same document to PRINT_JOB, it prints fine.

Screenshots If applicable, add screenshots to help explain your problem.

System Information:

Additional context Add any other context about the problem here.

michaelrsweet commented 7 months ago

OK, so I'm guessing it is the filename that is causing the problem - C needs backslashes escaped ("\"), or you can use a forward slash (even on Windows) to avoid this.

IPP status codes are normally shown in hexadecimal, so 1024 is 0x400 which is "client-error-bad-request". You can use the "ippErrorString" function to convert the status code to a readable string...

jpmsparks commented 7 months ago

Michael,

The original code has the filename with double "\" backslashes already - I added the updated filename on the bug report and did not double escape by error. The first cupsDoFileRequest returns successful with the same filename. Been a perplexing issue as the print-document operation works fine.

jpmsparks commented 7 months ago

Michael, here is the CREAT-JOB, SEND-DOCUMENT code that is failing. The CREATE-JOB request returns IPP_STATUS_OK, but the SEND-DOCUMENT request returns a 1024 error following the cupsDoFileRequest api. Its perplexing as using the same printer the PRINT-JOB request works just fine. To test you'd just have to change the filename pointer and the printer pointers.

include "C:\Users\778220\GitRepos\CupsTest\cups\cups.h"

int main() {

ipp_status_t status;
const char* filename = "C:\\Temp\\myprinters.txt";
const char* filetype = "text/plain";
const char* printer = "pd3b005";
char szUri[150] = { 0 };
strcat_s(szUri, sizeof(szUri), "ipp://");
strcat_s(szUri, sizeof(szUri), printer);
strcat_s(szUri, sizeof(szUri), "/ipp/print");
http_t* http;
ipp_t* request, * response;
http = httpConnect(printer, 631, NULL, AF_UNSPEC, HTTP_ENCRYPTION_IF_REQUESTED, 1, 30000, NULL);
if (http == NULL)
{
    printf("Could not connect to: %s", printer);
    return 0;
}
request = ippNewRequest(IPP_OP_CREATE_JOB);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, szUri);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, "myName");
ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "media", NULL, "na_letter_8.5x11in");
response = cupsDoFileRequest(http, request, "/ipp/print", filename);
status = ippGetStatusCode(response);
if (status != IPP_STATUS_OK)
{
    printf("Bad response: %d", status);
    return 0;
}
int Job_id = ippGetInteger(ippFindAttribute(response, "job-id", IPP_TAG_INTEGER), 0);
ippDelete(response);
request = ippNewRequest(IPP_OP_SEND_DOCUMENT);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, szUri);
ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", Job_id);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, "myName");
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", NULL, filetype);
response = cupsDoFileRequest(http, request, "/ipp/print", filename);
status = ippGetStatusCode(response);
if (status != IPP_STATUS_OK)
{
    printf("Bad response: %d", status);
    return 0;
}
ippDelete(response);

}

jpmsparks commented 7 months ago

OK, so I found the issue - oddly, I had to use the "last-document" boolean to the SEND_DOCUMENT op.

request = ippNewRequest(IPP_OP_SEND_DOCUMENT); status = ippGetStatusCode(request); if ((status == IPP_STATUS_OK)||(status == IPP_STATUS_OK_BUT_CANCEL_SUBSCRIPTION)) { ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", iJobId); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, szUriTag); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, userName); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", NULL, getMimeType(filetoPrint)); //must include the 'last-document' op or this will fail.. ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", 1); response = cupsDoFileRequest(http, request, "/ipp/print", filetoPrint); status = ippGetStatusCode(response);

    if (response)
    {
        ippDelete(response);
    }
}

Now the request is successful.

michaelrsweet commented 7 months ago

Ah yes, the "last-document" attribute is required. Looks like the C sample code in the "How to Use IPP" guide is missing it but the ipptool test file example is not...

At this point we don't have a bug tracker for the how-to guide, but if you subscribe to the IPP mailing list you can report it there:

https://www.pwg.org/mailman/listinfo/ipp