GCC Code Coverage Report


Directory: ./
File: panels/printers/pp-printer.c
Date: 2024-05-04 07:58:27
Exec Total Coverage
Lines: 0 218 0.0%
Functions: 0 25 0.0%
Branches: 0 75 0.0%

Line Branch Exec Source
1 /*
2 * Copyright (C) 2016 Red Hat, Inc
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see <http://www.gnu.org/licenses/>.
16 *
17 * Authors: Martin Hatina <mhatina@redhat.com>
18 * Marek Kasik <mkasik@redhat.com>
19 */
20
21 #include "pp-printer.h"
22
23 #include "pp-job.h"
24
25 #if (CUPS_VERSION_MAJOR == 1) && (CUPS_VERSION_MINOR <= 6)
26 #define IPP_STATE_IDLE IPP_IDLE
27 #endif
28
29 struct _PpPrinter
30 {
31 GObject parent_instance;
32 gchar *printer_name;
33 };
34
35 G_DEFINE_TYPE (PpPrinter, pp_printer, G_TYPE_OBJECT)
36
37 static void
38 pp_printer_dispose (GObject *object)
39 {
40 PpPrinter *self = PP_PRINTER (object);
41
42 g_clear_pointer (&self->printer_name, g_free);
43
44 G_OBJECT_CLASS (pp_printer_parent_class)->dispose (object);
45 }
46
47 static void
48 pp_printer_class_init (PpPrinterClass *klass)
49 {
50 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
51
52 gobject_class->dispose = pp_printer_dispose;
53 }
54
55 static void
56 pp_printer_init (PpPrinter *self)
57 {
58 }
59
60 PpPrinter *
61 pp_printer_new (const gchar *name)
62 {
63 PpPrinter *self = g_object_new (PP_TYPE_PRINTER, NULL);
64
65 self->printer_name = g_strdup (name);
66
67 return self;
68 }
69
70 const gchar *
71 pp_printer_get_name (PpPrinter *self)
72 {
73 g_return_val_if_fail (PP_IS_PRINTER (self), NULL);
74 return self->printer_name;
75 }
76
77 static void
78 printer_rename_thread (GTask *task,
79 gpointer source_object,
80 gpointer task_data,
81 GCancellable *cancellable)
82 {
83 PpPrinter *self = PP_PRINTER (source_object);
84 gboolean result;
85 const gchar *new_printer_name = task_data;
86
87 result = printer_rename (self->printer_name, new_printer_name);
88
89 if (result)
90 {
91 g_free (self->printer_name);
92 self->printer_name = g_strdup (new_printer_name);
93 }
94
95 g_task_return_boolean (task, result);
96 }
97
98 static void
99 printer_rename_dbus_cb (GObject *source_object,
100 GAsyncResult *res,
101 gpointer user_data)
102 {
103 PpPrinter *self;
104 g_autoptr(GVariant) output = NULL;
105 gboolean result = FALSE;
106 g_autoptr(GError) error = NULL;
107 g_autoptr(GTask) task = user_data;
108
109 output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
110 res,
111 &error);
112
113 if (output != NULL)
114 {
115 const gchar *ret_error;
116
117 self = g_task_get_source_object (task);
118
119 g_variant_get (output, "(&s)", &ret_error);
120 if (ret_error[0] != '\0')
121 {
122 g_warning ("cups-pk-helper: renaming of printer %s failed: %s", self->printer_name, ret_error);
123 }
124 else
125 {
126 result = TRUE;
127 g_free (self->printer_name);
128 self->printer_name = g_strdup (g_task_get_task_data (task));
129 }
130
131 g_task_return_boolean (task, result);
132 }
133 else
134 {
135 if (error->domain == G_DBUS_ERROR &&
136 (error->code == G_DBUS_ERROR_SERVICE_UNKNOWN ||
137 error->code == G_DBUS_ERROR_UNKNOWN_METHOD))
138 {
139 g_warning ("Update cups-pk-helper to at least 0.2.6 please to be able to use PrinterRename method.");
140
141 g_task_run_in_thread (task, printer_rename_thread);
142 }
143 else
144 {
145 g_task_return_boolean (task, FALSE);
146 }
147 }
148 }
149
150 static void
151 get_bus_cb (GObject *source_object,
152 GAsyncResult *res,
153 gpointer user_data)
154 {
155 PpPrinter *self;
156 GDBusConnection *bus;
157 g_autoptr(GError) error = NULL;
158 g_autoptr(GTask) task = user_data;
159
160 bus = g_bus_get_finish (res, &error);
161 if (bus != NULL)
162 {
163 self = g_task_get_source_object (task);
164 g_dbus_connection_call (bus,
165 MECHANISM_BUS,
166 "/",
167 MECHANISM_BUS,
168 "PrinterRename",
169 g_variant_new ("(ss)",
170 self->printer_name,
171 g_task_get_task_data (task)),
172 G_VARIANT_TYPE ("(s)"),
173 G_DBUS_CALL_FLAGS_NONE,
174 -1,
175 g_task_get_cancellable (task),
176 printer_rename_dbus_cb,
177 task);
178 g_steal_pointer (&task);
179 }
180 else
181 {
182 g_warning ("Failed to get system bus: %s", error->message);
183 g_task_return_boolean (task, FALSE);
184 }
185 }
186
187 void
188 pp_printer_rename_async (PpPrinter *self,
189 const gchar *new_printer_name,
190 GCancellable *cancellable,
191 GAsyncReadyCallback callback,
192 gpointer user_data)
193 {
194 GTask *task;
195
196 g_return_if_fail (new_printer_name != NULL);
197
198 task = g_task_new (G_OBJECT (self), cancellable, callback, user_data);
199 g_task_set_task_data (task, g_strdup (new_printer_name), g_free);
200
201 g_bus_get (G_BUS_TYPE_SYSTEM,
202 cancellable,
203 get_bus_cb,
204 task);
205 }
206
207 gboolean
208 pp_printer_rename_finish (PpPrinter *self,
209 GAsyncResult *res,
210 GError **error)
211 {
212 g_return_val_if_fail (g_task_is_valid (res, self), FALSE);
213
214 return g_task_propagate_boolean (G_TASK (res), error);
215 }
216
217 typedef struct
218 {
219 gboolean myjobs;
220 gint which_jobs;
221 } GetJobsData;
222
223 static void
224 get_jobs_thread (GTask *task,
225 gpointer source_object,
226 gpointer task_data,
227 GCancellable *cancellable)
228 {
229 ipp_attribute_t *attr = NULL;
230 static gchar *printer_attributes[] = { "auth-info-required" };
231 GetJobsData *get_jobs_data = task_data;
232 cups_job_t *jobs = NULL;
233 PpPrinter *self = PP_PRINTER (source_object);
234 gboolean auth_info_is_required;
235 PpJob *job;
236 ipp_t *job_request;
237 ipp_t *job_response;
238 ipp_t *printer_request;
239 ipp_t *printer_response;
240 gchar **auth_info_required = NULL;
241 g_autofree gchar *printer_name = NULL;
242 g_autoptr(GPtrArray) array = NULL;
243 gint num_jobs;
244 gint i, j;
245
246 num_jobs = cupsGetJobs (&jobs,
247 self->printer_name,
248 get_jobs_data->myjobs ? 1 : 0,
249 get_jobs_data->which_jobs);
250
251 array = g_ptr_array_new_with_free_func (g_object_unref);
252 for (i = 0; i < num_jobs; i++)
253 {
254 auth_info_is_required = FALSE;
255 if (jobs[i].state == IPP_JOB_HELD)
256 {
257 g_autofree gchar *job_uri = g_strdup_printf ("ipp://localhost/jobs/%d", jobs[i].id);
258
259 job_request = ippNewRequest (IPP_GET_JOB_ATTRIBUTES);
260 ippAddString (job_request, IPP_TAG_OPERATION, IPP_TAG_URI,
261 "job-uri", NULL, job_uri);
262 ippAddString (job_request, IPP_TAG_OPERATION, IPP_TAG_NAME,
263 "requesting-user-name", NULL, cupsUser ());
264 ippAddString (job_request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
265 "requested-attributes", NULL, "job-hold-until");
266 job_response = cupsDoRequest (CUPS_HTTP_DEFAULT, job_request, "/");
267
268 if (job_response != NULL)
269 {
270 attr = ippFindAttribute (job_response, "job-hold-until", IPP_TAG_ZERO);
271 if (attr != NULL && g_strcmp0 (ippGetString (attr, 0, NULL), "auth-info-required") == 0)
272 {
273 auth_info_is_required = TRUE;
274
275 if (auth_info_required == NULL)
276 {
277 g_autofree gchar *printer_uri = g_strdup_printf ("ipp://localhost/printers/%s", self->printer_name);
278
279 printer_request = ippNewRequest (IPP_GET_PRINTER_ATTRIBUTES);
280 ippAddString (printer_request, IPP_TAG_OPERATION, IPP_TAG_URI,
281 "printer-uri", NULL, printer_uri);
282 ippAddString (printer_request, IPP_TAG_OPERATION, IPP_TAG_NAME,
283 "requesting-user-name", NULL, cupsUser ());
284 ippAddStrings (printer_request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
285 "requested-attributes", 1, NULL, (const char **) printer_attributes);
286 printer_response = cupsDoRequest (CUPS_HTTP_DEFAULT, printer_request, "/");
287
288 if (printer_response != NULL)
289 {
290 attr = ippFindAttribute (printer_response, "auth-info-required", IPP_TAG_ZERO);
291 if (attr != NULL)
292 {
293 auth_info_required = g_new0 (gchar *, ippGetCount (attr) + 1);
294 for (j = 0; j < ippGetCount (attr); j++)
295 auth_info_required[j] = g_strdup (ippGetString (attr, j, NULL));
296 }
297
298 ippDelete (printer_response);
299 }
300 }
301 }
302
303 ippDelete (job_response);
304 }
305 }
306
307 job = pp_job_new (jobs[i].id, jobs[i].title, jobs[i].state, jobs[i].priority, auth_info_is_required ? auth_info_required : NULL);
308 g_ptr_array_add (array, job);
309 }
310
311 g_strfreev (auth_info_required);
312 cupsFreeJobs (num_jobs, jobs);
313
314 if (g_task_set_return_on_cancel (task, FALSE))
315 {
316 g_task_return_pointer (task, g_steal_pointer (&array), (GDestroyNotify) g_ptr_array_unref);
317 }
318 }
319
320 void
321 pp_printer_get_jobs_async (PpPrinter *self,
322 gboolean myjobs,
323 gint which_jobs,
324 GCancellable *cancellable,
325 GAsyncReadyCallback callback,
326 gpointer user_data)
327 {
328 GetJobsData *get_jobs_data;
329 g_autoptr(GTask) task = NULL;
330
331 get_jobs_data = g_new (GetJobsData, 1);
332 get_jobs_data->myjobs = myjobs;
333 get_jobs_data->which_jobs = which_jobs;
334
335 task = g_task_new (G_OBJECT (self), cancellable, callback, user_data);
336 g_task_set_task_data (task, get_jobs_data, g_free);
337 g_task_set_return_on_cancel (task, TRUE);
338 g_task_run_in_thread (task, get_jobs_thread);
339 }
340
341 GPtrArray *
342 pp_printer_get_jobs_finish (PpPrinter *self,
343 GAsyncResult *res,
344 GError **error)
345 {
346 g_return_val_if_fail (g_task_is_valid (res, self), NULL);
347
348 return g_task_propagate_pointer (G_TASK (res), error);
349 }
350
351 static void
352 pp_printer_delete_dbus_cb (GObject *source_object,
353 GAsyncResult *res,
354 gpointer user_data)
355 {
356 PpPrinter *self;
357 g_autoptr(GVariant) output = NULL;
358 gboolean result = FALSE;
359 g_autoptr(GError) error = NULL;
360 GTask *task = user_data;
361
362 output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
363 res,
364 &error);
365
366 if (output != NULL)
367 {
368 const gchar *ret_error;
369
370 self = g_task_get_source_object (task);
371
372 g_variant_get (output, "(&s)", &ret_error);
373 if (ret_error[0] != '\0')
374 g_warning ("cups-pk-helper: removing of printer %s failed: %s", self->printer_name, ret_error);
375 else
376 result = TRUE;
377
378 g_task_return_boolean (task, result);
379 }
380 else
381 {
382 g_warning ("%s", error->message);
383
384 g_task_return_boolean (task, FALSE);
385 }
386 }
387
388 static void
389 pp_printer_delete_cb (GObject *source_object,
390 GAsyncResult *res,
391 gpointer user_data)
392 {
393 PpPrinter *self;
394 GDBusConnection *bus;
395 g_autoptr(GError) error = NULL;
396 GTask *task = user_data;
397
398 bus = g_bus_get_finish (res, &error);
399 if (bus != NULL)
400 {
401 self = g_task_get_source_object (task);
402
403 g_dbus_connection_call (bus,
404 MECHANISM_BUS,
405 "/",
406 MECHANISM_BUS,
407 "PrinterDelete",
408 g_variant_new ("(s)", self->printer_name),
409 G_VARIANT_TYPE ("(s)"),
410 G_DBUS_CALL_FLAGS_NONE,
411 -1,
412 g_task_get_cancellable (task),
413 pp_printer_delete_dbus_cb,
414 task);
415 }
416 else
417 {
418 g_warning ("Failed to get system bus: %s", error->message);
419 g_task_return_boolean (task, FALSE);
420 }
421 }
422
423 void
424 pp_printer_delete_async (PpPrinter *self,
425 GCancellable *cancellable,
426 GAsyncReadyCallback callback,
427 gpointer user_data)
428 {
429 GTask *task;
430
431 task = g_task_new (G_OBJECT (self), cancellable, callback, user_data);
432
433 g_bus_get (G_BUS_TYPE_SYSTEM,
434 cancellable,
435 pp_printer_delete_cb,
436 task);
437 }
438
439 gboolean
440 pp_printer_delete_finish (PpPrinter *self,
441 GAsyncResult *res,
442 GError **error)
443 {
444 g_return_val_if_fail (g_task_is_valid (res, self), FALSE);
445
446 return g_task_propagate_boolean (G_TASK (res), error);
447 }
448
449 gboolean
450 pp_printer_delete_sync (PpPrinter *self,
451 GCancellable *cancellable,
452 GError **error)
453 {
454 g_autoptr(GDBusConnection) bus = NULL;
455 g_autoptr(GVariant) output = NULL;
456 g_autoptr(GError) tmp_error = NULL;
457 const gchar *ret_error;
458 gboolean result = FALSE;
459
460 bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, cancellable, &tmp_error);
461 if (bus == NULL)
462 {
463 g_warning ("Failed to get system bus: %s", tmp_error->message);
464 *error = g_error_copy (tmp_error);
465 return result;
466 }
467
468 output = g_dbus_connection_call_sync (bus,
469 MECHANISM_BUS,
470 "/",
471 MECHANISM_BUS,
472 "PrinterDelete",
473 g_variant_new ("(s)", self->printer_name),
474 G_VARIANT_TYPE ("(s)"),
475 G_DBUS_CALL_FLAGS_NONE,
476 -1,
477 cancellable,
478 &tmp_error);
479
480 if (output == NULL)
481 {
482 g_warning ("%s", tmp_error->message);
483 *error = g_error_copy (tmp_error);
484 return result;
485 }
486
487 g_variant_get (output, "(&s)", &ret_error);
488 if (ret_error[0] != '\0')
489 g_warning ("cups-pk-helper: removing of printer %s failed: %s", self->printer_name, ret_error);
490 else
491 result = TRUE;
492
493 return result;
494 }
495
496 typedef struct
497 {
498 gchar *filename;
499 gchar *job_name;
500 } PrintFileData;
501
502 static void
503 print_file_data_free (PrintFileData *print_file_data)
504 {
505 g_free (print_file_data->filename);
506 g_free (print_file_data->job_name);
507
508 g_slice_free (PrintFileData, print_file_data);
509 }
510
511 static void
512 print_file_thread (GTask *task,
513 gpointer source_object,
514 gpointer task_data,
515 GCancellable *cancellable)
516 {
517 PpPrinter *self = PP_PRINTER (source_object);
518 PrintFileData *print_file_data;
519 cups_dest_t *dest = NULL;
520 gboolean ret = FALSE;
521 gint job_id = 0;
522
523 dest = cupsGetNamedDest (CUPS_HTTP_DEFAULT, self->printer_name, NULL);
524
525 if (dest == NULL)
526 {
527 g_warning ("Failed to get the destination %s - %s.", self->printer_name, cupsLastErrorString ());
528 g_task_return_boolean (task, ret);
529 }
530
531 print_file_data = g_task_get_task_data (task);
532
533 job_id = cupsPrintFile2 (CUPS_HTTP_DEFAULT, dest->name, print_file_data->filename, print_file_data->job_name, dest->num_options, dest->options);
534
535 if (job_id < 1)
536 g_warning ("An error has occurred during printing of test page - %s", cupsLastErrorString ());
537 else
538 ret = TRUE;
539
540 cupsFreeDests (1, dest);
541
542 if (g_task_set_return_on_cancel (task, FALSE))
543 {
544 g_task_return_boolean (task, ret);
545 }
546 }
547
548 void
549 pp_printer_print_file_async (PpPrinter *self,
550 const gchar *filename,
551 const gchar *job_name,
552 GCancellable *cancellable,
553 GAsyncReadyCallback callback,
554 gpointer user_data)
555 {
556 PrintFileData *print_file_data;
557 g_autoptr(GTask) task = NULL;
558
559 print_file_data = g_new (PrintFileData, 1);
560 print_file_data->filename = g_strdup (filename);
561 print_file_data->job_name = g_strdup (job_name);
562
563 task = g_task_new (G_OBJECT (self), cancellable, callback, user_data);
564
565 g_task_set_return_on_cancel (task, TRUE);
566 g_task_set_task_data (task, print_file_data, (GDestroyNotify) print_file_data_free);
567
568 g_task_run_in_thread (task, print_file_thread);
569 }
570
571 gboolean
572 pp_printer_print_file_finish (PpPrinter *self,
573 GAsyncResult *res,
574 GError **error)
575 {
576 g_return_val_if_fail (g_task_is_valid (res, self), FALSE);
577
578 return g_task_propagate_boolean (G_TASK (res), error);
579 }
580