GCC Code Coverage Report


Directory: ./
File: panels/printers/pp-maintenance-command.c
Date: 2024-05-04 07:58:27
Exec Total Coverage
Lines: 0 155 0.0%
Functions: 0 16 0.0%
Branches: 0 61 0.0%

Line Branch Exec Source
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, see <http://www.gnu.org/licenses/>.
17 *
18 * Author: Marek Kasik <mkasik@redhat.com>
19 */
20
21 #include <glib/gstdio.h>
22
23 #include "pp-maintenance-command.h"
24
25 #include "pp-utils.h"
26
27 #if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 5)
28 #define HAVE_CUPS_1_6 1
29 #endif
30
31 #ifndef HAVE_CUPS_1_6
32 #define ippGetCount(attr) attr->num_values
33 #define ippGetValueTag(attr) attr->value_tag
34 #define ippGetStatusCode(ipp) ipp->request.status.status_code
35 #define ippGetString(attr, element, language) attr->values[element].string.text
36 #endif
37
38 struct _PpMaintenanceCommand
39 {
40 GObject parent_instance;
41
42 gchar *printer_name;
43 gchar *command;
44 gchar *parameters;
45 gchar *title;
46 };
47
48 G_DEFINE_TYPE (PpMaintenanceCommand, pp_maintenance_command, G_TYPE_OBJECT);
49
50 enum {
51 PROP_0 = 0,
52 PROP_PRINTER_NAME,
53 PROP_COMMAND,
54 PROP_PARAMETERS,
55 PROP_TITLE
56 };
57
58 static void
59 pp_maintenance_command_finalize (GObject *object)
60 {
61 PpMaintenanceCommand *self = PP_MAINTENANCE_COMMAND (object);
62
63 g_clear_pointer (&self->printer_name, g_free);
64 g_clear_pointer (&self->command, g_free);
65 g_clear_pointer (&self->parameters, g_free);
66 g_clear_pointer (&self->title, g_free);
67
68 G_OBJECT_CLASS (pp_maintenance_command_parent_class)->finalize (object);
69 }
70
71 static void
72 pp_maintenance_command_get_property (GObject *object,
73 guint prop_id,
74 GValue *value,
75 GParamSpec *param_spec)
76 {
77 PpMaintenanceCommand *self = PP_MAINTENANCE_COMMAND (object);
78
79 switch (prop_id)
80 {
81 case PROP_PRINTER_NAME:
82 g_value_set_string (value, self->printer_name);
83 break;
84 case PROP_COMMAND:
85 g_value_set_string (value, self->command);
86 break;
87 case PROP_PARAMETERS:
88 g_value_set_string (value, self->parameters);
89 break;
90 case PROP_TITLE:
91 g_value_set_string (value, self->title);
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_maintenance_command_set_property (GObject *object,
103 guint prop_id,
104 const GValue *value,
105 GParamSpec *param_spec)
106 {
107 PpMaintenanceCommand *self = PP_MAINTENANCE_COMMAND (object);
108
109 switch (prop_id)
110 {
111 case PROP_PRINTER_NAME:
112 g_free (self->printer_name);
113 self->printer_name = g_value_dup_string (value);
114 break;
115 case PROP_COMMAND:
116 g_free (self->command);
117 self->command = g_value_dup_string (value);
118 break;
119 case PROP_PARAMETERS:
120 g_free (self->parameters);
121 self->parameters = g_value_dup_string (value);
122 break;
123 case PROP_TITLE:
124 g_free (self->title);
125 self->title = g_value_dup_string (value);
126 break;
127 default:
128 G_OBJECT_WARN_INVALID_PROPERTY_ID (object,
129 prop_id,
130 param_spec);
131 break;
132 }
133 }
134
135 static void
136 pp_maintenance_command_class_init (PpMaintenanceCommandClass *klass)
137 {
138 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
139
140 gobject_class->set_property = pp_maintenance_command_set_property;
141 gobject_class->get_property = pp_maintenance_command_get_property;
142 gobject_class->finalize = pp_maintenance_command_finalize;
143
144 g_object_class_install_property (gobject_class, PROP_PRINTER_NAME,
145 g_param_spec_string ("printer-name",
146 "Printer name",
147 "Name of the printer",
148 NULL,
149 G_PARAM_READWRITE));
150
151 g_object_class_install_property (gobject_class, PROP_COMMAND,
152 g_param_spec_string ("command",
153 "Maintenance command",
154 "Command to execute",
155 NULL,
156 G_PARAM_READWRITE));
157
158 g_object_class_install_property (gobject_class, PROP_PARAMETERS,
159 g_param_spec_string ("parameters",
160 "Optional parameters",
161 "Optional parameters for the maintenance command",
162 NULL,
163 G_PARAM_READWRITE));
164
165 g_object_class_install_property (gobject_class, PROP_TITLE,
166 g_param_spec_string ("title",
167 "Command title",
168 "Title of the job by which the command will be executed",
169 NULL,
170 G_PARAM_READWRITE));
171 }
172
173 static void
174 pp_maintenance_command_init (PpMaintenanceCommand *self)
175 {
176 }
177
178 PpMaintenanceCommand *
179 pp_maintenance_command_new (const gchar *printer_name,
180 const gchar *command,
181 const gchar *parameters,
182 const gchar *title)
183 {
184 return g_object_new (PP_TYPE_MAINTENANCE_COMMAND,
185 "printer-name", printer_name,
186 "command", command,
187 "parameters", parameters,
188 "title", title,
189 NULL);
190 }
191
192 static gboolean _pp_maintenance_command_is_supported (const gchar *printer_name,
193 const gchar *command);
194
195 static void
196 _pp_maintenance_command_execute_thread (GTask *task,
197 gpointer source_object,
198 gpointer task_data,
199 GCancellable *cancellable)
200 {
201 PpMaintenanceCommand *self = PP_MAINTENANCE_COMMAND (source_object);
202 gboolean success = FALSE;
203 GError *error = NULL;
204
205 if (_pp_maintenance_command_is_supported (self->printer_name, self->command))
206 {
207 ipp_t *request;
208 ipp_t *response = NULL;
209 g_autofree gchar *printer_uri = NULL;
210 g_autofree gchar *file_name = NULL;
211 int fd = -1;
212
213 printer_uri = g_strdup_printf ("ipp://localhost/printers/%s",
214 self->printer_name);
215
216 request = ippNewRequest (IPP_PRINT_JOB);
217
218 ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_URI,
219 "printer-uri", NULL, printer_uri);
220 ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_NAME,
221 "job-name", NULL, self->title);
222 ippAddString (request, IPP_TAG_JOB, IPP_TAG_MIMETYPE,
223 "document-format", NULL, "application/vnd.cups-command");
224
225 fd = g_file_open_tmp ("ccXXXXXX", &file_name, &error);
226
227 if (fd != -1)
228 {
229 FILE *file;
230
231 file = fdopen (fd, "w");
232 fprintf (file, "#CUPS-COMMAND\n");
233 fprintf (file, "%s", self->command);
234 if (self->parameters)
235 fprintf (file, " %s", self->parameters);
236 fprintf (file, "\n");
237 fclose (file);
238
239 response = cupsDoFileRequest (CUPS_HTTP_DEFAULT, request, "/", file_name);
240 g_unlink (file_name);
241
242 if (response != NULL)
243 {
244 if (ippGetStatusCode (response) <= IPP_OK_CONFLICT)
245 {
246 success = TRUE;
247 }
248
249 ippDelete (response);
250 }
251 }
252 }
253 else
254 {
255 success = TRUE;
256 }
257
258 if (!success)
259 {
260 g_task_return_new_error (task,
261 G_IO_ERROR,
262 G_IO_ERROR_FAILED,
263 "Execution of maintenance command failed.");
264 }
265
266 g_task_return_boolean (task, success);
267 }
268
269 void
270 pp_maintenance_command_execute_async (PpMaintenanceCommand *self,
271 GCancellable *cancellable,
272 GAsyncReadyCallback callback,
273 gpointer user_data)
274 {
275 g_autoptr(GTask) task = NULL;
276
277 task = g_task_new (self, cancellable, callback, user_data);
278 g_task_set_check_cancellable (task, TRUE);
279 g_task_run_in_thread (task, _pp_maintenance_command_execute_thread);
280 }
281
282 gboolean
283 pp_maintenance_command_execute_finish (PpMaintenanceCommand *self,
284 GAsyncResult *result,
285 GError **error)
286 {
287 g_return_val_if_fail (g_task_is_valid (result, self), FALSE);
288
289 return g_task_propagate_boolean (G_TASK (result), error);
290 }
291
292 static gboolean
293 _pp_maintenance_command_is_supported (const gchar *printer_name,
294 const gchar *command)
295 {
296 ipp_attribute_t *attr = NULL;
297 gboolean is_supported = FALSE;
298 ipp_t *request;
299 ipp_t *response = NULL;
300 g_autofree gchar *printer_uri = NULL;
301 GPtrArray *available_commands = NULL;
302 int i;
303
304 printer_uri = g_strdup_printf ("ipp://localhost/printers/%s",
305 printer_name);
306
307 request = ippNewRequest (IPP_GET_PRINTER_ATTRIBUTES);
308 ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_URI,
309 "printer-uri", NULL, printer_uri);
310 ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
311 "requested-attributes", NULL, "printer-commands");
312 response = cupsDoRequest (CUPS_HTTP_DEFAULT, request, "/");
313 if (response != NULL)
314 {
315 if (ippGetStatusCode (response) <= IPP_OK_CONFLICT)
316 {
317 int commands_count;
318
319 attr = ippFindAttribute (response, "printer-commands", IPP_TAG_ZERO);
320 commands_count = attr != NULL ? ippGetCount (attr) : 0;
321 if (commands_count > 0 &&
322 ippGetValueTag (attr) != IPP_TAG_NOVALUE &&
323 (ippGetValueTag (attr) == IPP_TAG_KEYWORD))
324 {
325 available_commands = g_ptr_array_new_full (commands_count, g_free);
326 for (i = 0; i < commands_count; ++i)
327 {
328 /* Array gains ownership of the lower-cased string */
329 g_ptr_array_add (available_commands, g_ascii_strdown (ippGetString (attr, i, NULL), -1));
330 }
331 }
332 }
333
334 ippDelete (response);
335 }
336
337 if (available_commands != NULL)
338 {
339 g_autofree gchar *command_lowercase = g_ascii_strdown (command, -1);
340 for (i = 0; i < available_commands->len; ++i)
341 {
342 const gchar *available_command = g_ptr_array_index (available_commands, i);
343 if (g_strcmp0 (available_command, command_lowercase) == 0)
344 {
345 is_supported = TRUE;
346 break;
347 }
348 }
349
350 g_ptr_array_free (available_commands, TRUE);
351 }
352
353 return is_supported;
354 }
355
356 static void
357 _pp_maintenance_command_is_supported_thread (GTask *task,
358 gpointer source_object,
359 gpointer task_data,
360 GCancellable *cancellable)
361 {
362 PpMaintenanceCommand *self = PP_MAINTENANCE_COMMAND (source_object);
363 gboolean success = FALSE;
364
365 success = _pp_maintenance_command_is_supported (self->printer_name, self->command);
366 g_task_return_boolean (task, success);
367 }
368
369 void
370 pp_maintenance_command_is_supported_async (PpMaintenanceCommand *self,
371 GCancellable *cancellable,
372 GAsyncReadyCallback callback,
373 gpointer user_data)
374 {
375 g_autoptr(GTask) task = NULL;
376
377 task = g_task_new (self, cancellable, callback, user_data);
378 g_task_set_check_cancellable (task, TRUE);
379 g_task_run_in_thread (task, _pp_maintenance_command_is_supported_thread);
380 }
381
382 gboolean
383 pp_maintenance_command_is_supported_finish (PpMaintenanceCommand *self,
384 GAsyncResult *result,
385 GError **error)
386 {
387 g_return_val_if_fail (g_task_is_valid (result, self), FALSE);
388
389 return g_task_propagate_boolean (G_TASK (result), error);
390 }
391