Add pp_host_get_lpd_devices_async() and pp_host_get_lpd_devices_finish() functions to PpHost class. pp_host_get_lpd_devices_async() starts searching for LPD printer on given address. The test consist in connection to the default port 515 (or the one given by creator of PpHost) of the address and sending a print job to it, which in turn returns a status (we test several standard queue names). We suppose that there is a LPD printer on the address if a buffer with zero length is returned (rfc 1179 5.2). https://bugzilla.gnome.org/show_bug.cgi?id=695564
801 lines
24 KiB
C
801 lines
24 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 "pp-host.h"
|
|
|
|
#include <glib/gi18n.h>
|
|
|
|
#define BUFFER_LENGTH 1024
|
|
|
|
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",
|
|
-1, G_MAXINT32, PP_HOST_UNSET_PORT,
|
|
G_PARAM_READWRITE));
|
|
}
|
|
|
|
static void
|
|
pp_host_init (PpHost *host)
|
|
{
|
|
host->priv = G_TYPE_INSTANCE_GET_PRIVATE (host,
|
|
PP_TYPE_HOST,
|
|
PpHostPrivate);
|
|
host->priv->port = PP_HOST_UNSET_PORT;
|
|
}
|
|
|
|
PpHost *
|
|
pp_host_new (const gchar *hostname)
|
|
{
|
|
return g_object_new (PP_TYPE_HOST,
|
|
"hostname", hostname,
|
|
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)
|
|
{
|
|
if (data)
|
|
{
|
|
pp_devices_list_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 port;
|
|
gint i;
|
|
|
|
data = g_simple_async_result_get_op_res_gpointer (res);
|
|
data->devices = g_new0 (PpDevicesList, 1);
|
|
data->devices->devices = NULL;
|
|
|
|
if (priv->port == PP_HOST_UNSET_PORT)
|
|
port = PP_HOST_DEFAULT_IPP_PORT;
|
|
else
|
|
port = priv->port;
|
|
|
|
/* Connect to remote CUPS server and get its devices */
|
|
http = httpConnect (priv->hostname, 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,
|
|
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 = 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;
|
|
}
|
|
|
|
typedef struct
|
|
{
|
|
PpDevicesList *devices;
|
|
PpHost *host;
|
|
gint port;
|
|
} JetDirectData;
|
|
|
|
static void
|
|
jetdirect_data_free (JetDirectData *data)
|
|
{
|
|
if (data != NULL)
|
|
{
|
|
pp_devices_list_free (data->devices);
|
|
g_clear_object (&data->host);
|
|
g_free (data);
|
|
}
|
|
}
|
|
|
|
static void
|
|
jetdirect_connection_test_cb (GObject *source_object,
|
|
GAsyncResult *res,
|
|
gpointer user_data)
|
|
{
|
|
GSocketConnection *connection;
|
|
PpHostPrivate *priv;
|
|
PpPrintDevice *device;
|
|
JetDirectData *data;
|
|
gpointer result;
|
|
GError *error = NULL;
|
|
GTask *task = G_TASK (user_data);
|
|
|
|
data = g_task_get_task_data (task);
|
|
|
|
connection = g_socket_client_connect_to_host_finish (G_SOCKET_CLIENT (source_object),
|
|
res,
|
|
&error);
|
|
|
|
if (connection != NULL)
|
|
{
|
|
g_io_stream_close (G_IO_STREAM (connection), NULL, NULL);
|
|
g_object_unref (connection);
|
|
|
|
priv = data->host->priv;
|
|
|
|
device = g_new0 (PpPrintDevice, 1);
|
|
device->device_class = g_strdup ("network");
|
|
device->device_uri = g_strdup_printf ("socket://%s:%d",
|
|
priv->hostname,
|
|
data->port);
|
|
/* Translators: The found device is a JetDirect printer */
|
|
device->device_name = g_strdup (_("JetDirect Printer"));
|
|
device->host_name = g_strdup (priv->hostname);
|
|
device->host_port = data->port;
|
|
device->acquisition_method = ACQUISITION_METHOD_JETDIRECT;
|
|
|
|
data->devices->devices = g_list_append (data->devices->devices, device);
|
|
}
|
|
|
|
result = data->devices;
|
|
data->devices = NULL;
|
|
g_task_return_pointer (task, result, (GDestroyNotify) pp_devices_list_free);
|
|
g_object_unref (task);
|
|
}
|
|
|
|
/* Test whether given host has an AppSocket/HP JetDirect printer connected.
|
|
See http://en.wikipedia.org/wiki/JetDirect
|
|
http://www.cups.org/documentation.php/network.html */
|
|
void
|
|
pp_host_get_jetdirect_devices_async (PpHost *host,
|
|
GCancellable *cancellable,
|
|
GAsyncReadyCallback callback,
|
|
gpointer user_data)
|
|
{
|
|
PpHostPrivate *priv = host->priv;
|
|
GSocketClient *client;
|
|
JetDirectData *data;
|
|
GTask *task;
|
|
gchar *address;
|
|
gpointer result;
|
|
|
|
data = g_new0 (JetDirectData, 1);
|
|
data->host = g_object_ref (host);
|
|
data->devices = g_new0 (PpDevicesList, 1);
|
|
|
|
if (priv->port == PP_HOST_UNSET_PORT)
|
|
data->port = PP_HOST_DEFAULT_JETDIRECT_PORT;
|
|
else
|
|
data->port = priv->port;
|
|
|
|
task = g_task_new (G_OBJECT (host), cancellable, callback, user_data);
|
|
g_task_set_task_data (task, data, (GDestroyNotify) jetdirect_data_free);
|
|
|
|
address = g_strdup_printf ("%s:%d", priv->hostname, data->port);
|
|
if (address != NULL && address[0] != '/')
|
|
{
|
|
client = g_socket_client_new ();
|
|
|
|
g_socket_client_connect_to_host_async (client,
|
|
address,
|
|
data->port,
|
|
cancellable,
|
|
jetdirect_connection_test_cb,
|
|
task);
|
|
|
|
g_object_unref (client);
|
|
}
|
|
else
|
|
{
|
|
result = data->devices;
|
|
data->devices = NULL;
|
|
g_task_return_pointer (task, result, (GDestroyNotify) pp_devices_list_free);
|
|
g_object_unref (task);
|
|
}
|
|
|
|
g_free (address);
|
|
}
|
|
|
|
PpDevicesList *
|
|
pp_host_get_jetdirect_devices_finish (PpHost *host,
|
|
GAsyncResult *res,
|
|
GError **error)
|
|
{
|
|
g_return_val_if_fail (g_task_is_valid (res, host), NULL);
|
|
|
|
return g_task_propagate_pointer (G_TASK (res), error);
|
|
}
|
|
|
|
static gboolean
|
|
test_lpd_queue (GSocketClient *client,
|
|
gchar *address,
|
|
gint port,
|
|
GCancellable *cancellable,
|
|
gchar *queue_name)
|
|
{
|
|
GSocketConnection *connection;
|
|
gboolean result = FALSE;
|
|
GError *error = NULL;
|
|
|
|
connection = g_socket_client_connect_to_host (client,
|
|
address,
|
|
port,
|
|
cancellable,
|
|
&error);
|
|
|
|
if (connection != NULL)
|
|
{
|
|
if (G_IS_TCP_CONNECTION (connection))
|
|
{
|
|
GOutputStream *output;
|
|
GInputStream *input;
|
|
gssize bytes_read, bytes_written;
|
|
gchar buffer[BUFFER_LENGTH];
|
|
gint length;
|
|
|
|
output = g_io_stream_get_output_stream (G_IO_STREAM (connection));
|
|
input = g_io_stream_get_input_stream (G_IO_STREAM (connection));
|
|
|
|
/* This LPD command is explained in RFC 1179, section 5.2 */
|
|
length = g_snprintf (buffer, BUFFER_LENGTH, "\2%s\n", queue_name);
|
|
|
|
bytes_written = g_output_stream_write (output,
|
|
buffer,
|
|
length,
|
|
NULL,
|
|
&error);
|
|
|
|
if (bytes_written != -1)
|
|
{
|
|
bytes_read = g_input_stream_read (input,
|
|
buffer,
|
|
BUFFER_LENGTH,
|
|
NULL,
|
|
&error);
|
|
|
|
if (bytes_read != -1)
|
|
{
|
|
if (bytes_read > 0 && buffer[0] == 0)
|
|
{
|
|
/* This LPD command is explained in RFC 1179, section 6.1 */
|
|
length = g_snprintf (buffer, BUFFER_LENGTH, "\1\n");
|
|
|
|
bytes_written = g_output_stream_write (output,
|
|
buffer,
|
|
length,
|
|
NULL,
|
|
&error);
|
|
|
|
result = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
g_clear_error (&error);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
g_clear_error (&error);
|
|
}
|
|
}
|
|
|
|
g_io_stream_close (G_IO_STREAM (connection), NULL, NULL);
|
|
g_object_unref (connection);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static void
|
|
_pp_host_get_lpd_devices_thread (GTask *task,
|
|
gpointer source_object,
|
|
gpointer task_data,
|
|
GCancellable *cancellable)
|
|
{
|
|
GSocketConnection *connection;
|
|
PpPrintDevice *device;
|
|
PpHost *host = (PpHost *) source_object;
|
|
PpHostPrivate *priv = host->priv;
|
|
GSocketClient *client;
|
|
PpDevicesList *result;
|
|
GSDData *data = (GSDData *) task_data;
|
|
GError *error = NULL;
|
|
GList *candidates = NULL;
|
|
GList *iter;
|
|
gchar *found_queue = NULL;
|
|
gchar *candidate;
|
|
gchar *address;
|
|
gint port;
|
|
gint i;
|
|
|
|
if (priv->port == PP_HOST_UNSET_PORT)
|
|
port = PP_HOST_DEFAULT_LPD_PORT;
|
|
else
|
|
port = priv->port;
|
|
|
|
address = g_strdup_printf ("%s:%d", priv->hostname, port);
|
|
if (address == NULL || address[0] == '/')
|
|
goto out;
|
|
|
|
result = data->devices;
|
|
data->devices = NULL;
|
|
|
|
client = g_socket_client_new ();
|
|
|
|
connection = g_socket_client_connect_to_host (client,
|
|
address,
|
|
port,
|
|
cancellable,
|
|
&error);
|
|
|
|
if (connection != NULL)
|
|
{
|
|
g_io_stream_close (G_IO_STREAM (connection), NULL, NULL);
|
|
g_object_unref (connection);
|
|
|
|
/* Most of this list is taken from system-config-printer */
|
|
candidates = g_list_append (candidates, g_strdup ("PASSTHRU"));
|
|
candidates = g_list_append (candidates, g_strdup ("AUTO"));
|
|
candidates = g_list_append (candidates, g_strdup ("BINPS"));
|
|
candidates = g_list_append (candidates, g_strdup ("RAW"));
|
|
candidates = g_list_append (candidates, g_strdup ("TEXT"));
|
|
candidates = g_list_append (candidates, g_strdup ("ps"));
|
|
candidates = g_list_append (candidates, g_strdup ("lp"));
|
|
candidates = g_list_append (candidates, g_strdup ("PORT1"));
|
|
|
|
for (i = 0; i < 8; i++)
|
|
{
|
|
candidates = g_list_append (candidates, g_strdup_printf ("LPT%d", i));
|
|
candidates = g_list_append (candidates, g_strdup_printf ("LPT%d_PASSTHRU", i));
|
|
candidates = g_list_append (candidates, g_strdup_printf ("COM%d", i));
|
|
candidates = g_list_append (candidates, g_strdup_printf ("COM%d_PASSTHRU", i));
|
|
}
|
|
|
|
for (i = 0; i < 50; i++)
|
|
candidates = g_list_append (candidates, g_strdup_printf ("pr%d", i));
|
|
|
|
for (iter = candidates; iter != NULL; iter = iter->next)
|
|
{
|
|
candidate = (gchar *) iter->data;
|
|
|
|
if (test_lpd_queue (client,
|
|
address,
|
|
port,
|
|
cancellable,
|
|
candidate))
|
|
{
|
|
found_queue = g_strdup (candidate);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (found_queue != NULL)
|
|
{
|
|
device = g_new0 (PpPrintDevice, 1);
|
|
device->device_class = g_strdup ("network");
|
|
device->device_uri = g_strdup_printf ("lpd://%s:%d/%s",
|
|
priv->hostname,
|
|
port,
|
|
found_queue);
|
|
/* Translators: The found device is a Line Printer Daemon printer */
|
|
device->device_name = g_strdup (_("LPD Printer"));
|
|
device->host_name = g_strdup (priv->hostname);
|
|
device->host_port = port;
|
|
device->acquisition_method = ACQUISITION_METHOD_LPD;
|
|
|
|
result->devices = g_list_append (result->devices, device);
|
|
}
|
|
|
|
g_list_free_full (candidates, g_free);
|
|
}
|
|
|
|
g_object_unref (client);
|
|
|
|
out:
|
|
g_task_return_pointer (task, result, (GDestroyNotify) pp_devices_list_free);
|
|
g_object_unref (task);
|
|
|
|
g_free (address);
|
|
}
|
|
|
|
void
|
|
pp_host_get_lpd_devices_async (PpHost *host,
|
|
GCancellable *cancellable,
|
|
GAsyncReadyCallback callback,
|
|
gpointer user_data)
|
|
{
|
|
GSDData *data;
|
|
GTask *task;
|
|
|
|
data = g_new0 (GSDData, 1);
|
|
data->devices = g_new0 (PpDevicesList, 1);
|
|
|
|
task = g_task_new (G_OBJECT (host), cancellable, callback, user_data);
|
|
g_task_set_task_data (task, data, (GDestroyNotify) gsd_data_free);
|
|
g_task_run_in_thread (task, _pp_host_get_lpd_devices_thread);
|
|
}
|
|
|
|
PpDevicesList *
|
|
pp_host_get_lpd_devices_finish (PpHost *host,
|
|
GAsyncResult *res,
|
|
GError **error)
|
|
{
|
|
g_return_val_if_fail (g_task_is_valid (res, host), NULL);
|
|
|
|
return g_task_propagate_pointer (G_TASK (res), error);
|
|
}
|