diff options
Diffstat (limited to 'source3/printing')
-rw-r--r-- | source3/printing/print_cups.c | 1005 | ||||
-rw-r--r-- | source3/printing/printing.c | 186 |
2 files changed, 1023 insertions, 168 deletions
diff --git a/source3/printing/print_cups.c b/source3/printing/print_cups.c index 8739ddcec4..3ca0af537f 100644 --- a/source3/printing/print_cups.c +++ b/source3/printing/print_cups.c @@ -1,7 +1,7 @@ /* * Support code for the Common UNIX Printing System ("CUPS") * - * Copyright 1999 by Easy Software Products + * Copyright 1999-2001 by Easy Software Products * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,22 +18,66 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "includes.h" +#include "printing.h" #include "smb.h" #ifdef HAVE_LIBCUPS #include <cups/cups.h> #include <cups/language.h> + +/* + * CUPS printing interface definitions... + */ + +static int cups_job_delete(int snum, struct printjob *pjob); +static int cups_job_pause(int snum, struct printjob *pjob); +static int cups_job_resume(int snum, struct printjob *pjob); +static int cups_job_submit(int snum, struct printjob *pjob); +static int cups_queue_get(int snum, print_queue_struct **q, + print_status_struct *status); +static int cups_queue_pause(int snum); +static int cups_queue_resume(int snum); + + +struct printif cups_printif = + { + cups_queue_get, + cups_queue_pause, + cups_queue_resume, + cups_job_delete, + cups_job_pause, + cups_job_resume, + cups_job_submit, + }; + extern int DEBUGLEVEL; /* + * 'cups_passwd_cb()' - The CUPS password callback... + */ + +const char * /* O - Password or NULL */ +cups_passwd_cb(const char *prompt) /* I - Prompt */ +{ + /* + * Always return NULL to indicate that no password is available... + */ + + (void)prompt; + + return (NULL); +} + + +/* * 'cups_printer_fn()' - Call a function for every printer known to the * system. */ -void cups_printer_fn(void (*fn)(char *, char *)) +void +cups_printer_fn(void (*fn)(char *, char *)) /* I - Function to call */ { http_t *http; /* HTTP connection to server */ ipp_t *request, /* IPP Request */ @@ -41,15 +85,34 @@ void cups_printer_fn(void (*fn)(char *, char *)) ipp_attribute_t *attr; /* Current attribute */ cups_lang_t *language; /* Default language */ char *name, /* printer-name attribute */ - *make_model; /* make_model attribute */ + *make_model, /* printer-make-and-model attribute */ + *info; /* printer-info attribute */ + static const char *requested[] =/* Requested attributes */ + { + "printer-name", + "printer-make-and-model", + "printer-info" + }; + DEBUG(5,("cups_printer_fn(%p)\n", fn)); + + /* + * Make sure we don't ask for passwords... + */ + + cupsSetPasswordCB(cups_passwd_cb); + /* * Try to connect to the server... */ if ((http = httpConnect(cupsServer(), ippPort())) == NULL) + { + DEBUG(0,("Unable to connect to CUPS server %s - %s\n", + cupsServer(), strerror(errno))); return; + } /* * Build a CUPS_GET_PRINTERS request, which requires the following @@ -57,6 +120,7 @@ void cups_printer_fn(void (*fn)(char *, char *)) * * attributes-charset * attributes-natural-language + * requested-attributes */ request = ippNew(); @@ -72,12 +136,19 @@ void cups_printer_fn(void (*fn)(char *, char *)) ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, "attributes-natural-language", NULL, language->language); + ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME, + "requested-attributes", + (sizeof(requested) / sizeof(requested[0])), + NULL, requested); + /* * Do the request and get back a response... */ if ((response = cupsDoRequest(http, request, "/")) == NULL) { + DEBUG(0,("Unable to get printer list - %s\n", + ippErrorString(cupsLastError()))); httpClose(http); return; } @@ -100,6 +171,7 @@ void cups_printer_fn(void (*fn)(char *, char *)) name = NULL; make_model = NULL; + info = NULL; while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER) { @@ -111,6 +183,10 @@ void cups_printer_fn(void (*fn)(char *, char *)) attr->value_tag == IPP_TAG_TEXT) make_model = attr->values[0].string.text; + if (strcmp(attr->name, "printer-info") == 0 && + attr->value_tag == IPP_TAG_TEXT) + info = attr->values[0].string.text; + attr = attr->next; } @@ -121,7 +197,10 @@ void cups_printer_fn(void (*fn)(char *, char *)) if (name == NULL) break; - (*fn)(unix_to_dos(name,False), make_model); + if (info == NULL || !info[0]) + (*fn)(unix_to_dos(name,False), make_model); + else + (*fn)(unix_to_dos(name,False), info); } ippDelete(response); @@ -130,31 +209,46 @@ void cups_printer_fn(void (*fn)(char *, char *)) /* - * provide the equivalent of pcap_printername_ok() for SVID/XPG4 conforming - * systems. + * 'cups_printername_ok()' - Provide the equivalent of pcap_printername_ok() + * for CUPS. */ -int cups_printername_ok(char *name) + +int /* O - 1 if printer name OK */ +cups_printername_ok(char *name) /* I - Name of printer */ { http_t *http; /* HTTP connection to server */ ipp_t *request, /* IPP Request */ *response; /* IPP Response */ - ipp_attribute_t *attr; /* Current attribute */ cups_lang_t *language; /* Default language */ char uri[HTTP_MAX_URI]; /* printer-uri attribute */ + + DEBUG(5,("cups_printername_ok(\"%s\")\n", name)); + + /* + * Make sure we don't ask for passwords... + */ + + cupsSetPasswordCB(cups_passwd_cb); + /* * Try to connect to the server... */ if ((http = httpConnect(cupsServer(), ippPort())) == NULL) + { + DEBUG(0,("Unable to connect to CUPS server %s - %s\n", + cupsServer(), strerror(errno))); return (0); + } /* - * Build a IPP_GET_PRINTER_ATTRS request, which requires the following + * Build an IPP_GET_PRINTER_ATTRS request, which requires the following * attributes: * * attributes-charset * attributes-natural-language + * requested-attributes * printer-uri */ @@ -171,7 +265,11 @@ int cups_printername_ok(char *name) ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, "attributes-natural-language", NULL, language->language); - slprintf(uri, sizeof(uri)-1, "ipp://localhost/printers/%s", dos_to_unix(name,False)); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, + "requested-attributes", NULL, "printer-uri"); + + slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s", + dos_to_unix(name, False)); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); @@ -182,6 +280,8 @@ int cups_printername_ok(char *name) if ((response = cupsDoRequest(http, request, "/")) == NULL) { + DEBUG(0,("Unable to get printer status for %s - %s\n", name, + ippErrorString(cupsLastError()))); httpClose(http); return (0); } @@ -190,6 +290,8 @@ int cups_printername_ok(char *name) if (response->request.status.status_code >= IPP_OK_CONFLICT) { + DEBUG(0,("Unable to get printer status for %s - %s\n", name, + ippErrorString(response->request.status.status_code))); ippDelete(response); return (0); } @@ -200,6 +302,887 @@ int cups_printername_ok(char *name) } } + +/* + * 'cups_job_delete()' - Delete a job. + */ + +static int +cups_job_delete(int snum, struct printjob *pjob) +{ + int ret; /* Return value */ + http_t *http; /* HTTP connection to server */ + ipp_t *request, /* IPP Request */ + *response; /* IPP Response */ + cups_lang_t *language; /* Default language */ + char uri[HTTP_MAX_URI]; /* printer-uri attribute */ + + + DEBUG(5,("cups_job_delete(%d, %p (%d))\n", snum, pjob, pjob->sysjob)); + + /* + * Make sure we don't ask for passwords... + */ + + cupsSetPasswordCB(cups_passwd_cb); + + /* + * Try to connect to the server... + */ + + if ((http = httpConnect(cupsServer(), ippPort())) == NULL) + { + DEBUG(0,("Unable to connect to CUPS server %s - %s\n", + cupsServer(), strerror(errno))); + return (1); + } + + /* + * Build an IPP_CANCEL_JOB request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * job-uri + * requesting-user-name + */ + + request = ippNew(); + + request->request.op.operation_id = IPP_CANCEL_JOB; + request->request.op.request_id = 1; + + language = cupsLangDefault(); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + slprintf(uri, sizeof(uri) - 1, "ipp://localhost/jobs/%d", pjob->sysjob); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, cupsUser()); + + /* + * Do the request and get back a response... + */ + + ret = 1; + + if ((response = cupsDoRequest(http, request, "/jobs")) != NULL) + { + if (response->request.status.status_code >= IPP_OK_CONFLICT) + DEBUG(0,("Unable to cancel job %d - %s\n", pjob->sysjob, + ippErrorString(cupsLastError()))); + else + ret = 0; + + ippDelete(response); + } + else + DEBUG(0,("Unable to cancel job %d - %s\n", pjob->sysjob, + ippErrorString(cupsLastError()))); + + httpClose(http); + + return (ret); +} + + +/* + * 'cups_job_pause()' - Pause a job. + */ + +static int +cups_job_pause(int snum, struct printjob *pjob) +{ + int ret; /* Return value */ + http_t *http; /* HTTP connection to server */ + ipp_t *request, /* IPP Request */ + *response; /* IPP Response */ + cups_lang_t *language; /* Default language */ + char uri[HTTP_MAX_URI]; /* printer-uri attribute */ + + + DEBUG(5,("cups_job_pause(%d, %p (%d))\n", snum, pjob, pjob->sysjob)); + + /* + * Make sure we don't ask for passwords... + */ + + cupsSetPasswordCB(cups_passwd_cb); + + /* + * Try to connect to the server... + */ + + if ((http = httpConnect(cupsServer(), ippPort())) == NULL) + { + DEBUG(0,("Unable to connect to CUPS server %s - %s\n", + cupsServer(), strerror(errno))); + return (1); + } + + /* + * Build an IPP_HOLD_JOB request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * job-uri + * requesting-user-name + */ + + request = ippNew(); + + request->request.op.operation_id = IPP_HOLD_JOB; + request->request.op.request_id = 1; + + language = cupsLangDefault(); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + slprintf(uri, sizeof(uri) - 1, "ipp://localhost/jobs/%d", pjob->sysjob); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, cupsUser()); + + /* + * Do the request and get back a response... + */ + + ret = 1; + + if ((response = cupsDoRequest(http, request, "/jobs")) != NULL) + { + if (response->request.status.status_code >= IPP_OK_CONFLICT) + DEBUG(0,("Unable to hold job %d - %s\n", pjob->sysjob, + ippErrorString(cupsLastError()))); + else + ret = 0; + + ippDelete(response); + } + else + DEBUG(0,("Unable to hold job %d - %s\n", pjob->sysjob, + ippErrorString(cupsLastError()))); + + httpClose(http); + + return (ret); +} + + +/* + * 'cups_job_resume()' - Resume a paused job. + */ + +static int +cups_job_resume(int snum, struct printjob *pjob) +{ + int ret; /* Return value */ + http_t *http; /* HTTP connection to server */ + ipp_t *request, /* IPP Request */ + *response; /* IPP Response */ + cups_lang_t *language; /* Default language */ + char uri[HTTP_MAX_URI]; /* printer-uri attribute */ + + + DEBUG(5,("cups_job_resume(%d, %p (%d))\n", snum, pjob, pjob->sysjob)); + + /* + * Make sure we don't ask for passwords... + */ + + cupsSetPasswordCB(cups_passwd_cb); + + /* + * Try to connect to the server... + */ + + if ((http = httpConnect(cupsServer(), ippPort())) == NULL) + { + DEBUG(0,("Unable to connect to CUPS server %s - %s\n", + cupsServer(), strerror(errno))); + return (1); + } + + /* + * Build an IPP_RELEASE_JOB request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * job-uri + * requesting-user-name + */ + + request = ippNew(); + + request->request.op.operation_id = IPP_RELEASE_JOB; + request->request.op.request_id = 1; + + language = cupsLangDefault(); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + slprintf(uri, sizeof(uri) - 1, "ipp://localhost/jobs/%d", pjob->sysjob); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, cupsUser()); + + /* + * Do the request and get back a response... + */ + + ret = 1; + + if ((response = cupsDoRequest(http, request, "/jobs")) != NULL) + { + if (response->request.status.status_code >= IPP_OK_CONFLICT) + DEBUG(0,("Unable to release job %d - %s\n", pjob->sysjob, + ippErrorString(cupsLastError()))); + else + ret = 0; + + ippDelete(response); + } + else + DEBUG(0,("Unable to release job %d - %s\n", pjob->sysjob, + ippErrorString(cupsLastError()))); + + httpClose(http); + + return (ret); +} + + +/* + * 'cups_job_submit()' - Submit a job for printing. + */ + +static int +cups_job_submit(int snum, struct printjob *pjob) +{ + int ret; /* Return value */ + http_t *http; /* HTTP connection to server */ + ipp_t *request, /* IPP Request */ + *response; /* IPP Response */ + cups_lang_t *language; /* Default language */ + char uri[HTTP_MAX_URI]; /* printer-uri attribute */ + + + DEBUG(5,("cups_job_submit(%d, %p (%d))\n", snum, pjob, pjob->sysjob)); + + /* + * Make sure we don't ask for passwords... + */ + + cupsSetPasswordCB(cups_passwd_cb); + + /* + * Try to connect to the server... + */ + + if ((http = httpConnect(cupsServer(), ippPort())) == NULL) + { + DEBUG(0,("Unable to connect to CUPS server %s - %s\n", + cupsServer(), strerror(errno))); + return (1); + } + + /* + * Build an IPP_PRINT_JOB request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + * requesting-user-name + * [document-data] + */ + + request = ippNew(); + + request->request.op.operation_id = IPP_PRINT_JOB; + request->request.op.request_id = 1; + + language = cupsLangDefault(); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s", + PRINTERNAME(snum)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, + "printer-uri", NULL, uri); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, cupsUser()); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL, + pjob->jobname); + + /* + * Do the request and get back a response... + */ + + slprintf(uri, sizeof(uri) - 1, "/printers/%s", PRINTERNAME(snum)); + + ret = 1; + if ((response = cupsDoFileRequest(http, request, uri, + pjob->filename)) != NULL) + { + if (response->request.status.status_code >= IPP_OK_CONFLICT) + DEBUG(0,("Unable to print file to %s - %s\n", PRINTERNAME(snum), + ippErrorString(cupsLastError()))); + else + ret = 0; + + ippDelete(response); + } + else + DEBUG(0,("Unable to print file to `%s' - %s\n", PRINTERNAME(snum), + ippErrorString(cupsLastError()))); + + httpClose(http); + + return (ret); +} + + +/* + * 'cups_queue_get()' - Get all the jobs in the print queue. + */ + +static int +cups_queue_get(int snum, print_queue_struct **q, print_status_struct *status) +{ + http_t *http; /* HTTP connection to server */ + ipp_t *request, /* IPP Request */ + *response; /* IPP Response */ + ipp_attribute_t *attr; /* Current attribute */ + cups_lang_t *language; /* Default language */ + char uri[HTTP_MAX_URI]; /* printer-uri attribute */ + int qcount, /* Number of active queue entries */ + qalloc; /* Number of queue entries allocated */ + print_queue_struct *queue, /* Queue entries */ + *temp; /* Temporary pointer for queue */ + const char *user_name, /* job-originating-user-name attribute */ + *job_name; /* job-name attribute */ + int job_id; /* job-id attribute */ + int job_k_octets; /* job-k-octets attribute */ + time_t job_time; /* time-at-creation attribute */ + ipp_jstate_t job_status; /* job-status attribute */ + int job_priority; /* job-priority attribute */ + static const char *jattrs[] = /* Requested job attributes */ + { + "job-id", + "job-k-octets", + "job-name", + "job-originating-user-name", + "job-priority", + "job-state", + "time-at-creation", + }; + static const char *pattrs[] = /* Requested printer attributes */ + { + "printer-state", + "printer-state-message" + }; + + + DEBUG(5,("cups_queue_get(%d, %p, %p)\n", snum, q, status)); + + /* + * Make sure we don't ask for passwords... + */ + + cupsSetPasswordCB(cups_passwd_cb); + + /* + * Try to connect to the server... + */ + + if ((http = httpConnect(cupsServer(), ippPort())) == NULL) + { + DEBUG(0,("Unable to connect to CUPS server %s - %s\n", + cupsServer(), strerror(errno))); + return (0); + } + + /* + * Generate the printer URI... + */ + + slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s", + PRINTERNAME(snum)); + + /* + * Build an IPP_GET_JOBS request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * requested-attributes + * printer-uri + */ + + request = ippNew(); + + request->request.op.operation_id = IPP_GET_JOBS; + request->request.op.request_id = 1; + + language = cupsLangDefault(); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME, + "requested-attributes", + (sizeof(jattrs) / sizeof(jattrs[0])), + NULL, jattrs); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, + "printer-uri", NULL, uri); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/")) == NULL) + { + DEBUG(0,("Unable to get jobs for %s - %s\n", uri, + ippErrorString(cupsLastError()))); + httpClose(http); + return (0); + } + + if (response->request.status.status_code >= IPP_OK_CONFLICT) + { + DEBUG(0,("Unable to get jobs for %s - %s\n", uri, + ippErrorString(response->request.status.status_code))); + ippDelete(response); + httpClose(http); + + return (0); + } + + /* + * Process the jobs... + */ + + qcount = 0; + qalloc = 0; + queue = NULL; + + for (attr = response->attrs; attr != NULL; attr = attr->next) + { + /* + * Skip leading attributes until we hit a job... + */ + + while (attr != NULL && attr->group_tag != IPP_TAG_JOB) + attr = attr->next; + + if (attr == NULL) + break; + + /* + * Allocate memory as needed... + */ + if (qcount >= qalloc) + { + qalloc += 16; + + if (qalloc == 16) + temp = malloc(sizeof(print_queue_struct) * qalloc); + else + temp = realloc(queue, sizeof(print_queue_struct) * qalloc); + + if (temp == NULL) + { + ippDelete(response); + httpClose(http); + + return (qcount); + } + + queue = temp; + } + + temp = queue + qcount; + memset(temp, 0, sizeof(print_queue_struct)); + + /* + * Pull the needed attributes from this job... + */ + + job_id = 0; + job_priority = 50; + job_status = IPP_JOB_PENDING; + job_time = 0; + job_k_octets = 0; + user_name = NULL; + job_name = NULL; + + while (attr != NULL && attr->group_tag == IPP_TAG_JOB) + { + if (attr->name == NULL) + { + attr = attr->next; + break; + } + + if (strcmp(attr->name, "job-id") == 0 && + attr->value_tag == IPP_TAG_INTEGER) + job_id = attr->values[0].integer; + + if (strcmp(attr->name, "job-k-octets") == 0 && + attr->value_tag == IPP_TAG_INTEGER) + job_k_octets = attr->values[0].integer; + + if (strcmp(attr->name, "job-priority") == 0 && + attr->value_tag == IPP_TAG_INTEGER) + job_priority = attr->values[0].integer; + + if (strcmp(attr->name, "job-state") == 0 && + attr->value_tag == IPP_TAG_ENUM) + job_status = (ipp_jstate_t)(attr->values[0].integer); + + if (strcmp(attr->name, "time-at-creation") == 0 && + attr->value_tag == IPP_TAG_INTEGER) + job_time = attr->values[0].integer; + + if (strcmp(attr->name, "job-name") == 0 && + attr->value_tag == IPP_TAG_NAME) + job_name = attr->values[0].string.text; + + if (strcmp(attr->name, "job-originating-user-name") == 0 && + attr->value_tag == IPP_TAG_NAME) + user_name = attr->values[0].string.text; + + attr = attr->next; + } + + /* + * See if we have everything needed... + */ + + if (user_name == NULL || job_name == NULL || job_id == 0) + { + if (attr == NULL) + break; + else + continue; + } + + temp->job = job_id; + temp->size = job_k_octets * 1024; + temp->status = job_status == IPP_JOB_PENDING ? LPQ_QUEUED : + job_status == IPP_JOB_STOPPED ? LPQ_PAUSED : + job_status == IPP_JOB_HELD ? LPQ_PAUSED : + LPQ_PRINTING; + temp->priority = job_priority; + temp->time = job_time; + strncpy(temp->user, user_name, sizeof(temp->user) - 1); + strncpy(temp->file, job_name, sizeof(temp->file) - 1); + + qcount ++; + + if (attr == NULL) + break; + } + + ippDelete(response); + + /* + * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the + * following attributes: + * + * attributes-charset + * attributes-natural-language + * requested-attributes + * printer-uri + */ + + request = ippNew(); + + request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES; + request->request.op.request_id = 1; + + language = cupsLangDefault(); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME, + "requested-attributes", + (sizeof(pattrs) / sizeof(pattrs[0])), + NULL, pattrs); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, + "printer-uri", NULL, uri); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/")) == NULL) + { + DEBUG(0,("Unable to get printer status for %s - %s\n", PRINTERNAME(snum), + ippErrorString(cupsLastError()))); + httpClose(http); + return (qcount); + } + + if (response->request.status.status_code >= IPP_OK_CONFLICT) + { + DEBUG(0,("Unable to get printer status for %s - %s\n", PRINTERNAME(snum), + ippErrorString(response->request.status.status_code))); + ippDelete(response); + httpClose(http); + + return (qcount); + } + + /* + * Get the current printer status and convert it to the SAMBA values. + */ + + if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL) + { + if (attr->values[0].integer == IPP_PRINTER_STOPPED) + status->status = LPSTAT_STOPPED; + else + status->status = LPSTAT_OK; + } + + if ((attr = ippFindAttribute(response, "printer-state-message", + IPP_TAG_TEXT)) != NULL) + fstrcpy(status->message, attr->values[0].string.text); + + ippDelete(response); + + /* + * Return the job queue... + */ + + httpClose(http); + + *q = queue; + return (qcount); +} + + +/* + * 'cups_queue_pause()' - Pause a print queue. + */ + +static int +cups_queue_pause(int snum) +{ + int ret; /* Return value */ + http_t *http; /* HTTP connection to server */ + ipp_t *request, /* IPP Request */ + *response; /* IPP Response */ + cups_lang_t *language; /* Default language */ + char uri[HTTP_MAX_URI]; /* printer-uri attribute */ + + + DEBUG(5,("cups_queue_pause(%d)\n", snum)); + + /* + * Make sure we don't ask for passwords... + */ + + cupsSetPasswordCB(cups_passwd_cb); + + /* + * Try to connect to the server... + */ + + if ((http = httpConnect(cupsServer(), ippPort())) == NULL) + { + DEBUG(0,("Unable to connect to CUPS server %s - %s\n", + cupsServer(), strerror(errno))); + return (1); + } + + /* + * Build an IPP_PAUSE_PRINTER request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + * requesting-user-name + */ + + request = ippNew(); + + request->request.op.operation_id = IPP_PAUSE_PRINTER; + request->request.op.request_id = 1; + + language = cupsLangDefault(); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s", + PRINTERNAME(snum)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, cupsUser()); + + /* + * Do the request and get back a response... + */ + + ret = 1; + + if ((response = cupsDoRequest(http, request, "/admin")) != NULL) + { + if (response->request.status.status_code >= IPP_OK_CONFLICT) + DEBUG(0,("Unable to pause printer %s - %s\n", PRINTERNAME(snum), + ippErrorString(cupsLastError()))); + else + ret = 0; + + ippDelete(response); + } + else + DEBUG(0,("Unable to pause printer %s - %s\n", PRINTERNAME(snum), + ippErrorString(cupsLastError()))); + + httpClose(http); + + return (ret); +} + + +/* + * 'cups_queue_resume()' - Restart a print queue. + */ + +static int +cups_queue_resume(int snum) +{ + int ret; /* Return value */ + http_t *http; /* HTTP connection to server */ + ipp_t *request, /* IPP Request */ + *response; /* IPP Response */ + cups_lang_t *language; /* Default language */ + char uri[HTTP_MAX_URI]; /* printer-uri attribute */ + + + DEBUG(5,("cups_queue_resume(%d)\n", snum)); + + /* + * Make sure we don't ask for passwords... + */ + + cupsSetPasswordCB(cups_passwd_cb); + + /* + * Try to connect to the server... + */ + + if ((http = httpConnect(cupsServer(), ippPort())) == NULL) + { + DEBUG(0,("Unable to connect to CUPS server %s - %s\n", + cupsServer(), strerror(errno))); + return (1); + } + + /* + * Build an IPP_RESUME_PRINTER request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + * requesting-user-name + */ + + request = ippNew(); + + request->request.op.operation_id = IPP_RESUME_PRINTER; + request->request.op.request_id = 1; + + language = cupsLangDefault(); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s", + PRINTERNAME(snum)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, cupsUser()); + + /* + * Do the request and get back a response... + */ + + ret = 1; + + if ((response = cupsDoRequest(http, request, "/admin")) != NULL) + { + if (response->request.status.status_code >= IPP_OK_CONFLICT) + DEBUG(0,("Unable to resume printer %s - %s\n", PRINTERNAME(snum), + ippErrorString(cupsLastError()))); + else + ret = 0; + + ippDelete(response); + } + else + DEBUG(0,("Unable to resume printer %s - %s\n", PRINTERNAME(snum), + ippErrorString(cupsLastError()))); + + httpClose(http); + + return (ret); +} + + #else /* this keeps fussy compilers happy */ void print_cups_dummy(void) {} diff --git a/source3/printing/printing.c b/source3/printing/printing.c index 241135f744..84ed1a3993 100644 --- a/source3/printing/printing.c +++ b/source3/printing/printing.c @@ -19,10 +19,13 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "includes.h" +#include "printing.h" extern int DEBUGLEVEL; +/* Current printer interface */ +struct printif *current_printif = &generic_printif; + /* the printing backend revolves around a tdb database that stores the SMB view of the print queue @@ -37,34 +40,10 @@ extern int DEBUGLEVEL; jobids are assigned when a job starts spooling. */ -#define NEXT_JOBID(j) ((j+1) % PRINT_MAX_JOBID > 0 ? (j+1) % PRINT_MAX_JOBID : 1) - - -struct printjob { - pid_t pid; /* which process launched the job */ - int sysjob; /* the system (lp) job number */ - int fd; /* file descriptor of open file if open */ - time_t starttime; /* when the job started spooling */ - int status; /* the status of this job */ - size_t size; /* the size of the job so far */ - BOOL spooled; /* has it been sent to the spooler yet? */ - BOOL smbjob; /* set if the job is a SMB job */ - fstring filename; /* the filename used to spool the file */ - fstring jobname; /* the job name given to us by the client */ - fstring user; /* the user who started the job */ - fstring qname; /* name of the print queue the job was sent to */ -}; - /* the open printing.tdb database */ static TDB_CONTEXT *tdb; static pid_t local_pid; -#define PRINT_MAX_JOBID 10000 -#define UNIX_JOB_START PRINT_MAX_JOBID - -#define PRINT_SPOOL_PREFIX "smbprn." -#define PRINT_DATABASE_VERSION 2 - static int get_queue_status(int, print_status_struct *); /**************************************************************************** @@ -92,6 +71,13 @@ BOOL print_backend_init(void) } tdb_unlock_bystring(tdb, sversion); + /* select the appropriate printing interface... */ +#ifdef HAVE_LIBCUPS + if (strcmp(lp_printcapname(), "cups") == 0) + current_printif = &cups_printif; +#endif /* HAVE_LIBCUPS */ + + /* do NT print initialization... */ return nt_printing_init(); } @@ -138,51 +124,6 @@ static BOOL print_job_store(int jobid, struct printjob *pjob) } /**************************************************************************** -run a given print command -a null terminated list of value/substitute pairs is provided -for local substitution strings -****************************************************************************/ -static int print_run_command(int snum,char *command, - char *outfile, - ...) -{ - pstring syscmd; - char *p, *arg; - int ret; - va_list ap; - - if (!command || !*command) return -1; - - if (!VALID_SNUM(snum)) { - DEBUG(0,("Invalid snum %d for command %s\n", snum, command)); - return -1; - } - - pstrcpy(syscmd, command); - - va_start(ap, outfile); - while ((arg = va_arg(ap, char *))) { - char *value = va_arg(ap,char *); - pstring_sub(syscmd, arg, value); - } - va_end(ap); - - p = PRINTERNAME(snum); - - pstring_sub(syscmd, "%p", p); - standard_sub_snum(snum,syscmd); - - /* Convert script args to unix-codepage */ - dos_to_unix(syscmd, True); - ret = smbrun(syscmd,outfile,False); - - DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret)); - - return ret; -} - - -/**************************************************************************** parse a file name from the system spooler to generate a jobid ****************************************************************************/ static int print_parse_jobid(char *fname) @@ -378,11 +319,7 @@ update the internal database from the system print queue for a queue static void print_queue_update(int snum) { - char *path = lp_pathname(snum); - char *cmd = lp_lpqcommand(snum); - char **qlines; - pstring tmp_file; - int numlines, i, qcount; + int i, qcount; print_queue_struct *queue = NULL; print_status_struct status; print_status_struct old_status; @@ -446,31 +383,10 @@ static void print_queue_update(int snum) slprintf(cachestr, sizeof(cachestr), "CACHE/%s", printer_name); tdb_store_int(tdb, cachestr, (int)time(NULL)); - slprintf(tmp_file, sizeof(tmp_file), "%s/smblpq.%d", path, local_pid); - - unlink(tmp_file); - print_run_command(snum, cmd, tmp_file, NULL); - - numlines = 0; - qlines = file_lines_load(tmp_file, &numlines, True); - unlink(tmp_file); - - /* turn the lpq output into a series of job structures */ - qcount = 0; + /* get the current queue using the appropriate interface */ ZERO_STRUCT(status); - if (numlines) - queue = (print_queue_struct *)malloc(sizeof(print_queue_struct)*(numlines+1)); - - if (queue) { - for (i=0; i<numlines; i++) { - /* parse the line */ - if (parse_lpq_entry(snum,qlines[i], - &queue[qcount],&status,qcount==0)) { - qcount++; - } - } - } - file_lines_free(qlines); + + qcount = (*(current_printif->queue_get))(snum, &queue, &status); DEBUG(3, ("%d job%s in queue for %s\n", qcount, (qcount != 1) ? "s" : "", printer_name)); @@ -658,17 +574,14 @@ static BOOL print_job_delete1(int jobid) pjob->status = LPQ_DELETING; print_job_store(jobid, pjob); - if (pjob->spooled && pjob->sysjob != -1) { - fstring jobstr; - - /* need to delete the spooled entry */ - slprintf(jobstr, sizeof(jobstr), "%d", pjob->sysjob); - result = print_run_command( - snum, - lp_lprmcommand(snum), NULL, - "%j", jobstr, - "%T", http_timestring(pjob->starttime), - NULL); + if (pjob->spooled && pjob->sysjob != -1) + result = (*(current_printif->job_delete))(snum, pjob); + + /* Delete the tdb entry if the delete suceeded or the job hasn't + been spooled. */ + + if (result == 0) { + tdb_delete(tdb, print_key(jobid)); } return (result == 0); @@ -739,17 +652,14 @@ BOOL print_job_pause(struct current_user *user, int jobid, int *errcode) struct printjob *pjob = print_job_find(jobid); int snum, ret = -1; char *printer_name; - fstring jobstr; - BOOL owner; if (!pjob || !user) return False; if (!pjob->spooled || pjob->sysjob == -1) return False; snum = print_job_snum(jobid); - owner = is_owner(user, jobid); - if (!owner && + if (!is_owner(user, jobid) && !print_access_check(user, snum, JOB_ACCESS_ADMINISTER)) { DEBUG(3, ("pause denied by security descriptor\n")); *errcode = ERROR_ACCESS_DENIED; @@ -757,11 +667,7 @@ BOOL print_job_pause(struct current_user *user, int jobid, int *errcode) } /* need to pause the spooled entry */ - slprintf(jobstr, sizeof(jobstr), "%d", pjob->sysjob); - ret = print_run_command(snum, - lp_lppausecommand(snum), NULL, - "%j", jobstr, - NULL); + ret = (*(current_printif->job_pause))(snum, pjob); if (ret != 0) { *errcode = ERROR_INVALID_PARAMETER; @@ -790,7 +696,6 @@ BOOL print_job_resume(struct current_user *user, int jobid, int *errcode) struct printjob *pjob = print_job_find(jobid); char *printer_name; int snum, ret; - fstring jobstr; if (!pjob || !user) return False; @@ -805,11 +710,7 @@ BOOL print_job_resume(struct current_user *user, int jobid, int *errcode) return False; } - slprintf(jobstr, sizeof(jobstr), "%d", pjob->sysjob); - ret = print_run_command(snum, - lp_lpresumecommand(snum), NULL, - "%j", jobstr, - NULL); + ret = (*(current_printif->job_resume))(snum, pjob); if (ret != 0) { *errcode = ERROR_INVALID_PARAMETER; @@ -1056,10 +957,6 @@ BOOL print_job_end(int jobid, BOOL normal_close) struct printjob *pjob = print_job_find(jobid); int snum, ret; SMB_STRUCT_STAT sbuf; - pstring current_directory; - pstring print_directory; - char *wd, *p; - pstring jobname; if (!pjob) return False; @@ -1096,30 +993,7 @@ BOOL print_job_end(int jobid, BOOL normal_close) return True; } - /* we print from the directory path to give the best chance of - parsing the lpq output */ - wd = sys_getwd(current_directory); - if (!wd) goto fail; - - pstrcpy(print_directory, pjob->filename); - p = strrchr(print_directory,'/'); - if (!p) goto fail; - *p++ = 0; - - if (chdir(print_directory) != 0) goto fail; - - pstrcpy(jobname, pjob->jobname); - pstring_sub(jobname, "'", "_"); - - /* send it to the system spooler */ - ret = print_run_command(snum, - lp_printcommand(snum), NULL, - "%s", p, - "%J", jobname, - "%f", p, - NULL); - - chdir(wd); + ret = (*(current_printif->job_submit))(snum, pjob); if (ret) goto fail; @@ -1310,8 +1184,7 @@ BOOL print_queue_pause(struct current_user *user, int snum, int *errcode) return False; } - ret = print_run_command(snum, lp_queuepausecommand(snum), NULL, - NULL); + ret = (*(current_printif->queue_pause))(snum); if (ret != 0) { *errcode = ERROR_INVALID_PARAMETER; @@ -1343,8 +1216,7 @@ BOOL print_queue_resume(struct current_user *user, int snum, int *errcode) return False; } - ret = print_run_command(snum, lp_queueresumecommand(snum), NULL, - NULL); + ret = (*(current_printif->queue_resume))(snum); if (ret != 0) { *errcode = ERROR_INVALID_PARAMETER; |