[gnome-control-center] printers: Add PpHost object for listing print devices
- From: Marek KaÅÃk <mkasik src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-control-center] printers: Add PpHost object for listing print devices
- Date: Tue, 4 Sep 2012 12:11:19 +0000 (UTC)
commit 142d2c65b4fa01100d7cc8d6f6ca856c94d07182
Author: Marek Kasik <mkasik redhat com>
Date: Mon Sep 3 20:04:38 2012 +0200
printers: Add PpHost object for listing print devices
This commit adds PpHost object which represents a remote
host from which we want to get printers. It contains
asynchronous method for enumerating printers list from the host
using CUPS' SNMP backend and method for enumerating printers list
directly from the remote CUPS server running on the host. (#683229)
panels/printers/Makefile.am | 2 +
panels/printers/pp-host.c | 459 +++++++++++++++++++++++++++++++++++++++++++
panels/printers/pp-host.h | 82 ++++++++
panels/printers/pp-utils.h | 4 +-
4 files changed, 546 insertions(+), 1 deletions(-)
---
diff --git a/panels/printers/Makefile.am b/panels/printers/Makefile.am
index acd742b..f4a46a2 100644
--- a/panels/printers/Makefile.am
+++ b/panels/printers/Makefile.am
@@ -22,6 +22,8 @@ ccpanels_LTLIBRARIES = libprinters.la
libprinters_la_SOURCES = \
printers-module.c \
+ pp-host.c \
+ pp-host.h \
pp-cups.c \
pp-cups.h \
pp-utils.c \
diff --git a/panels/printers/pp-host.c b/panels/printers/pp-host.c
new file mode 100644
index 0000000..f6724b0
--- /dev/null
+++ b/panels/printers/pp-host.c
@@ -0,0 +1,459 @@
+/* -*- 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 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Author: Marek Kasik <mkasik redhat com>
+ */
+
+#include "pp-host.h"
+
+struct _PpHostPrivate
+{
+ gchar *hostname;
+ gint port;
+};
+
+G_DEFINE_TYPE (PpHost, pp_host, G_TYPE_OBJECT);
+
+enum {
+ PROP_0 = 0,
+ PROP_HOSTNAME,
+ PROP_PORT,
+};
+
+static void
+pp_host_finalize (GObject *object)
+{
+ PpHostPrivate *priv;
+
+ priv = PP_HOST (object)->priv;
+
+ g_clear_pointer (&priv->hostname, g_free);
+
+ G_OBJECT_CLASS (pp_host_parent_class)->finalize (object);
+}
+
+static void
+pp_host_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *param_spec)
+{
+ PpHost *self;
+
+ self = PP_HOST (object);
+
+ switch (prop_id)
+ {
+ case PROP_HOSTNAME:
+ g_value_set_string (value, self->priv->hostname);
+ break;
+ case PROP_PORT:
+ g_value_set_int (value, self->priv->port);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object,
+ prop_id,
+ param_spec);
+ break;
+ }
+}
+
+static void
+pp_host_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *param_spec)
+{
+ PpHost *self = PP_HOST (object);
+
+ switch (prop_id)
+ {
+ case PROP_HOSTNAME:
+ g_free (self->priv->hostname);
+ self->priv->hostname = g_value_dup_string (value);
+ break;
+ case PROP_PORT:
+ self->priv->port = g_value_get_int (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object,
+ prop_id,
+ param_spec);
+ break;
+ }
+}
+
+static void
+pp_host_class_init (PpHostClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (PpHostPrivate));
+
+ gobject_class->set_property = pp_host_set_property;
+ gobject_class->get_property = pp_host_get_property;
+ gobject_class->finalize = pp_host_finalize;
+
+ g_object_class_install_property (gobject_class, PROP_HOSTNAME,
+ g_param_spec_string ("hostname",
+ "Hostname",
+ "The hostname",
+ NULL,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class, PROP_PORT,
+ g_param_spec_int ("port",
+ "Port",
+ "The port",
+ 0, G_MAXINT32, 631,
+ G_PARAM_READWRITE));
+}
+
+static void
+pp_host_init (PpHost *host)
+{
+ host->priv = G_TYPE_INSTANCE_GET_PRIVATE (host,
+ PP_TYPE_HOST,
+ PpHostPrivate);
+}
+
+PpHost *
+pp_host_new (const gchar *hostname,
+ gint port)
+{
+ return g_object_new (PP_TYPE_HOST,
+ "hostname", hostname,
+ "port", port,
+ NULL);
+}
+
+typedef struct
+{
+ PpDevicesList *devices;
+} GSDData;
+
+static gchar **
+line_split (gchar *line)
+{
+ gboolean escaped = FALSE;
+ gboolean quoted = FALSE;
+ gboolean in_word = FALSE;
+ gchar **words = NULL;
+ gchar **result = NULL;
+ gchar *buffer = NULL;
+ gchar ch;
+ gint n = 0;
+ gint i, j = 0, k = 0;
+
+ if (line)
+ {
+ n = strlen (line);
+ words = g_new0 (gchar *, n + 1);
+ buffer = g_new0 (gchar, n + 1);
+
+ for (i = 0; i < n; i++)
+ {
+ ch = line[i];
+
+ if (escaped)
+ {
+ buffer[k++] = ch;
+ escaped = FALSE;
+ continue;
+ }
+
+ if (ch == '\\')
+ {
+ in_word = TRUE;
+ escaped = TRUE;
+ continue;
+ }
+
+ if (in_word)
+ {
+ if (quoted)
+ {
+ if (ch == '"')
+ quoted = FALSE;
+ else
+ buffer[k++] = ch;
+ }
+ else if (g_ascii_isspace (ch))
+ {
+ words[j++] = g_strdup (buffer);
+ memset (buffer, 0, n + 1);
+ k = 0;
+ in_word = FALSE;
+ }
+ else if (ch == '"')
+ quoted = TRUE;
+ else
+ buffer[k++] = ch;
+ }
+ else
+ {
+ if (ch == '"')
+ {
+ in_word = TRUE;
+ quoted = TRUE;
+ }
+ else if (!g_ascii_isspace (ch))
+ {
+ in_word = TRUE;
+ buffer[k++] = ch;
+ }
+ }
+ }
+ }
+
+ if (buffer && buffer[0] != '\0')
+ words[j++] = g_strdup (buffer);
+
+ result = g_strdupv (words);
+ g_strfreev (words);
+ g_free (buffer);
+
+ return result;
+}
+
+static void
+_pp_host_get_snmp_devices_thread (GSimpleAsyncResult *res,
+ GObject *object,
+ GCancellable *cancellable)
+{
+ PpHost *host = (PpHost *) object;
+ PpHostPrivate *priv = host->priv;
+ PpPrintDevice *device;
+ GSDData *data;
+ GError *error;
+ gchar **argv;
+ gchar *stdout_string = NULL;
+ gchar *stderr_string = NULL;
+ gint exit_status;
+
+ data = g_simple_async_result_get_op_res_gpointer (res);
+ data->devices = g_new0 (PpDevicesList, 1);
+ data->devices->devices = NULL;
+
+ argv = g_new0 (gchar *, 3);
+ argv[0] = g_strdup ("/usr/lib/cups/backend/snmp");
+ argv[1] = g_strdup (priv->hostname);
+
+ /* Use SNMP to get printer's informations */
+ g_spawn_sync (NULL,
+ argv,
+ NULL,
+ 0,
+ NULL,
+ NULL,
+ &stdout_string,
+ &stderr_string,
+ &exit_status,
+ &error);
+
+ g_free (argv[1]);
+ g_free (argv[0]);
+ g_free (argv);
+
+ if (exit_status == 0 && stdout_string)
+ {
+ gchar **printer_informations = NULL;
+ gint length;
+
+ printer_informations = line_split (stdout_string);
+ length = g_strv_length (printer_informations);
+
+ if (length >= 4)
+ {
+ device = g_new0 (PpPrintDevice, 1);
+
+ device->device_class = g_strdup (printer_informations[0]);
+ device->device_uri = g_strdup (printer_informations[1]);
+ device->device_make_and_model = g_strdup (printer_informations[2]);
+ device->device_info = g_strdup (printer_informations[3]);
+ device->device_name = g_strdup (printer_informations[3]);
+ device->device_name =
+ g_strcanon (device->device_name, ALLOWED_CHARACTERS, '-');
+ device->acquisition_method = ACQUISITION_METHOD_SNMP;
+
+ if (length >= 5 && printer_informations[4][0] != '\0')
+ device->device_id = g_strdup (printer_informations[4]);
+
+ if (length >= 6 && printer_informations[5][0] != '\0')
+ device->device_location = g_strdup (printer_informations[5]);
+
+ data->devices->devices = g_list_append (data->devices->devices, device);
+ }
+
+ g_strfreev (printer_informations);
+ g_free (stdout_string);
+ }
+}
+
+static void
+gsd_data_free (GSDData *data)
+{
+ GList *iter;
+
+ if (data)
+ {
+ if (data->devices)
+ {
+ if (data->devices->devices)
+ {
+ for (iter = data->devices->devices; iter; iter = iter->next)
+ pp_print_device_free ((PpPrintDevice *) iter->data);
+ g_list_free (data->devices->devices);
+ }
+
+ g_free (data->devices);
+ }
+
+ g_free (data);
+ }
+}
+
+void
+pp_host_get_snmp_devices_async (PpHost *host,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *res;
+ GSDData *data;
+
+ res = g_simple_async_result_new (G_OBJECT (host), callback, user_data, pp_host_get_snmp_devices_async);
+ data = g_new0 (GSDData, 1);
+ data->devices = NULL;
+
+ g_simple_async_result_set_check_cancellable (res, cancellable);
+ g_simple_async_result_set_op_res_gpointer (res, data, (GDestroyNotify) gsd_data_free);
+ g_simple_async_result_run_in_thread (res, _pp_host_get_snmp_devices_thread, 0, cancellable);
+
+ g_object_unref (res);
+}
+
+PpDevicesList *
+pp_host_get_snmp_devices_finish (PpHost *host,
+ GAsyncResult *res,
+ GError **error)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
+ GSDData *data;
+ PpDevicesList *result;
+
+ g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == pp_host_get_snmp_devices_async);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return NULL;
+
+ data = g_simple_async_result_get_op_res_gpointer (simple);
+ result = data->devices;
+ data->devices = NULL;
+
+ return result;
+}
+
+static void
+_pp_host_get_remote_cups_devices_thread (GSimpleAsyncResult *res,
+ GObject *object,
+ GCancellable *cancellable)
+{
+ cups_dest_t *dests = NULL;
+ GSDData *data;
+ PpHost *host = (PpHost *) object;
+ PpHostPrivate *priv = host->priv;
+ PpPrintDevice *device;
+ http_t *http;
+ gint num_of_devices = 0;
+ gint i;
+
+ data = g_simple_async_result_get_op_res_gpointer (res);
+ data->devices = g_new0 (PpDevicesList, 1);
+ data->devices->devices = NULL;
+
+ /* Connect to remote CUPS server and get its devices */
+ http = httpConnect (priv->hostname, priv->port);
+ if (http)
+ {
+ num_of_devices = cupsGetDests2 (http, &dests);
+ if (num_of_devices > 0)
+ {
+ for (i = 0; i < num_of_devices; i++)
+ {
+ device = g_new0 (PpPrintDevice, 1);
+ device->device_class = g_strdup ("network");
+ device->device_uri = g_strdup_printf ("ipp://%s:%d/printers/%s",
+ priv->hostname,
+ priv->port,
+ dests[i].name);
+ device->device_name = g_strdup (dests[i].name);
+ device->device_location = g_strdup (cupsGetOption ("printer-location",
+ dests[i].num_options,
+ dests[i].options));
+ device->host_name = g_strdup (priv->hostname);
+ device->host_port = priv->port;
+ device->acquisition_method = ACQUISITION_METHOD_REMOTE_CUPS_SERVER;
+ data->devices->devices = g_list_append (data->devices->devices, device);
+ }
+ }
+
+ httpClose (http);
+ }
+}
+
+void
+pp_host_get_remote_cups_devices_async (PpHost *host,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *res;
+ GSDData *data;
+
+ res = g_simple_async_result_new (G_OBJECT (host), callback, user_data, pp_host_get_remote_cups_devices_async);
+ data = g_new0 (GSDData, 1);
+ data->devices = NULL;
+
+ g_simple_async_result_set_check_cancellable (res, cancellable);
+ g_simple_async_result_set_op_res_gpointer (res, data, (GDestroyNotify) gsd_data_free);
+ g_simple_async_result_run_in_thread (res, _pp_host_get_remote_cups_devices_thread, 0, cancellable);
+
+ g_object_unref (res);
+}
+
+PpDevicesList *
+pp_host_get_remote_cups_devices_finish (PpHost *host,
+ GAsyncResult *res,
+ GError **error)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
+ GSDData *data;
+ PpDevicesList *result;
+
+ g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == pp_host_get_remote_cups_devices_async);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return NULL;
+
+ data = g_simple_async_result_get_op_res_gpointer (simple);
+ result = data->devices;
+ data->devices = NULL;
+
+ return result;
+}
diff --git a/panels/printers/pp-host.h b/panels/printers/pp-host.h
new file mode 100644
index 0000000..603c4e0
--- /dev/null
+++ b/panels/printers/pp-host.h
@@ -0,0 +1,82 @@
+/* -*- 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 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Author: Marek Kasik <mkasik redhat com>
+ */
+
+#ifndef __PP_HOST_H__
+#define __PP_HOST_H__
+
+#include <glib-object.h>
+#include <gio/gio.h>
+#include "pp-utils.h"
+
+G_BEGIN_DECLS
+
+#define PP_TYPE_HOST (pp_host_get_type ())
+#define PP_HOST(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), PP_TYPE_HOST, PpHost))
+#define PP_HOST_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), PP_TYPE_HOST, PpHostClass))
+#define PP_IS_HOST(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), PP_TYPE_HOST))
+#define PP_IS_HOST_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), PP_TYPE_HOST))
+#define PP_HOST_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), PP_TYPE_HOST, PpHostClass))
+
+typedef struct{
+ GList *devices;
+} PpDevicesList;
+
+typedef struct _PpHost PpHost;
+typedef struct _PpHostClass PpHostClass;
+typedef struct _PpHostPrivate PpHostPrivate;
+
+struct _PpHost
+{
+ GObject parent_instance;
+ PpHostPrivate *priv;
+};
+
+struct _PpHostClass
+{
+ GObjectClass parent_class;
+};
+
+GType pp_host_get_type (void) G_GNUC_CONST;
+
+PpHost *pp_host_new (const gchar *hostname,
+ gint port);
+
+void pp_host_get_snmp_devices_async (PpHost *host,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+PpDevicesList *pp_host_get_snmp_devices_finish (PpHost *host,
+ GAsyncResult *result,
+ GError **error);
+
+void pp_host_get_remote_cups_devices_async (PpHost *host,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+PpDevicesList *pp_host_get_remote_cups_devices_finish (PpHost *host,
+ GAsyncResult *result,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* __PP_HOST_H__ */
diff --git a/panels/printers/pp-utils.h b/panels/printers/pp-utils.h
index a497f3f..0299979 100644
--- a/panels/printers/pp-utils.h
+++ b/panels/printers/pp-utils.h
@@ -48,7 +48,9 @@ enum
enum
{
- ACQUISITION_METHOD_DEFAULT_CUPS_SERVER = 0
+ ACQUISITION_METHOD_DEFAULT_CUPS_SERVER = 0,
+ ACQUISITION_METHOD_REMOTE_CUPS_SERVER,
+ ACQUISITION_METHOD_SNMP
};
typedef struct
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]