printers: Add functions for searching for LPD printers

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
This commit is contained in:
Marek Kasik 2014-07-30 15:37:46 +02:00
parent 89fe4eda12
commit 7eded1afa5
3 changed files with 234 additions and 1 deletions

View file

@ -22,6 +22,8 @@
#include <glib/gi18n.h>
#define BUFFER_LENGTH 1024
struct _PpHostPrivate
{
gchar *hostname;
@ -577,3 +579,223 @@ pp_host_get_jetdirect_devices_finish (PpHost *host,
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);
}

View file

@ -37,6 +37,7 @@ G_BEGIN_DECLS
#define PP_HOST_UNSET_PORT -1
#define PP_HOST_DEFAULT_IPP_PORT 631
#define PP_HOST_DEFAULT_JETDIRECT_PORT 9100
#define PP_HOST_DEFAULT_LPD_PORT 515
typedef struct _PpHost PpHost;
typedef struct _PpHostClass PpHostClass;
@ -84,6 +85,15 @@ PpDevicesList *pp_host_get_jetdirect_devices_finish (PpHost *hos
GAsyncResult *result,
GError **error);
void pp_host_get_lpd_devices_async (PpHost *host,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
PpDevicesList *pp_host_get_lpd_devices_finish (PpHost *host,
GAsyncResult *result,
GError **error);
G_END_DECLS
#endif /* __PP_HOST_H__ */

View file

@ -54,7 +54,8 @@ enum
ACQUISITION_METHOD_SNMP,
ACQUISITION_METHOD_SAMBA,
ACQUISITION_METHOD_SAMBA_HOST,
ACQUISITION_METHOD_JETDIRECT
ACQUISITION_METHOD_JETDIRECT,
ACQUISITION_METHOD_LPD
};
typedef struct