gnome-control-center/panels/printers/pp-cups.c
Philip Chimento 389ee0dfe5 printers: Use CUPS httpConnect2() if available
In CUPS 1.7 httpConnect() and httpConnectEncrypt() were deprecated and
replaced with httpConnect2(). This checks if httpConnect2() is available
and if so, replaces the uses of the deprecated functions.

In the CUPS source code, httpConnect() and httpConnectEncrypt() are now
wrappers around httpConnect2(), so we make sure to use the same
arguments as in the CUPS source code so the two code paths are sure to
be identical:
2c030c7a06/cups/http.c (L412)
2c030c7a06/cups/http.c (L477)
2019-09-16 14:09:40 -07:00

329 lines
10 KiB
C

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright 2012 Red Hat, Inc,
*
* 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 2 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/>.
*
* Author: Marek Kasik <mkasik@redhat.com>
*/
#include "config.h"
#include "pp-cups.h"
#if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 5)
#define HAVE_CUPS_1_6 1
#endif
#ifndef HAVE_CUPS_1_6
#define ippGetInteger(attr, element) attr->values[element].integer
#define ippGetStatusCode(ipp) ipp->request.status.status_code
#endif
struct _PpCups
{
GObject parent_instance;
};
G_DEFINE_TYPE (PpCups, pp_cups, G_TYPE_OBJECT);
static void
pp_cups_finalize (GObject *object)
{
G_OBJECT_CLASS (pp_cups_parent_class)->finalize (object);
}
static void
pp_cups_class_init (PpCupsClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->finalize = pp_cups_finalize;
}
static void
pp_cups_init (PpCups *self)
{
}
PpCups *
pp_cups_new ()
{
return g_object_new (PP_TYPE_CUPS, NULL);
}
static void
pp_cups_dests_free (PpCupsDests *dests)
{
cupsFreeDests (dests->num_of_dests, dests->dests);
}
static void
_pp_cups_get_dests_thread (GTask *task,
gpointer *object,
gpointer task_data,
GCancellable *cancellable)
{
PpCupsDests *dests;
dests = g_new0 (PpCupsDests, 1);
dests->num_of_dests = cupsGetDests (&dests->dests);
if (g_task_set_return_on_cancel (task, FALSE))
{
g_task_return_pointer (task, dests, (GDestroyNotify) pp_cups_dests_free);
}
else
{
pp_cups_dests_free (dests);
}
}
void
pp_cups_get_dests_async (PpCups *self,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GTask *task;
task = g_task_new (self, cancellable, callback, user_data);
g_task_set_return_on_cancel (task, TRUE);
g_task_run_in_thread (task, (GTaskThreadFunc) _pp_cups_get_dests_thread);
g_object_unref (task);
}
PpCupsDests *
pp_cups_get_dests_finish (PpCups *self,
GAsyncResult *res,
GError **error)
{
g_return_val_if_fail (g_task_is_valid (res, self), NULL);
return g_task_propagate_pointer (G_TASK (res), error);
}
static void
connection_test_thread (GTask *task,
gpointer source_object,
gpointer task_data,
GCancellable *cancellable)
{
http_t *http;
#ifdef HAVE_CUPS_HTTPCONNECT2
http = httpConnect2 (cupsServer (), ippPort (), NULL, AF_UNSPEC,
cupsEncryption (), 1, 30000, NULL);
#else
http = httpConnectEncrypt (cupsServer (), ippPort (), cupsEncryption ());
#endif
httpClose (http);
if (g_task_set_return_on_cancel (task, FALSE))
{
g_task_return_boolean (task, http != NULL);
}
}
void
pp_cups_connection_test_async (PpCups *self,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GTask *task;
task = g_task_new (self, cancellable, callback, user_data);
g_task_set_return_on_cancel (task, TRUE);
g_task_run_in_thread (task, connection_test_thread);
g_object_unref (task);
}
gboolean
pp_cups_connection_test_finish (PpCups *self,
GAsyncResult *result,
GError **error)
{
g_return_val_if_fail (g_task_is_valid (result, self), FALSE);
return g_task_propagate_boolean (G_TASK (result), error);
}
/* Cancels subscription of given id */
static void
cancel_subscription_thread (GTask *task,
gpointer source_object,
gpointer task_data,
GCancellable *cancellable)
{
ipp_t *request;
ipp_t *response = NULL;
gint id = GPOINTER_TO_INT (task_data);
if (id >= 0)
{
request = ippNewRequest (IPP_CANCEL_SUBSCRIPTION);
ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_URI,
"printer-uri", NULL, "/");
ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_NAME,
"requesting-user-name", NULL, cupsUser ());
ippAddInteger (request, IPP_TAG_OPERATION, IPP_TAG_INTEGER,
"notify-subscription-id", id);
response = cupsDoRequest (CUPS_HTTP_DEFAULT, request, "/");
}
g_task_return_boolean (task, response != NULL && ippGetStatusCode (response) <= IPP_OK);
ippDelete (response);
}
void
pp_cups_cancel_subscription_async (PpCups *self,
gint subscription_id,
GAsyncReadyCallback callback,
gpointer user_data)
{
GTask *task;
task = g_task_new (self, NULL, callback, user_data);
g_task_set_task_data (task, GINT_TO_POINTER (subscription_id), NULL);
g_task_run_in_thread (task, cancel_subscription_thread);
g_object_unref (task);
}
gboolean
pp_cups_cancel_subscription_finish (PpCups *self,
GAsyncResult *result)
{
g_return_val_if_fail (g_task_is_valid (result, self), FALSE);
return g_task_propagate_boolean (G_TASK (result), NULL);
}
typedef struct {
gint id;
gchar **events;
int lease_duration;
} CRSData;
static void
crs_data_free (CRSData *data)
{
g_strfreev (data->events);
g_slice_free (CRSData, data);
}
static void
renew_subscription_thread (GTask *task,
gpointer source_object,
gpointer task_data,
GCancellable *cancellable)
{
ipp_attribute_t *attr = NULL;
CRSData *subscription_data = task_data;
ipp_t *request;
ipp_t *response = NULL;
gint result = -1;
if (g_cancellable_is_cancelled (cancellable))
return;
if (subscription_data->id > 0)
{
request = ippNewRequest (IPP_RENEW_SUBSCRIPTION);
ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_URI,
"printer-uri", NULL, "/");
ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_NAME,
"requesting-user-name", NULL, cupsUser ());
ippAddInteger (request, IPP_TAG_OPERATION, IPP_TAG_INTEGER,
"notify-subscription-id", subscription_data->id);
ippAddInteger (request, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
"notify-lease-duration", subscription_data->lease_duration);
response = cupsDoRequest (CUPS_HTTP_DEFAULT, request, "/");
if (response != NULL && ippGetStatusCode (response) <= IPP_OK_CONFLICT)
{
if ((attr = ippFindAttribute (response, "notify-lease-duration", IPP_TAG_INTEGER)) == NULL)
g_debug ("No notify-lease-duration in response!\n");
else if (ippGetInteger (attr, 0) == subscription_data->lease_duration)
result = subscription_data->id;
}
}
if (result < 0)
{
request = ippNewRequest (IPP_CREATE_PRINTER_SUBSCRIPTION);
ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_URI,
"printer-uri", NULL, "/");
ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_NAME,
"requesting-user-name", NULL, cupsUser ());
ippAddStrings (request, IPP_TAG_SUBSCRIPTION, IPP_TAG_KEYWORD,
"notify-events", g_strv_length (subscription_data->events), NULL,
(const char * const *) subscription_data->events);
ippAddString (request, IPP_TAG_SUBSCRIPTION, IPP_TAG_KEYWORD,
"notify-pull-method", NULL, "ippget");
ippAddString (request, IPP_TAG_SUBSCRIPTION, IPP_TAG_URI,
"notify-recipient-uri", NULL, "dbus://");
ippAddInteger (request, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
"notify-lease-duration", subscription_data->lease_duration);
response = cupsDoRequest (CUPS_HTTP_DEFAULT, request, "/");
if (response != NULL && ippGetStatusCode (response) <= IPP_OK_CONFLICT)
{
if ((attr = ippFindAttribute (response, "notify-subscription-id", IPP_TAG_INTEGER)) == NULL)
g_debug ("No notify-subscription-id in response!\n");
else
result = ippGetInteger (attr, 0);
}
}
ippDelete (response);
g_task_return_int (task, result);
}
void
pp_cups_renew_subscription_async (PpCups *self,
gint subscription_id,
gchar **events,
gint lease_duration,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
CRSData *subscription_data;
GTask *task;
subscription_data = g_slice_new (CRSData);
subscription_data->id = subscription_id;
subscription_data->events = g_strdupv (events);
subscription_data->lease_duration = lease_duration;
task = g_task_new (self, cancellable, callback, user_data);
g_task_set_task_data (task, subscription_data, (GDestroyNotify) crs_data_free);
g_task_run_in_thread (task, renew_subscription_thread);
g_object_unref (task);
}
/* Returns id of renewed subscription or new id */
gint
pp_cups_renew_subscription_finish (PpCups *self,
GAsyncResult *result)
{
g_return_val_if_fail (g_task_is_valid (result, self), FALSE);
return g_task_propagate_int (G_TASK (result), NULL);
}