1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-28 07:21:54 +03:00
samba-mirror/source3/printing/print_cups.c

1348 lines
32 KiB
C
Raw Normal View History

/*
* Support code for the Common UNIX Printing System ("CUPS")
*
* Copyright 1999-2003 by Michael R Sweet.
*
* 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
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#include "printing.h"
#ifdef HAVE_CUPS
#include <cups/cups.h>
#include <cups/language.h>
extern userdom_struct current_user_info;
/*
* 'cups_passwd_cb()' - The CUPS password callback...
*/
static const char * /* O - Password or NULL */
cups_passwd_cb(const char *prompt) /* I - Prompt */
{
/*
* Always return NULL to indicate that no password is available...
*/
return (NULL);
}
static http_t *cups_connect(void)
{
http_t *http;
char *server, *p;
int port;
if (lp_cups_server() != NULL && strlen(lp_cups_server()) > 0) {
server = smb_xstrdup(lp_cups_server());
} else {
server = smb_xstrdup(cupsServer());
}
p = strchr(server, ':');
if (p) {
port = atoi(p+1);
*p = '\0';
} else {
port = ippPort();
}
DEBUG(10, ("connecting to cups server %s:%d\n",
server, port));
if ((http = httpConnect(server, port)) == NULL) {
DEBUG(0,("Unable to connect to CUPS server %s:%d - %s\n",
server, port, strerror(errno)));
SAFE_FREE(server);
return NULL;
}
SAFE_FREE(server);
return http;
}
bool cups_cache_reload(void)
{
http_t *http = NULL; /* HTTP connection to server */
ipp_t *request = NULL, /* IPP Request */
*response = NULL; /* IPP Response */
ipp_attribute_t *attr; /* Current attribute */
cups_lang_t *language = NULL; /* Default language */
char *name, /* printer-name attribute */
*info; /* printer-info attribute */
static const char *requested[] =/* Requested attributes */
{
"printer-name",
"printer-info"
};
bool ret = False;
DEBUG(5, ("reloading cups printcap cache\n"));
/*
* Make sure we don't ask for passwords...
*/
cupsSetPasswordCB(cups_passwd_cb);
/*
* Try to connect to the server...
*/
if ((http = cups_connect()) == NULL) {
goto out;
}
/*
* Build a CUPS_GET_PRINTERS request, which requires the following
* attributes:
*
* attributes-charset
* attributes-natural-language
* requested-attributes
*/
request = ippNew();
request->request.op.operation_id = CUPS_GET_PRINTERS;
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(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())));
goto out;
}
for (attr = response->attrs; attr != NULL;) {
/*
* Skip leading attributes until we hit a printer...
*/
while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
attr = attr->next;
if (attr == NULL)
break;
/*
* Pull the needed attributes from this printer...
*/
name = NULL;
info = NULL;
while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER) {
if (strcmp(attr->name, "printer-name") == 0 &&
attr->value_tag == IPP_TAG_NAME)
name = 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;
}
/*
* See if we have everything needed...
*/
if (name == NULL)
break;
if (!pcap_cache_add(name, info)) {
goto out;
}
}
ippDelete(response);
response = NULL;
/*
* Build a CUPS_GET_CLASSES request, which requires the following
* attributes:
*
* attributes-charset
* attributes-natural-language
* requested-attributes
*/
request = ippNew();
request->request.op.operation_id = CUPS_GET_CLASSES;
request->request.op.request_id = 1;
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(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())));
goto out;
}
for (attr = response->attrs; attr != NULL;) {
/*
* Skip leading attributes until we hit a printer...
*/
while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
attr = attr->next;
if (attr == NULL)
break;
/*
* Pull the needed attributes from this printer...
*/
name = NULL;
info = NULL;
while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER) {
if (strcmp(attr->name, "printer-name") == 0 &&
attr->value_tag == IPP_TAG_NAME)
name = 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;
}
/*
* See if we have everything needed...
*/
if (name == NULL)
break;
if (!pcap_cache_add(name, info)) {
goto out;
}
}
ret = True;
out:
if (response)
ippDelete(response);
if (language)
cupsLangFree(language);
if (http)
httpClose(http);
return ret;
}
/*
* 'cups_job_delete()' - Delete a job.
*/
static int cups_job_delete(const char *sharename, const char *lprm_command, struct printjob *pjob)
{
int ret = 1; /* Return value */
http_t *http = NULL; /* HTTP connection to server */
ipp_t *request = NULL, /* IPP Request */
*response = NULL; /* IPP Response */
cups_lang_t *language = NULL; /* Default language */
char uri[HTTP_MAX_URI]; /* printer-uri attribute */
DEBUG(5,("cups_job_delete(%s, %p (%d))\n", sharename, pjob, pjob->sysjob));
/*
* Make sure we don't ask for passwords...
*/
cupsSetPasswordCB(cups_passwd_cb);
/*
* Try to connect to the server...
*/
if ((http = cups_connect()) == NULL) {
goto out;
}
/*
* 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, pjob->user);
/*
* Do the request and get back a response...
*/
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;
}
} else {
DEBUG(0,("Unable to cancel job %d - %s\n", pjob->sysjob,
ippErrorString(cupsLastError())));
}
out:
if (response)
ippDelete(response);
if (language)
cupsLangFree(language);
if (http)
httpClose(http);
return ret;
}
/*
* 'cups_job_pause()' - Pause a job.
*/
static int cups_job_pause(int snum, struct printjob *pjob)
{
int ret = 1; /* Return value */
http_t *http = NULL; /* HTTP connection to server */
ipp_t *request = NULL, /* IPP Request */
*response = NULL; /* IPP Response */
cups_lang_t *language = NULL; /* 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 = cups_connect()) == NULL) {
goto out;
}
/*
* 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, pjob->user);
/*
* Do the request and get back a response...
*/
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;
}
} else {
DEBUG(0,("Unable to hold job %d - %s\n", pjob->sysjob,
ippErrorString(cupsLastError())));
}
out:
if (response)
ippDelete(response);
if (language)
cupsLangFree(language);
if (http)
httpClose(http);
return ret;
}
/*
* 'cups_job_resume()' - Resume a paused job.
*/
static int cups_job_resume(int snum, struct printjob *pjob)
{
int ret = 1; /* Return value */
http_t *http = NULL; /* HTTP connection to server */
ipp_t *request = NULL, /* IPP Request */
*response = NULL; /* IPP Response */
cups_lang_t *language = NULL; /* 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 = cups_connect()) == NULL) {
goto out;
}
/*
* 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, pjob->user);
/*
* Do the request and get back a response...
*/
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;
}
} else {
DEBUG(0,("Unable to release job %d - %s\n", pjob->sysjob,
ippErrorString(cupsLastError())));
}
out:
if (response)
ippDelete(response);
if (language)
cupsLangFree(language);
if (http)
httpClose(http);
return ret;
}
/*
* 'cups_job_submit()' - Submit a job for printing.
*/
static int cups_job_submit(int snum, struct printjob *pjob)
{
int ret = 1; /* Return value */
http_t *http = NULL; /* HTTP connection to server */
ipp_t *request = NULL, /* IPP Request */
*response = NULL; /* IPP Response */
cups_lang_t *language = NULL; /* Default language */
char uri[HTTP_MAX_URI]; /* printer-uri attribute */
const char *clientname = NULL; /* hostname of client for job-originating-host attribute */
char *new_jobname = NULL;
int num_options = 0;
cups_option_t *options = NULL;
char addr[INET6_ADDRSTRLEN];
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 = cups_connect()) == NULL) {
goto out;
}
/*
* 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, pjob->user);
clientname = client_name(get_client_fd());
if (strcmp(clientname, "UNKNOWN") == 0) {
clientname = client_addr(get_client_fd(),addr,sizeof(addr));
}
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
"job-originating-host-name", NULL,
clientname);
if (asprintf(&new_jobname,"%s%.8u %s", PRINT_SPOOL_PREFIX,
(unsigned int)pjob->smbjob, pjob->jobname) < 0) {
goto out;
}
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
new_jobname);
/*
* add any options defined in smb.conf
*/
num_options = 0;
options = NULL;
num_options = cupsParseOptions(lp_cups_options(snum), num_options, &options);
if ( num_options )
cupsEncodeOptions(request, num_options, options);
/*
* Do the request and get back a response...
*/
slprintf(uri, sizeof(uri) - 1, "/printers/%s", PRINTERNAME(snum));
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;
}
} else {
DEBUG(0,("Unable to print file to `%s' - %s\n", PRINTERNAME(snum),
ippErrorString(cupsLastError())));
}
if ( ret == 0 )
unlink(pjob->filename);
/* else print_job_end will do it for us */
out:
if (response)
ippDelete(response);
if (language)
cupsLangFree(language);
if (http)
httpClose(http);
SAFE_FREE(new_jobname);
return ret;
}
/*
* 'cups_queue_get()' - Get all the jobs in the print queue.
*/
static int cups_queue_get(const char *sharename,
enum printing_types printing_type,
char *lpq_command,
print_queue_struct **q,
print_status_struct *status)
{
fstring printername;
http_t *http = NULL; /* HTTP connection to server */
ipp_t *request = NULL, /* IPP Request */
*response = NULL; /* IPP Response */
ipp_attribute_t *attr = NULL; /* Current attribute */
cups_lang_t *language = NULL; /* Default language */
char uri[HTTP_MAX_URI]; /* printer-uri attribute */
int qcount = 0, /* Number of active queue entries */
qalloc = 0; /* Number of queue entries allocated */
print_queue_struct *queue = NULL, /* 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"
};
*q = NULL;
/* HACK ALERT!!! The problem with support the 'printer name'
option is that we key the tdb off the sharename. So we will
overload the lpq_command string to pass in the printername
(which is basically what we do for non-cups printers ... using
the lpq_command to get the queue listing). */
fstrcpy( printername, lpq_command );
DEBUG(5,("cups_queue_get(%s, %p, %p)\n", printername, q, status));
/*
* Make sure we don't ask for passwords...
*/
cupsSetPasswordCB(cups_passwd_cb);
/*
* Try to connect to the server...
*/
if ((http = cups_connect()) == NULL) {
goto out;
}
/*
* Generate the printer URI...
*/
slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s", printername);
/*
* 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())));
goto out;
}
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)));
goto out;
}
/*
* 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;
r13915: Fixed a very interesting class of realloc() bugs found by Coverity. realloc can return NULL in one of two cases - (1) the realloc failed, (2) realloc succeeded but the new size requested was zero, in which case this is identical to a free() call. The error paths dealing with these two cases should be different, but mostly weren't. Secondly the standard idiom for dealing with realloc when you know the new size is non-zero is the following : tmp = realloc(p, size); if (!tmp) { SAFE_FREE(p); return error; } else { p = tmp; } However, there were *many* *many* places in Samba where we were using the old (broken) idiom of : p = realloc(p, size) if (!p) { return error; } which will leak the memory pointed to by p on realloc fail. This commit (hopefully) fixes all these cases by moving to a standard idiom of : p = SMB_REALLOC(p, size) if (!p) { return error; } Where if the realloc returns null due to the realloc failing or size == 0 we *guarentee* that the storage pointed to by p has been freed. This allows me to remove a lot of code that was dealing with the standard (more verbose) method that required a tmp pointer. This is almost always what you want. When a realloc fails you never usually want the old memory, you want to free it and get into your error processing asap. For the 11 remaining cases where we really do need to keep the old pointer I have invented the new macro SMB_REALLOC_KEEP_OLD_ON_ERROR, which can be used as follows : tmp = SMB_REALLOC_KEEP_OLD_ON_ERROR(p, size); if (!tmp) { SAFE_FREE(p); return error; } else { p = tmp; } SMB_REALLOC_KEEP_OLD_ON_ERROR guarentees never to free the pointer p, even on size == 0 or realloc fail. All this is done by a hidden extra argument to Realloc(), BOOL free_old_on_error which is set appropriately by the SMB_REALLOC and SMB_REALLOC_KEEP_OLD_ON_ERROR macros (and their array counterparts). It remains to be seen what this will do to our Coverity bug count :-). Jeremy. (This used to be commit 1d710d06a214f3f1740e80e0bffd6aab44aac2b0)
2006-03-07 09:31:04 +03:00
queue = SMB_REALLOC_ARRAY(queue, print_queue_struct, qalloc);
r13915: Fixed a very interesting class of realloc() bugs found by Coverity. realloc can return NULL in one of two cases - (1) the realloc failed, (2) realloc succeeded but the new size requested was zero, in which case this is identical to a free() call. The error paths dealing with these two cases should be different, but mostly weren't. Secondly the standard idiom for dealing with realloc when you know the new size is non-zero is the following : tmp = realloc(p, size); if (!tmp) { SAFE_FREE(p); return error; } else { p = tmp; } However, there were *many* *many* places in Samba where we were using the old (broken) idiom of : p = realloc(p, size) if (!p) { return error; } which will leak the memory pointed to by p on realloc fail. This commit (hopefully) fixes all these cases by moving to a standard idiom of : p = SMB_REALLOC(p, size) if (!p) { return error; } Where if the realloc returns null due to the realloc failing or size == 0 we *guarentee* that the storage pointed to by p has been freed. This allows me to remove a lot of code that was dealing with the standard (more verbose) method that required a tmp pointer. This is almost always what you want. When a realloc fails you never usually want the old memory, you want to free it and get into your error processing asap. For the 11 remaining cases where we really do need to keep the old pointer I have invented the new macro SMB_REALLOC_KEEP_OLD_ON_ERROR, which can be used as follows : tmp = SMB_REALLOC_KEEP_OLD_ON_ERROR(p, size); if (!tmp) { SAFE_FREE(p); return error; } else { p = tmp; } SMB_REALLOC_KEEP_OLD_ON_ERROR guarentees never to free the pointer p, even on size == 0 or realloc fail. All this is done by a hidden extra argument to Realloc(), BOOL free_old_on_error which is set appropriately by the SMB_REALLOC and SMB_REALLOC_KEEP_OLD_ON_ERROR macros (and their array counterparts). It remains to be seen what this will do to our Coverity bug count :-). Jeremy. (This used to be commit 1d710d06a214f3f1740e80e0bffd6aab44aac2b0)
2006-03-07 09:31:04 +03:00
if (queue == NULL) {
DEBUG(0,("cups_queue_get: Not enough memory!"));
qcount = 0;
goto out;
}
}
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->fs_user, user_name, sizeof(temp->fs_user) - 1);
strncpy(temp->fs_file, job_name, sizeof(temp->fs_file) - 1);
qcount ++;
if (attr == NULL)
break;
}
ippDelete(response);
response = NULL;
/*
* 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;
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,
ippErrorString(cupsLastError())));
*q = queue;
goto out;
}
if (response->request.status.status_code >= IPP_OK_CONFLICT) {
DEBUG(0,("Unable to get printer status for %s - %s\n", printername,
ippErrorString(response->request.status.status_code)));
*q = queue;
goto out;
}
/*
* 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);
/*
* Return the job queue...
*/
*q = queue;
out:
if (response)
ippDelete(response);
if (language)
cupsLangFree(language);
if (http)
httpClose(http);
return qcount;
}
/*
* 'cups_queue_pause()' - Pause a print queue.
*/
static int cups_queue_pause(int snum)
{
int ret = 1; /* Return value */
http_t *http = NULL; /* HTTP connection to server */
ipp_t *request = NULL, /* IPP Request */
*response = NULL; /* IPP Response */
cups_lang_t *language = NULL; /* 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 = cups_connect()) == NULL) {
goto out;
}
/*
* 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, current_user_info.unix_name);
/*
* Do the request and get back a response...
*/
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;
}
} else {
DEBUG(0,("Unable to pause printer %s - %s\n", PRINTERNAME(snum),
ippErrorString(cupsLastError())));
}
out:
if (response)
ippDelete(response);
if (language)
cupsLangFree(language);
if (http)
httpClose(http);
return ret;
}
/*
* 'cups_queue_resume()' - Restart a print queue.
*/
static int cups_queue_resume(int snum)
{
int ret = 1; /* Return value */
http_t *http = NULL; /* HTTP connection to server */
ipp_t *request = NULL, /* IPP Request */
*response = NULL; /* IPP Response */
cups_lang_t *language = NULL; /* 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 = cups_connect()) == NULL) {
goto out;
}
/*
* 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, current_user_info.unix_name);
/*
* Do the request and get back a response...
*/
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;
}
} else {
DEBUG(0,("Unable to resume printer %s - %s\n", PRINTERNAME(snum),
ippErrorString(cupsLastError())));
}
out:
if (response)
ippDelete(response);
if (language)
cupsLangFree(language);
if (http)
httpClose(http);
return ret;
}
/*******************************************************************
* CUPS printing interface definitions...
******************************************************************/
struct printif cups_printif =
{
PRINT_CUPS,
cups_queue_get,
cups_queue_pause,
cups_queue_resume,
cups_job_delete,
cups_job_pause,
cups_job_resume,
cups_job_submit,
};
bool cups_pull_comment_location(NT_PRINTER_INFO_LEVEL_2 *printer)
{
http_t *http = NULL; /* HTTP connection to server */
ipp_t *request = NULL, /* IPP Request */
*response = NULL; /* IPP Response */
ipp_attribute_t *attr; /* Current attribute */
cups_lang_t *language = NULL; /* Default language */
char *name, /* printer-name attribute */
*info, /* printer-info attribute */
*location; /* printer-location attribute */
char uri[HTTP_MAX_URI];
static const char *requested[] =/* Requested attributes */
{
"printer-name",
"printer-info",
"printer-location"
};
bool ret = False;
DEBUG(5, ("pulling %s location\n", printer->sharename));
/*
* Make sure we don't ask for passwords...
*/
cupsSetPasswordCB(cups_passwd_cb);
/*
* Try to connect to the server...
*/
if ((http = cups_connect()) == NULL) {
goto out;
}
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);
slprintf(uri, sizeof(uri) - 1, "ipp://%s/printers/%s",
lp_cups_server(), printer->sharename);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
"printer-uri", NULL, uri);
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 attributes - %s\n",
ippErrorString(cupsLastError())));
goto out;
}
for (attr = response->attrs; attr != NULL;) {
/*
* Skip leading attributes until we hit a printer...
*/
while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
attr = attr->next;
if (attr == NULL)
break;
/*
* Pull the needed attributes from this printer...
*/
name = NULL;
info = NULL;
location = NULL;
while ( attr && (attr->group_tag == IPP_TAG_PRINTER) ) {
/* Grab the comment if we don't have one */
if ( (strcmp(attr->name, "printer-info") == 0)
&& (attr->value_tag == IPP_TAG_TEXT)
&& !strlen(printer->comment) )
{
DEBUG(5,("cups_pull_comment_location: Using cups comment: %s\n",
attr->values[0].string.text));
strlcpy(printer->comment,
attr->values[0].string.text,
sizeof(printer->comment));
}
/* Grab the location if we don't have one */
if ( (strcmp(attr->name, "printer-location") == 0)
&& (attr->value_tag == IPP_TAG_TEXT)
&& !strlen(printer->location) )
{
DEBUG(5,("cups_pull_comment_location: Using cups location: %s\n",
attr->values[0].string.text));
fstrcpy(printer->location,attr->values[0].string.text);
}
attr = attr->next;
}
/*
* See if we have everything needed...
*/
if (name == NULL)
break;
}
ret = True;
out:
if (response)
ippDelete(response);
if (language)
cupsLangFree(language);
if (http)
httpClose(http);
return ret;
}
#else
/* this keeps fussy compilers happy */
void print_cups_dummy(void);
void print_cups_dummy(void) {}
#endif /* HAVE_CUPS */