~ubuntu-branches/ubuntu/trusty/unity-control-center/trusty

« back to all changes in this revision

Viewing changes to panels/printers/pp-host.c

  • Committer: Package Import Robot
  • Author(s): Robert Ancell
  • Date: 2014-01-08 16:29:18 UTC
  • Revision ID: package-import@ubuntu.com-20140108162918-g29dd08tr913y2qh
Tags: upstream-14.04.0
ImportĀ upstreamĀ versionĀ 14.04.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
 
2
 *
 
3
 * Copyright 2012  Red Hat, Inc,
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or modify
 
6
 * it under the terms of the GNU General Public License as published by
 
7
 * the Free Software Foundation; either version 2 of the License, or
 
8
 * (at your option) any later version.
 
9
 *
 
10
 * This program is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 * GNU General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU General Public License
 
16
 * along with this program; if not, write to the Free Software
 
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
18
 *
 
19
 * Author: Marek Kasik <mkasik@redhat.com>
 
20
 */
 
21
 
 
22
#include "pp-host.h"
 
23
 
 
24
struct _PpHostPrivate
 
25
{
 
26
  gchar *hostname;
 
27
  gint   port;
 
28
};
 
29
 
 
30
G_DEFINE_TYPE (PpHost, pp_host, G_TYPE_OBJECT);
 
31
 
 
32
enum {
 
33
  PROP_0 = 0,
 
34
  PROP_HOSTNAME,
 
35
  PROP_PORT,
 
36
};
 
37
 
 
38
static void
 
39
pp_host_finalize (GObject *object)
 
40
{
 
41
  PpHostPrivate *priv;
 
42
 
 
43
  priv = PP_HOST (object)->priv;
 
44
 
 
45
  g_clear_pointer (&priv->hostname, g_free);
 
46
 
 
47
  G_OBJECT_CLASS (pp_host_parent_class)->finalize (object);
 
48
}
 
49
 
 
50
static void
 
51
pp_host_get_property (GObject    *object,
 
52
                      guint       prop_id,
 
53
                      GValue     *value,
 
54
                      GParamSpec *param_spec)
 
55
{
 
56
  PpHost *self;
 
57
 
 
58
  self = PP_HOST (object);
 
59
 
 
60
  switch (prop_id)
 
61
    {
 
62
      case PROP_HOSTNAME:
 
63
        g_value_set_string (value, self->priv->hostname);
 
64
        break;
 
65
      case PROP_PORT:
 
66
        g_value_set_int (value, self->priv->port);
 
67
        break;
 
68
      default:
 
69
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object,
 
70
                                           prop_id,
 
71
                                           param_spec);
 
72
      break;
 
73
    }
 
74
}
 
75
 
 
76
static void
 
77
pp_host_set_property (GObject      *object,
 
78
                      guint         prop_id,
 
79
                      const GValue *value,
 
80
                      GParamSpec   *param_spec)
 
81
{
 
82
  PpHost *self = PP_HOST (object);
 
83
 
 
84
  switch (prop_id)
 
85
    {
 
86
      case PROP_HOSTNAME:
 
87
        g_free (self->priv->hostname);
 
88
        self->priv->hostname = g_value_dup_string (value);
 
89
        break;
 
90
      case PROP_PORT:
 
91
        self->priv->port = g_value_get_int (value);
 
92
        break;
 
93
      default:
 
94
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object,
 
95
                                           prop_id,
 
96
                                           param_spec);
 
97
        break;
 
98
    }
 
99
}
 
100
 
 
101
static void
 
102
pp_host_class_init (PpHostClass *klass)
 
103
{
 
104
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
105
 
 
106
  g_type_class_add_private (klass, sizeof (PpHostPrivate));
 
107
 
 
108
  gobject_class->set_property = pp_host_set_property;
 
109
  gobject_class->get_property = pp_host_get_property;
 
110
  gobject_class->finalize = pp_host_finalize;
 
111
 
 
112
  g_object_class_install_property (gobject_class, PROP_HOSTNAME,
 
113
    g_param_spec_string ("hostname",
 
114
                         "Hostname",
 
115
                         "The hostname",
 
116
                         NULL,
 
117
                         G_PARAM_READWRITE));
 
118
 
 
119
  g_object_class_install_property (gobject_class, PROP_PORT,
 
120
    g_param_spec_int ("port",
 
121
                      "Port",
 
122
                      "The port",
 
123
                      0, G_MAXINT32, 631,
 
124
                      G_PARAM_READWRITE));
 
125
}
 
126
 
 
127
static void
 
128
pp_host_init (PpHost *host)
 
129
{
 
130
  host->priv = G_TYPE_INSTANCE_GET_PRIVATE (host,
 
131
                                            PP_TYPE_HOST,
 
132
                                            PpHostPrivate);
 
133
}
 
134
 
 
135
PpHost *
 
136
pp_host_new (const gchar *hostname,
 
137
             gint         port)
 
138
{
 
139
  return g_object_new (PP_TYPE_HOST,
 
140
                       "hostname", hostname,
 
141
                       "port", port,
 
142
                       NULL);
 
143
}
 
144
 
 
145
typedef struct
 
146
{
 
147
  PpDevicesList *devices;
 
148
} GSDData;
 
149
 
 
150
static gchar **
 
151
line_split (gchar *line)
 
152
{
 
153
  gboolean   escaped = FALSE;
 
154
  gboolean   quoted = FALSE;
 
155
  gboolean   in_word = FALSE;
 
156
  gchar    **words = NULL;
 
157
  gchar    **result = NULL;
 
158
  gchar     *buffer = NULL;
 
159
  gchar      ch;
 
160
  gint       n = 0;
 
161
  gint       i, j = 0, k = 0;
 
162
 
 
163
  if (line)
 
164
    {
 
165
      n = strlen (line);
 
166
      words = g_new0 (gchar *, n + 1);
 
167
      buffer = g_new0 (gchar, n + 1);
 
168
 
 
169
      for (i = 0; i < n; i++)
 
170
        {
 
171
          ch = line[i];
 
172
 
 
173
          if (escaped)
 
174
            {
 
175
              buffer[k++] = ch;
 
176
              escaped = FALSE;
 
177
              continue;
 
178
            }
 
179
 
 
180
          if (ch == '\\')
 
181
            {
 
182
              in_word = TRUE;
 
183
              escaped = TRUE;
 
184
              continue;
 
185
            }
 
186
 
 
187
          if (in_word)
 
188
            {
 
189
              if (quoted)
 
190
                {
 
191
                  if (ch == '"')
 
192
                    quoted = FALSE;
 
193
                  else
 
194
                    buffer[k++] = ch;
 
195
                }
 
196
              else if (g_ascii_isspace (ch))
 
197
                {
 
198
                  words[j++] = g_strdup (buffer);
 
199
                  memset (buffer, 0, n + 1);
 
200
                  k = 0;
 
201
                  in_word = FALSE;
 
202
                }
 
203
              else if (ch == '"')
 
204
                quoted = TRUE;
 
205
              else
 
206
                buffer[k++] = ch;
 
207
            }
 
208
          else
 
209
            {
 
210
              if (ch == '"')
 
211
                {
 
212
                  in_word = TRUE;
 
213
                  quoted = TRUE;
 
214
                }
 
215
              else if (!g_ascii_isspace (ch))
 
216
                {
 
217
                  in_word = TRUE;
 
218
                  buffer[k++] = ch;
 
219
                }
 
220
            }
 
221
        }
 
222
    }
 
223
 
 
224
  if (buffer && buffer[0] != '\0')
 
225
    words[j++] = g_strdup (buffer);
 
226
 
 
227
  result = g_strdupv (words);
 
228
  g_strfreev (words);
 
229
  g_free (buffer);
 
230
 
 
231
  return result;
 
232
}
 
233
 
 
234
static void
 
235
_pp_host_get_snmp_devices_thread (GSimpleAsyncResult *res,
 
236
                                  GObject            *object,
 
237
                                  GCancellable       *cancellable)
 
238
{
 
239
  PpHost         *host = (PpHost *) object;
 
240
  PpHostPrivate  *priv = host->priv;
 
241
  PpPrintDevice  *device;
 
242
  GSDData        *data;
 
243
  GError         *error;
 
244
  gchar         **argv;
 
245
  gchar          *stdout_string = NULL;
 
246
  gchar          *stderr_string = NULL;
 
247
  gint            exit_status;
 
248
 
 
249
  data = g_simple_async_result_get_op_res_gpointer (res);
 
250
  data->devices = g_new0 (PpDevicesList, 1);
 
251
  data->devices->devices = NULL;
 
252
 
 
253
  argv = g_new0 (gchar *, 3);
 
254
  argv[0] = g_strdup ("/usr/lib/cups/backend/snmp");
 
255
  argv[1] = g_strdup (priv->hostname);
 
256
 
 
257
  /* Use SNMP to get printer's informations */
 
258
  g_spawn_sync (NULL,
 
259
                argv,
 
260
                NULL,
 
261
                0,
 
262
                NULL,
 
263
                NULL,
 
264
                &stdout_string,
 
265
                &stderr_string,
 
266
                &exit_status,
 
267
                &error);
 
268
 
 
269
  g_free (argv[1]);
 
270
  g_free (argv[0]);
 
271
  g_free (argv);
 
272
 
 
273
  if (exit_status == 0 && stdout_string)
 
274
    {
 
275
      gchar **printer_informations = NULL;
 
276
      gint    length;
 
277
 
 
278
      printer_informations = line_split (stdout_string);
 
279
      length = g_strv_length (printer_informations);
 
280
 
 
281
      if (length >= 4)
 
282
        {
 
283
          device = g_new0 (PpPrintDevice, 1);
 
284
 
 
285
          device->device_class = g_strdup (printer_informations[0]);
 
286
          device->device_uri = g_strdup (printer_informations[1]);
 
287
          device->device_make_and_model = g_strdup (printer_informations[2]);
 
288
          device->device_info = g_strdup (printer_informations[3]);
 
289
          device->device_name = g_strdup (printer_informations[3]);
 
290
          device->device_name =
 
291
            g_strcanon (device->device_name, ALLOWED_CHARACTERS, '-');
 
292
          device->acquisition_method = ACQUISITION_METHOD_SNMP;
 
293
 
 
294
          if (length >= 5 && printer_informations[4][0] != '\0')
 
295
            device->device_id = g_strdup (printer_informations[4]);
 
296
 
 
297
          if (length >= 6 && printer_informations[5][0] != '\0')
 
298
            device->device_location = g_strdup (printer_informations[5]);
 
299
 
 
300
          data->devices->devices = g_list_append (data->devices->devices, device);
 
301
        }
 
302
 
 
303
      g_strfreev (printer_informations);
 
304
      g_free (stdout_string);
 
305
    }
 
306
}
 
307
 
 
308
static void
 
309
gsd_data_free (GSDData *data)
 
310
{
 
311
  GList *iter;
 
312
 
 
313
  if (data)
 
314
    {
 
315
      if (data->devices)
 
316
        {
 
317
          if (data->devices->devices)
 
318
            {
 
319
              for (iter = data->devices->devices; iter; iter = iter->next)
 
320
                pp_print_device_free ((PpPrintDevice *) iter->data);
 
321
              g_list_free (data->devices->devices);
 
322
            }
 
323
 
 
324
          g_free (data->devices);
 
325
        }
 
326
 
 
327
      g_free (data);
 
328
    }
 
329
}
 
330
 
 
331
void
 
332
pp_host_get_snmp_devices_async (PpHost              *host,
 
333
                                GCancellable        *cancellable,
 
334
                                GAsyncReadyCallback  callback,
 
335
                                gpointer             user_data)
 
336
{
 
337
  GSimpleAsyncResult *res;
 
338
  GSDData            *data;
 
339
 
 
340
  res = g_simple_async_result_new (G_OBJECT (host), callback, user_data, pp_host_get_snmp_devices_async);
 
341
  data = g_new0 (GSDData, 1);
 
342
  data->devices = NULL;
 
343
 
 
344
  g_simple_async_result_set_check_cancellable (res, cancellable);
 
345
  g_simple_async_result_set_op_res_gpointer (res, data, (GDestroyNotify) gsd_data_free);
 
346
  g_simple_async_result_run_in_thread (res, _pp_host_get_snmp_devices_thread, 0, cancellable);
 
347
 
 
348
  g_object_unref (res);
 
349
}
 
350
 
 
351
PpDevicesList *
 
352
pp_host_get_snmp_devices_finish (PpHost        *host,
 
353
                                 GAsyncResult  *res,
 
354
                                 GError       **error)
 
355
{
 
356
  GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
 
357
  GSDData            *data;
 
358
  PpDevicesList      *result;
 
359
 
 
360
  g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == pp_host_get_snmp_devices_async);
 
361
 
 
362
  if (g_simple_async_result_propagate_error (simple, error))
 
363
    return NULL;
 
364
 
 
365
  data = g_simple_async_result_get_op_res_gpointer (simple);
 
366
  result = data->devices;
 
367
  data->devices = NULL;
 
368
 
 
369
  return result;
 
370
}
 
371
 
 
372
static void
 
373
_pp_host_get_remote_cups_devices_thread (GSimpleAsyncResult *res,
 
374
                                         GObject            *object,
 
375
                                         GCancellable       *cancellable)
 
376
{
 
377
  cups_dest_t   *dests = NULL;
 
378
  GSDData       *data;
 
379
  PpHost        *host = (PpHost *) object;
 
380
  PpHostPrivate *priv = host->priv;
 
381
  PpPrintDevice *device;
 
382
  http_t        *http;
 
383
  gint           num_of_devices = 0;
 
384
  gint           i;
 
385
 
 
386
  data = g_simple_async_result_get_op_res_gpointer (res);
 
387
  data->devices = g_new0 (PpDevicesList, 1);
 
388
  data->devices->devices = NULL;
 
389
 
 
390
  /* Connect to remote CUPS server and get its devices */
 
391
  http = httpConnect (priv->hostname, priv->port);
 
392
  if (http)
 
393
    {
 
394
      num_of_devices = cupsGetDests2 (http, &dests);
 
395
      if (num_of_devices > 0)
 
396
        {
 
397
          for (i = 0; i < num_of_devices; i++)
 
398
            {
 
399
              device = g_new0 (PpPrintDevice, 1);
 
400
              device->device_class = g_strdup ("network");
 
401
              device->device_uri = g_strdup_printf ("ipp://%s:%d/printers/%s",
 
402
                                           priv->hostname,
 
403
                                           priv->port,
 
404
                                           dests[i].name);
 
405
              device->device_name = g_strdup (dests[i].name);
 
406
              device->device_location = g_strdup (cupsGetOption ("printer-location",
 
407
                                                        dests[i].num_options,
 
408
                                                        dests[i].options));
 
409
              device->host_name = g_strdup (priv->hostname);
 
410
              device->host_port = priv->port;
 
411
              device->acquisition_method = ACQUISITION_METHOD_REMOTE_CUPS_SERVER;
 
412
              data->devices->devices = g_list_append (data->devices->devices, device);
 
413
            }
 
414
        }
 
415
 
 
416
      httpClose (http);
 
417
    }
 
418
}
 
419
 
 
420
void
 
421
pp_host_get_remote_cups_devices_async (PpHost              *host,
 
422
                                       GCancellable        *cancellable,
 
423
                                       GAsyncReadyCallback  callback,
 
424
                                       gpointer             user_data)
 
425
{
 
426
  GSimpleAsyncResult *res;
 
427
  GSDData            *data;
 
428
 
 
429
  res = g_simple_async_result_new (G_OBJECT (host), callback, user_data, pp_host_get_remote_cups_devices_async);
 
430
  data = g_new0 (GSDData, 1);
 
431
  data->devices = NULL;
 
432
 
 
433
  g_simple_async_result_set_check_cancellable (res, cancellable);
 
434
  g_simple_async_result_set_op_res_gpointer (res, data, (GDestroyNotify) gsd_data_free);
 
435
  g_simple_async_result_run_in_thread (res, _pp_host_get_remote_cups_devices_thread, 0, cancellable);
 
436
 
 
437
  g_object_unref (res);
 
438
}
 
439
 
 
440
PpDevicesList *
 
441
pp_host_get_remote_cups_devices_finish (PpHost        *host,
 
442
                                        GAsyncResult  *res,
 
443
                                        GError       **error)
 
444
{
 
445
  GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
 
446
  GSDData            *data;
 
447
  PpDevicesList      *result;
 
448
 
 
449
  g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == pp_host_get_remote_cups_devices_async);
 
450
 
 
451
  if (g_simple_async_result_propagate_error (simple, error))
 
452
    return NULL;
 
453
 
 
454
  data = g_simple_async_result_get_op_res_gpointer (simple);
 
455
  result = data->devices;
 
456
  data->devices = NULL;
 
457
 
 
458
  return result;
 
459
}