GCC Code Coverage Report


Directory: ./
File: panels/printers/pp-job.c
Date: 2024-05-04 07:58:27
Exec Total Coverage
Lines: 0 184 0.0%
Functions: 0 27 0.0%
Branches: 0 76 0.0%

Line Branch Exec Source
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2 *
3 * Copyright 2015 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, see <http://www.gnu.org/licenses/>.
17 *
18 * Author: Felipe Borges <feborges@redhat.com>
19 */
20
21 #include "pp-job.h"
22
23 #include <gio/gio.h>
24 #include <cups/cups.h>
25
26 #if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 5)
27 #define HAVE_CUPS_1_6 1
28 #endif
29
30 #ifndef HAVE_CUPS_1_6
31 #define ippGetBoolean(attr, element) attr->values[element].boolean
32 #define ippGetCount(attr) attr->num_values
33 #define ippGetInteger(attr, element) attr->values[element].integer
34 #define ippGetString(attr, element, language) attr->values[element].string.text
35 #define ippGetValueTag(attr) attr->value_tag
36 static int
37 ippGetRange (ipp_attribute_t *attr,
38 int element,
39 int *upper)
40 {
41 *upper = attr->values[element].range.upper;
42 return (attr->values[element].range.lower);
43 }
44 #endif
45
46 struct _PpJob
47 {
48 GObject parent_instance;
49
50 gint id;
51 gchar *title;
52 gint state;
53 gint priority;
54 gboolean sensitive;
55
56 GStrv auth_info_required;
57 };
58
59 G_DEFINE_TYPE (PpJob, pp_job, G_TYPE_OBJECT)
60
61 static void
62 pp_job_cancel_purge_async_dbus_cb (GObject *source_object,
63 GAsyncResult *res,
64 gpointer user_data)
65 {
66 g_autoptr(GVariant) output = NULL;
67
68 output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
69 res,
70 NULL);
71 }
72
73 PpJob *
74 pp_job_new (gint id, const gchar *title, gint state, gint priority, GStrv auth_info_required)
75 {
76 PpJob *job = g_object_new (pp_job_get_type (), NULL);
77
78 job->id = id;
79 job->title = g_strdup (title);
80 job->state = state;
81 job->priority = priority;
82 job->sensitive = FALSE;
83 job->auth_info_required = g_strdupv (auth_info_required);
84
85 return job;
86 }
87
88 const gchar *
89 pp_job_get_title (PpJob *self)
90 {
91 g_return_val_if_fail (PP_IS_JOB(self), NULL);
92 return self->title;
93 }
94
95 gint
96 pp_job_get_state (PpJob *self)
97 {
98 g_return_val_if_fail (PP_IS_JOB(self), -1);
99 return self->state;
100 }
101
102 void
103 pp_job_priority_set_sensitive (PpJob *self,
104 gboolean sensitive)
105 {
106 self->sensitive = sensitive;
107 }
108
109 gboolean
110 pp_job_priority_get_sensitive (PpJob *self)
111 {
112 g_return_val_if_fail (PP_IS_JOB (self), FALSE);
113 return self->sensitive;
114 }
115
116 gint
117 pp_job_get_priority (PpJob *self)
118 {
119 g_return_val_if_fail (PP_IS_JOB (self), -1);
120 return self->priority;
121 }
122
123 void
124 pp_job_set_priority (PpJob *self,
125 gint priority)
126 {
127 self->priority = priority;
128 }
129
130 GStrv
131 pp_job_get_auth_info_required (PpJob *self)
132 {
133 g_return_val_if_fail (PP_IS_JOB(self), NULL);
134 return self->auth_info_required;
135 }
136
137 void
138 pp_job_cancel_purge_async (PpJob *self,
139 gboolean job_purge)
140 {
141 g_autoptr(GDBusConnection) bus = NULL;
142 g_autoptr(GError) error = NULL;
143
144 bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
145 if (!bus)
146 {
147 g_warning ("Failed to get session bus: %s", error->message);
148 return;
149 }
150
151 g_dbus_connection_call (bus,
152 MECHANISM_BUS,
153 "/",
154 MECHANISM_BUS,
155 "JobCancelPurge",
156 g_variant_new ("(ib)",
157 self->id,
158 job_purge),
159 G_VARIANT_TYPE ("(s)"),
160 G_DBUS_CALL_FLAGS_NONE,
161 -1,
162 NULL,
163 pp_job_cancel_purge_async_dbus_cb,
164 NULL);
165 }
166
167 static void
168 pp_job_set_hold_until_async_dbus_cb (GObject *source_object,
169 GAsyncResult *res,
170 gpointer user_data)
171 {
172 g_autoptr(GVariant) output = NULL;
173
174 output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
175 res,
176 NULL);
177 }
178
179 void
180 pp_job_set_hold_until_async (PpJob *self,
181 const gchar *job_hold_until)
182 {
183 g_autoptr(GDBusConnection) bus = NULL;
184 g_autoptr(GError) error = NULL;
185
186 bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
187 if (!bus)
188 {
189 g_warning ("Failed to get session bus: %s", error->message);
190 return;
191 }
192
193 g_dbus_connection_call (bus,
194 MECHANISM_BUS,
195 "/",
196 MECHANISM_BUS,
197 "JobSetHoldUntil",
198 g_variant_new ("(is)",
199 self->id,
200 job_hold_until),
201 G_VARIANT_TYPE ("(s)"),
202 G_DBUS_CALL_FLAGS_NONE,
203 -1,
204 NULL,
205 pp_job_set_hold_until_async_dbus_cb,
206 NULL);
207 }
208
209 static void
210 pp_job_init (PpJob *obj)
211 {
212 }
213
214 static void
215 pp_job_finalize (GObject *object)
216 {
217 PpJob *self = PP_JOB (object);
218
219 g_clear_pointer (&self->title, g_free);
220 g_clear_pointer (&self->auth_info_required, g_strfreev);
221
222 G_OBJECT_CLASS (pp_job_parent_class)->finalize (object);
223 }
224
225 static void
226 pp_job_class_init (PpJobClass *class)
227 {
228 GObjectClass *object_class = G_OBJECT_CLASS (class);
229
230 object_class->finalize = pp_job_finalize;
231 }
232
233 static void
234 _pp_job_get_attributes_thread (GTask *task,
235 gpointer source_object,
236 gpointer task_data,
237 GCancellable *cancellable)
238 {
239 PpJob *self = PP_JOB (source_object);
240 ipp_attribute_t *attr = NULL;
241 GVariantBuilder builder;
242 GVariant *attributes = NULL;
243 gchar **attributes_names = task_data;
244 ipp_t *request;
245 ipp_t *response = NULL;
246 g_autofree gchar *job_uri = NULL;
247 gint i, j, length = 0, n_attrs = 0;
248
249 job_uri = g_strdup_printf ("ipp://localhost/jobs/%d", self->id);
250
251 if (attributes_names != NULL)
252 {
253 length = g_strv_length (attributes_names);
254
255 request = ippNewRequest (IPP_GET_JOB_ATTRIBUTES);
256 ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_URI,
257 "job-uri", NULL, job_uri);
258 ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_NAME,
259 "requesting-user-name", NULL, cupsUser ());
260 ippAddStrings (request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
261 "requested-attributes", length, NULL, (const char **) attributes_names);
262 response = cupsDoRequest (CUPS_HTTP_DEFAULT, request, "/");
263 }
264
265 if (response != NULL)
266 {
267 g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
268
269 for (j = 0; j < length; j++)
270 {
271 attr = ippFindAttribute (response, attributes_names[j], IPP_TAG_ZERO);
272 n_attrs = ippGetCount (attr);
273 if (attr != NULL && n_attrs > 0 && ippGetValueTag (attr) != IPP_TAG_NOVALUE)
274 {
275 const GVariantType *type = NULL;
276 GVariant **values;
277 GVariant *range[2];
278 gint range_uppervalue;
279
280 values = g_new (GVariant*, n_attrs);
281
282 switch (ippGetValueTag (attr))
283 {
284 case IPP_TAG_INTEGER:
285 case IPP_TAG_ENUM:
286 type = G_VARIANT_TYPE_INT32;
287
288 for (i = 0; i < n_attrs; i++)
289 values[i] = g_variant_new_int32 (ippGetInteger (attr, i));
290 break;
291
292 case IPP_TAG_NAME:
293 case IPP_TAG_STRING:
294 case IPP_TAG_TEXT:
295 case IPP_TAG_URI:
296 case IPP_TAG_KEYWORD:
297 case IPP_TAG_URISCHEME:
298 type = G_VARIANT_TYPE_STRING;
299
300 for (i = 0; i < n_attrs; i++)
301 values[i] = g_variant_new_string (ippGetString (attr, i, NULL));
302 break;
303
304 case IPP_TAG_RANGE:
305 type = G_VARIANT_TYPE_TUPLE;
306
307 for (i = 0; i < n_attrs; i++)
308 {
309 range[0] = g_variant_new_int32 (ippGetRange (attr, i, &(range_uppervalue)));
310 range[1] = g_variant_new_int32 (range_uppervalue);
311
312 values[i] = g_variant_new_tuple (range, 2);
313 }
314 break;
315
316 case IPP_TAG_BOOLEAN:
317 type = G_VARIANT_TYPE_BOOLEAN;
318
319 for (i = 0; i < n_attrs; i++)
320 values[i] = g_variant_new_boolean (ippGetBoolean (attr, i));
321 break;
322
323 default:
324 /* do nothing (switch w/ enumeration type) */
325 break;
326 }
327
328 if (type != NULL)
329 {
330 g_variant_builder_add (&builder, "{sv}",
331 attributes_names[j],
332 g_variant_new_array (type, values, n_attrs));
333 }
334
335 g_free (values);
336 }
337 }
338
339 attributes = g_variant_builder_end (&builder);
340 }
341
342 g_task_return_pointer (task, attributes, (GDestroyNotify) g_variant_unref);
343 }
344
345 void
346 pp_job_get_attributes_async (PpJob *self,
347 gchar **attributes_names,
348 GCancellable *cancellable,
349 GAsyncReadyCallback callback,
350 gpointer user_data)
351 {
352 g_autoptr(GTask) task = NULL;
353
354 task = g_task_new (self, cancellable, callback, user_data);
355 g_task_set_task_data (task, g_strdupv (attributes_names), (GDestroyNotify) g_strfreev);
356 g_task_run_in_thread (task, _pp_job_get_attributes_thread);
357 }
358
359 GVariant *
360 pp_job_get_attributes_finish (PpJob *self,
361 GAsyncResult *result,
362 GError **error)
363 {
364 g_return_val_if_fail (g_task_is_valid (result, self), NULL);
365
366 return g_task_propagate_pointer (G_TASK (result), error);
367 }
368
369 static void
370 _pp_job_authenticate_thread (GTask *task,
371 gpointer source_object,
372 gpointer task_data,
373 GCancellable *cancellable)
374 {
375 PpJob *self = source_object;
376 gboolean result = FALSE;
377 gchar **auth_info = task_data;
378 ipp_t *request;
379 ipp_t *response = NULL;
380 gint length;
381
382 if (auth_info != NULL)
383 {
384 g_autofree gchar *job_uri = g_strdup_printf ("ipp://localhost/jobs/%d", self->id);
385
386 length = g_strv_length (auth_info);
387
388 request = ippNewRequest (IPP_OP_CUPS_AUTHENTICATE_JOB);
389 ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_URI,
390 "job-uri", NULL, job_uri);
391 ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_NAME,
392 "requesting-user-name", NULL, cupsUser ());
393 ippAddStrings (request, IPP_TAG_OPERATION, IPP_TAG_TEXT,
394 "auth-info", length, NULL, (const char **) auth_info);
395 response = cupsDoRequest (CUPS_HTTP_DEFAULT, request, "/");
396
397 result = response != NULL && ippGetStatusCode (response) <= IPP_OK;
398
399 if (response != NULL)
400 ippDelete (response);
401 }
402
403 g_task_return_boolean (task, result);
404 }
405
406 void
407 pp_job_authenticate_async (PpJob *self,
408 gchar **auth_info,
409 GCancellable *cancellable,
410 GAsyncReadyCallback callback,
411 gpointer user_data)
412 {
413 g_autoptr(GTask) task = NULL;
414
415 task = g_task_new (self, cancellable, callback, user_data);
416 g_task_set_task_data (task, g_strdupv (auth_info), (GDestroyNotify) g_strfreev);
417 g_task_run_in_thread (task, _pp_job_authenticate_thread);
418 }
419
420 gboolean
421 pp_job_authenticate_finish (PpJob *self,
422 GAsyncResult *result,
423 GError **error)
424 {
425 g_return_val_if_fail (g_task_is_valid (result, self), FALSE);
426
427 return g_task_propagate_boolean (G_TASK (result), error);
428 }
429
430 static void
431 pp_job_set_priority_thread (GTask *task,
432 gpointer source_object,
433 gpointer task_data,
434 GCancellable *cancellable)
435 {
436 PpJob *self = source_object;
437 gint priority = GPOINTER_TO_INT (task_data);
438 ipp_t *request;
439 gboolean result = TRUE;
440 g_autofree gchar *uri = NULL;
441
442 request = ippNewRequest (IPP_SET_JOB_ATTRIBUTES);
443 uri = g_strdup_printf ("ipp://localhost/jobs/%d", self->id);
444 ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_URI,
445 "job-uri", NULL, uri);
446 ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_NAME,
447 "requesting-user-name", NULL, cupsUser ());
448
449 ippAddInteger (request, IPP_TAG_JOB, IPP_TAG_INTEGER,
450 "job-priority", priority);
451
452 ippDelete (cupsDoRequest (CUPS_HTTP_DEFAULT, request, "/"));
453
454 if (cupsLastError () > IPP_OK_CONFLICT)
455 {
456 g_warning ("Failed to set job priority: %s", cupsLastErrorString ());
457 result = FALSE;
458 }
459
460 g_task_return_boolean (task, result);
461 }
462
463 void
464 pp_job_set_priority_async (PpJob *self,
465 gint priority,
466 GCancellable *cancellable,
467 GAsyncReadyCallback callback,
468 gpointer user_data)
469 {
470 g_autoptr(GTask) task = NULL;
471
472 task = g_task_new (self, cancellable, callback, user_data);
473 g_task_set_task_data (task, GINT_TO_POINTER (priority), NULL);
474 g_task_run_in_thread (task, pp_job_set_priority_thread);
475 }
476
477 gboolean
478 pp_job_set_priority_finish (PpJob *self,
479 GAsyncResult *result,
480 GError **error)
481 {
482 g_return_val_if_fail (g_task_is_valid (result, self), FALSE);
483
484 return g_task_propagate_boolean (G_TASK (result), error);
485 }
486