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:
parent
89fe4eda12
commit
7eded1afa5
3 changed files with 234 additions and 1 deletions
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue