1 /* Copyright (C) 2018-2020 Greenbone Networks GmbH
2  *
3  * SPDX-License-Identifier: AGPL-3.0-or-later
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Affero General Public License as
7  * published by the Free Software Foundation, either version 3 of the
8  * License, or (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 Affero General Public License for more details.
14  *
15  * You should have received a copy of the GNU Affero General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 /**
20  * @file gmp_tickets.c
21  * @brief GVM GMP layer: Tickets
22  *
23  * GMP tickets.
24  */
25 
26 #include "gmp_tickets.h"
27 #include "gmp_base.h"
28 #include "gmp_get.h"
29 #include "manage_tickets.h"
30 
31 #include <glib.h>
32 #include <stdlib.h>
33 #include <string.h>
34 
35 #include <gvm/util/xmlutils.h>
36 
37 #undef G_LOG_DOMAIN
38 /**
39  * @brief GLib log domain.
40  */
41 #define G_LOG_DOMAIN "md    gmp"
42 
43 
44 /* GET_TICKETS. */
45 
46 /**
47  * @brief The get_tickets command.
48  */
49 typedef struct
50 {
51   get_data_t get;    ///< Get args.
52 } get_tickets_t;
53 
54 /**
55  * @brief Parser callback data.
56  *
57  * This is initially 0 because it's a global variable.
58  */
59 static get_tickets_t get_tickets_data;
60 
61 /**
62  * @brief Reset command data.
63  */
64 static void
get_tickets_reset()65 get_tickets_reset ()
66 {
67   get_data_reset (&get_tickets_data.get);
68   memset (&get_tickets_data, 0, sizeof (get_tickets_t));
69 }
70 
71 /**
72  * @brief Handle command start element.
73  *
74  * @param[in]  attribute_names   All attribute names.
75  * @param[in]  attribute_values  All attribute values.
76  */
77 void
get_tickets_start(const gchar ** attribute_names,const gchar ** attribute_values)78 get_tickets_start (const gchar **attribute_names,
79                    const gchar **attribute_values)
80 {
81   get_data_parse_attributes (&get_tickets_data.get, "ticket",
82                              attribute_names,
83                              attribute_values);
84 }
85 
86 /**
87  * @brief Handle end element.
88  *
89  * @param[in]  gmp_parser   GMP parser.
90  * @param[in]  error        Error parameter.
91  */
92 void
get_tickets_run(gmp_parser_t * gmp_parser,GError ** error)93 get_tickets_run (gmp_parser_t *gmp_parser, GError **error)
94 {
95   iterator_t tickets;
96   int count, filtered, ret, first;
97 
98   count = 0;
99 
100   ret = init_get ("get_tickets",
101                   &get_tickets_data.get,
102                   "Tickets",
103                   &first);
104   if (ret)
105     {
106       switch (ret)
107         {
108           case 99:
109             SEND_TO_CLIENT_OR_FAIL
110              (XML_ERROR_SYNTAX ("get_tickets",
111                                 "Permission denied"));
112             break;
113           default:
114             internal_error_send_to_client (error);
115             get_tickets_reset ();
116             return;
117         }
118       get_tickets_reset ();
119       return;
120     }
121 
122   /* Setup the iterator. */
123 
124   ret = init_ticket_iterator (&tickets, &get_tickets_data.get);
125   if (ret)
126     {
127       switch (ret)
128         {
129           case 1:
130             if (send_find_error_to_client ("get_tickets",
131                                            "ticket",
132                                            get_tickets_data.get.id,
133                                            gmp_parser))
134               {
135                 error_send_to_client (error);
136                 get_tickets_reset ();
137                 return;
138               }
139             break;
140           case 2:
141             if (send_find_error_to_client
142                   ("get_tickets", "filter",
143                    get_tickets_data.get.filt_id, gmp_parser))
144               {
145                 error_send_to_client (error);
146                 get_tickets_reset ();
147                 return;
148               }
149             break;
150           case -1:
151             SEND_TO_CLIENT_OR_FAIL
152               (XML_INTERNAL_ERROR ("get_tickets"));
153             break;
154         }
155       get_tickets_reset ();
156       return;
157     }
158 
159   /* Loop through tickets, sending XML. */
160 
161   SEND_GET_START ("ticket");
162   while (1)
163     {
164       iterator_t results;
165 
166       ret = get_next (&tickets, &get_tickets_data.get, &first,
167                       &count, init_ticket_iterator);
168       if (ret == 1)
169         break;
170       if (ret == -1)
171         {
172           internal_error_send_to_client (error);
173           get_tickets_reset ();
174           return;
175         }
176 
177       /* Send generic GET command elements. */
178 
179       SEND_GET_COMMON (ticket, &get_tickets_data.get, &tickets);
180 
181       /* Send ticket info. */
182 
183       SENDF_TO_CLIENT_OR_FAIL ("<assigned_to>"
184                                "<user id=\"%s\">"
185                                "<name>%s</name>"
186                                "</user>"
187                                "</assigned_to>"
188                                "<severity>%1.1f</severity>"
189                                "<host>%s</host>"
190                                "<location>%s</location>"
191                                "<solution_type>%s</solution_type>"
192                                "<status>%s</status>"
193                                "<open_time>%s</open_time>"
194                                "<open_note>%s</open_note>"
195                                "<nvt oid=\"%s\"/>",
196                                ticket_iterator_user_id (&tickets),
197                                ticket_iterator_user_name (&tickets),
198                                ticket_iterator_severity (&tickets),
199                                ticket_iterator_host (&tickets),
200                                ticket_iterator_location (&tickets),
201                                ticket_iterator_solution_type (&tickets),
202                                ticket_iterator_status (&tickets),
203                                ticket_iterator_open_time (&tickets),
204                                ticket_iterator_open_note (&tickets),
205                                ticket_iterator_nvt_oid (&tickets));
206 
207       if (ticket_iterator_task_id (&tickets))
208         SENDF_TO_CLIENT_OR_FAIL ("<task id=\"%s\">"
209                                  "<name>%s</name>"
210                                  "<trash>%i</trash>"
211                                  "</task>",
212                                  ticket_iterator_task_id (&tickets),
213                                  ticket_iterator_task_name (&tickets),
214                                  task_in_trash_id (ticket_iterator_task_id
215                                                     (&tickets)));
216 
217       if (ticket_iterator_report_id (&tickets))
218         {
219           gchar *timestamp;
220 
221           if (report_timestamp (ticket_iterator_report_id (&tickets),
222                                 &timestamp))
223             g_error ("%s: error getting timestamp of report, aborting",
224                      __func__);
225 
226           SENDF_TO_CLIENT_OR_FAIL ("<report id=\"%s\">"
227                                    "<timestamp>%s</timestamp>"
228                                    "</report>",
229                                    ticket_iterator_report_id (&tickets),
230                                    timestamp);
231         }
232 
233       /* Send timestamps. */
234 
235       if (ticket_iterator_fixed_time (&tickets)
236           && strlen (ticket_iterator_fixed_time (&tickets)))
237         SENDF_TO_CLIENT_OR_FAIL ("<fixed_time>%s</fixed_time>",
238                                  ticket_iterator_fixed_time (&tickets));
239 
240       if (ticket_iterator_fixed_note (&tickets))
241         SENDF_TO_CLIENT_OR_FAIL ("<fixed_note>%s</fixed_note>",
242                                   ticket_iterator_fixed_note (&tickets));
243 
244       if (ticket_iterator_closed_time (&tickets)
245           && strlen (ticket_iterator_closed_time (&tickets)))
246         SENDF_TO_CLIENT_OR_FAIL ("<closed_time>%s</closed_time>",
247                                  ticket_iterator_closed_time (&tickets));
248 
249       if (ticket_iterator_closed_note (&tickets))
250         SENDF_TO_CLIENT_OR_FAIL ("<closed_note>%s</closed_note>",
251                                  ticket_iterator_closed_note (&tickets));
252 
253       if (ticket_iterator_fix_verified_time (&tickets)
254           && strlen (ticket_iterator_fix_verified_time (&tickets)))
255         {
256           SENDF_TO_CLIENT_OR_FAIL ("<fix_verified_time>%s</fix_verified_time>",
257                                    ticket_iterator_fix_verified_time (&tickets));
258           if (ticket_iterator_fix_verified_report_id (&tickets))
259             {
260               gchar *timestamp;
261 
262               if (report_timestamp (ticket_iterator_fix_verified_report_id
263                                      (&tickets),
264                                     &timestamp))
265                 g_error ("%s: error getting timestamp of verified report,"
266                          " aborting",
267                          __func__);
268 
269               SENDF_TO_CLIENT_OR_FAIL ("<fix_verified_report>"
270                                        "<report id=\"%s\">"
271                                        "<timestamp>%s</timestamp>"
272                                        "</report>"
273                                        "</fix_verified_report>",
274                                        ticket_iterator_fix_verified_report_id
275                                         (&tickets),
276                                        timestamp);
277             }
278         }
279 
280       /* Send results that are linked to ticket. */
281 
282       if (init_ticket_result_iterator (&results,
283                                        get_iterator_uuid (&tickets),
284                                        get_tickets_data.get.trash))
285         {
286           internal_error_send_to_client (error);
287           get_tickets_reset ();
288           return;
289         }
290       while (next (&results))
291         SENDF_TO_CLIENT_OR_FAIL ("<result id=\"%s\"/>",
292                                  ticket_result_iterator_result_id (&results));
293       cleanup_iterator (&results);
294 
295       SENDF_TO_CLIENT_OR_FAIL ("<orphan>%i</orphan>"
296                                "</ticket>",
297                                ticket_iterator_orphan (&tickets));
298       count++;
299     }
300   cleanup_iterator (&tickets);
301   filtered = get_tickets_data.get.id
302               ? 1
303               : ticket_count (&get_tickets_data.get);
304   SEND_GET_END ("ticket", &get_tickets_data.get, count, filtered);
305 
306   get_tickets_reset ();
307 }
308 
309 
310 /* CREATE_TICKET. */
311 
312 /**
313  * @brief The create_ticket command.
314  */
315 typedef struct
316 {
317   context_data_t *context;     ///< XML parser context.
318 } create_ticket_t;
319 
320 /**
321  * @brief Parser callback data.
322  *
323  * This is initially 0 because it's a global variable.
324  */
325 static create_ticket_t create_ticket_data;
326 
327 /**
328  * @brief Reset command data.
329  */
330 static void
create_ticket_reset()331 create_ticket_reset ()
332 {
333   if (create_ticket_data.context->first)
334     {
335       free_entity (create_ticket_data.context->first->data);
336       g_slist_free_1 (create_ticket_data.context->first);
337     }
338   g_free (create_ticket_data.context);
339   memset (&create_ticket_data, 0, sizeof (create_ticket_t));
340 }
341 
342 /**
343  * @brief Start a command.
344  *
345  * @param[in]  gmp_parser        GMP parser.
346  * @param[in]  attribute_names   All attribute names.
347  * @param[in]  attribute_values  All attribute values.
348  */
349 void
create_ticket_start(gmp_parser_t * gmp_parser,const gchar ** attribute_names,const gchar ** attribute_values)350 create_ticket_start (gmp_parser_t *gmp_parser,
351                      const gchar **attribute_names,
352                      const gchar **attribute_values)
353 {
354   memset (&create_ticket_data, 0, sizeof (create_ticket_t));
355   create_ticket_data.context = g_malloc0 (sizeof (context_data_t));
356   create_ticket_element_start (gmp_parser, "create_ticket", attribute_names,
357                                attribute_values);
358 }
359 
360 /**
361  * @brief Start element.
362  *
363  * @param[in]  gmp_parser        GMP parser.
364  * @param[in]  name              Element name.
365  * @param[in]  attribute_names   All attribute names.
366  * @param[in]  attribute_values  All attribute values.
367  */
368 void
create_ticket_element_start(gmp_parser_t * gmp_parser,const gchar * name,const gchar ** attribute_names,const gchar ** attribute_values)369 create_ticket_element_start (gmp_parser_t *gmp_parser, const gchar *name,
370                              const gchar **attribute_names,
371                              const gchar **attribute_values)
372 {
373   xml_handle_start_element (create_ticket_data.context, name, attribute_names,
374                             attribute_values);
375 }
376 
377 /**
378  * @brief Execute command.
379  *
380  * @param[in]  gmp_parser   GMP parser.
381  * @param[in]  error        Error parameter.
382  */
383 void
create_ticket_run(gmp_parser_t * gmp_parser,GError ** error)384 create_ticket_run (gmp_parser_t *gmp_parser, GError **error)
385 {
386   entity_t entity, copy, comment, result, assigned_to, user, open_note;
387   ticket_t new_ticket;
388   const char *result_id, *user_id;
389 
390   entity = (entity_t) create_ticket_data.context->first->data;
391 
392   copy = entity_child (entity, "copy");
393 
394   if (copy)
395     {
396       /* Copy from an existing ticket and exit. */
397 
398       comment = entity_child (entity, "comment");
399       switch (copy_ticket (comment ? entity_text (comment) : "",
400                            entity_text (copy),
401                            &new_ticket))
402         {
403           case 0:
404             {
405               char *uuid;
406               uuid = ticket_uuid (new_ticket);
407               SENDF_TO_CLIENT_OR_FAIL (XML_OK_CREATED_ID ("create_ticket"),
408                                        uuid);
409               log_event ("ticket", "Ticket", uuid, "created");
410               free (uuid);
411               break;
412             }
413           case 1:
414             SEND_TO_CLIENT_OR_FAIL
415              (XML_ERROR_SYNTAX ("create_ticket",
416                                 "Ticket exists already"));
417             log_event_fail ("ticket", "Ticket", NULL, "created");
418             break;
419           case 2:
420             if (send_find_error_to_client ("create_ticket", "ticket",
421                                            entity_text (copy),
422                                            gmp_parser))
423               {
424                 error_send_to_client (error);
425                 return;
426               }
427             log_event_fail ("ticket", "Ticket", NULL, "created");
428             break;
429           case 99:
430             SEND_TO_CLIENT_OR_FAIL
431              (XML_ERROR_SYNTAX ("create_ticket",
432                                 "Permission denied"));
433             log_event_fail ("ticket", "Ticket", NULL, "created");
434             break;
435           case -1:
436           default:
437             SEND_TO_CLIENT_OR_FAIL
438              (XML_INTERNAL_ERROR ("create_ticket"));
439             log_event_fail ("ticket", "Ticket", NULL, "created");
440             break;
441         }
442       create_ticket_reset ();
443       return;
444     }
445 
446   /* Check given info. */
447 
448   comment = entity_child (entity, "comment");
449 
450   open_note = entity_child (entity, "open_note");
451   if (open_note == NULL)
452     {
453       SEND_TO_CLIENT_OR_FAIL
454        (XML_ERROR_SYNTAX ("create_ticket",
455                           "CREATE_TICKET requires an OPEN_NOTE"));
456       create_ticket_reset ();
457       return;
458     }
459 
460   result = entity_child (entity, "result");
461   if (result == NULL)
462     {
463       SEND_TO_CLIENT_OR_FAIL
464        (XML_ERROR_SYNTAX ("create_ticket",
465                           "CREATE_TICKET requires a RESULT"));
466       create_ticket_reset ();
467       return;
468     }
469 
470   assigned_to = entity_child (entity, "assigned_to");
471   if (assigned_to == NULL)
472     {
473       SEND_TO_CLIENT_OR_FAIL
474        (XML_ERROR_SYNTAX ("create_ticket",
475                           "CREATE_TICKET requires an ASSIGNED_TO element"));
476       create_ticket_reset ();
477       return;
478     }
479 
480   user = entity_child (assigned_to, "user");
481   if (user == NULL)
482     {
483       SEND_TO_CLIENT_OR_FAIL
484        (XML_ERROR_SYNTAX ("create_ticket",
485                           "CREATE_TICKET requires USER in ASSIGNED_TO"));
486       create_ticket_reset ();
487       return;
488     }
489 
490   /* Create ticket from given info. */
491 
492   result_id = entity_attribute (result, "id");
493   user_id = entity_attribute (user, "id");
494 
495   if ((result_id == NULL) || (strlen (result_id) == 0))
496     SEND_TO_CLIENT_OR_FAIL
497      (XML_ERROR_SYNTAX ("create_ticket",
498                         "CREATE_TICKET RESULT must have an id"
499                         " attribute"));
500   else if ((user_id == NULL) || (strlen (user_id) == 0))
501     SEND_TO_CLIENT_OR_FAIL
502      (XML_ERROR_SYNTAX ("create_ticket",
503                         "CREATE_TICKET USER must have an id"
504                         " attribute"));
505   else if (strlen (entity_text (open_note)) == 0)
506     SEND_TO_CLIENT_OR_FAIL
507      (XML_ERROR_SYNTAX ("create_ticket",
508                         "CREATE_TICKET OPEN_NOTE is empty"));
509   else switch (create_ticket
510                 (comment ? entity_text (comment) : "",
511                  result_id,
512                  user_id,
513                  entity_text (open_note),
514                  &new_ticket))
515     {
516       case 0:
517         {
518           char *uuid = ticket_uuid (new_ticket);
519           SENDF_TO_CLIENT_OR_FAIL (XML_OK_CREATED_ID ("create_ticket"),
520                                    uuid);
521           log_event ("ticket", "Ticket", uuid, "created");
522           free (uuid);
523           break;
524         }
525       case 1:
526         log_event_fail ("ticket", "Ticket", NULL, "created");
527         if (send_find_error_to_client ("create_ticket", "user", user_id,
528                                        gmp_parser))
529           {
530             error_send_to_client (error);
531             return;
532           }
533         break;
534       case 2:
535         log_event_fail ("ticket", "Ticket", NULL, "created");
536         if (send_find_error_to_client ("create_ticket", "result", result_id,
537                                        gmp_parser))
538           {
539             error_send_to_client (error);
540             return;
541           }
542         break;
543       case 98:
544         SEND_TO_CLIENT_OR_FAIL
545          (XML_ERROR_SYNTAX ("create_ticket",
546                             "Permission to create permission denied"));
547         log_event_fail ("ticket", "Ticket", NULL, "created");
548         break;
549       case 99:
550         SEND_TO_CLIENT_OR_FAIL
551          (XML_ERROR_SYNTAX ("create_ticket",
552                             "Permission denied"));
553         log_event_fail ("ticket", "Ticket", NULL, "created");
554         break;
555       case -1:
556       default:
557         SEND_TO_CLIENT_OR_FAIL (XML_INTERNAL_ERROR ("create_ticket"));
558         log_event_fail ("ticket", "Ticket", NULL, "created");
559         break;
560     }
561 
562   create_ticket_reset ();
563 }
564 
565 /**
566  * @brief End element.
567  *
568  * @param[in]  gmp_parser   GMP parser.
569  * @param[in]  error        Error parameter.
570  * @param[in]  name         Element name.
571  *
572  * @return 0 success, 1 command finished.
573  */
574 int
create_ticket_element_end(gmp_parser_t * gmp_parser,GError ** error,const gchar * name)575 create_ticket_element_end (gmp_parser_t *gmp_parser, GError **error,
576                            const gchar *name)
577 {
578   xml_handle_end_element (create_ticket_data.context, name);
579   if (create_ticket_data.context->done)
580     {
581       create_ticket_run (gmp_parser, error);
582       return 1;
583     }
584   return 0;
585 }
586 
587 /**
588  * @brief Add text to element.
589  *
590  * @param[in]  text         Text.
591  * @param[in]  text_len     Text length.
592  */
593 void
create_ticket_element_text(const gchar * text,gsize text_len)594 create_ticket_element_text (const gchar *text, gsize text_len)
595 {
596   xml_handle_text (create_ticket_data.context, text, text_len);
597 }
598 
599 
600 /* MODIFY_TICKET. */
601 
602 /**
603  * @brief The modify_ticket command.
604  */
605 typedef struct
606 {
607   context_data_t *context;     ///< XML parser context.
608 } modify_ticket_t;
609 
610 /**
611  * @brief Parser callback data.
612  *
613  * This is initially 0 because it's a global variable.
614  */
615 static modify_ticket_t modify_ticket_data;
616 
617 /**
618  * @brief Reset command data.
619  */
620 static void
modify_ticket_reset()621 modify_ticket_reset ()
622 {
623   if (modify_ticket_data.context->first)
624     {
625       free_entity (modify_ticket_data.context->first->data);
626       g_slist_free_1 (modify_ticket_data.context->first);
627     }
628   g_free (modify_ticket_data.context);
629   memset (&modify_ticket_data, 0, sizeof (modify_ticket_t));
630 }
631 
632 /**
633  * @brief Start a command.
634  *
635  * @param[in]  gmp_parser        GMP parser.
636  * @param[in]  attribute_names   All attribute names.
637  * @param[in]  attribute_values  All attribute values.
638  */
639 void
modify_ticket_start(gmp_parser_t * gmp_parser,const gchar ** attribute_names,const gchar ** attribute_values)640 modify_ticket_start (gmp_parser_t *gmp_parser,
641                      const gchar **attribute_names,
642                      const gchar **attribute_values)
643 {
644   memset (&modify_ticket_data, 0, sizeof (modify_ticket_t));
645   modify_ticket_data.context = g_malloc0 (sizeof (context_data_t));
646   modify_ticket_element_start (gmp_parser, "modify_ticket", attribute_names,
647                                attribute_values);
648 }
649 
650 /**
651  * @brief Start element.
652  *
653  * @param[in]  gmp_parser        GMP parser.
654  * @param[in]  name              Element name.
655  * @param[in]  attribute_names   All attribute names.
656  * @param[in]  attribute_values  All attribute values.
657  */
658 void
modify_ticket_element_start(gmp_parser_t * gmp_parser,const gchar * name,const gchar ** attribute_names,const gchar ** attribute_values)659 modify_ticket_element_start (gmp_parser_t *gmp_parser, const gchar *name,
660                              const gchar **attribute_names,
661                              const gchar **attribute_values)
662 {
663   xml_handle_start_element (modify_ticket_data.context, name, attribute_names,
664                             attribute_values);
665 }
666 
667 /**
668  * @brief Execute command.
669  *
670  * @param[in]  gmp_parser   GMP parser.
671  * @param[in]  error        Error parameter.
672  */
673 void
modify_ticket_run(gmp_parser_t * gmp_parser,GError ** error)674 modify_ticket_run (gmp_parser_t *gmp_parser, GError **error)
675 {
676   entity_t entity, comment, status, open_note, fixed_note, closed_note;
677   entity_t assigned_to;
678   const char *ticket_id, *user_id;
679 
680   entity = (entity_t) modify_ticket_data.context->first->data;
681 
682   ticket_id = entity_attribute (entity, "ticket_id");
683 
684   /* Check the given info. */
685 
686   comment = entity_child (entity, "comment");
687   status = entity_child (entity, "status");
688   open_note = entity_child (entity, "open_note");
689   fixed_note = entity_child (entity, "fixed_note");
690   closed_note = entity_child (entity, "closed_note");
691 
692   assigned_to = entity_child (entity, "assigned_to");
693   if (assigned_to)
694     {
695       entity_t user;
696 
697       user = entity_child (assigned_to, "user");
698       if (user == NULL)
699         {
700           SEND_TO_CLIENT_OR_FAIL
701            (XML_ERROR_SYNTAX ("modify_ticket",
702                               "MODIFY_TICKET requires USER in ASSIGNED_TO"));
703           modify_ticket_reset ();
704           return;
705         }
706 
707       user_id = entity_attribute (user, "id");
708       if ((user_id == NULL) || (strlen (user_id) == 0))
709         {
710           SEND_TO_CLIENT_OR_FAIL
711            (XML_ERROR_SYNTAX ("modify_ticket",
712                               "MODIFY_TICKET USER must have an id"
713                               " attribute"));
714           modify_ticket_reset ();
715           return;
716         }
717     }
718   else
719     user_id = NULL;
720 
721   /* Modify the ticket. */
722 
723   if (ticket_id == NULL)
724     SEND_TO_CLIENT_OR_FAIL
725      (XML_ERROR_SYNTAX ("modify_ticket",
726                         "MODIFY_TICKET requires a ticket_id"
727                         " attribute"));
728   else switch (modify_ticket
729                 (ticket_id,
730                  comment ? entity_text (comment) : NULL,
731                  status ? entity_text (status) : NULL,
732                  open_note ? entity_text (open_note) : NULL,
733                  fixed_note ? entity_text (fixed_note) : NULL,
734                  closed_note ? entity_text (closed_note) : NULL,
735                  user_id))
736     {
737       case 0:
738         SENDF_TO_CLIENT_OR_FAIL (XML_OK ("modify_ticket"));
739         log_event ("ticket", "Ticket", ticket_id, "modified");
740         break;
741       case 1:
742         SEND_TO_CLIENT_OR_FAIL
743          (XML_ERROR_SYNTAX ("modify_ticket",
744                             "Ticket exists already"));
745         log_event_fail ("ticket", "Ticket", ticket_id, "modified");
746         break;
747       case 2:
748         log_event_fail ("ticket", "Ticket", ticket_id, "modified");
749         if (send_find_error_to_client ("modify_ticket", "ticket", ticket_id,
750                                        gmp_parser))
751           {
752             error_send_to_client (error);
753             return;
754           }
755         break;
756       case 3:
757         log_event_fail ("ticket", "Ticket", ticket_id, "modified");
758         if (send_find_error_to_client ("modify_ticket", "user", user_id,
759                                        gmp_parser))
760           {
761             error_send_to_client (error);
762             return;
763           }
764         break;
765       case 4:
766         SEND_TO_CLIENT_OR_FAIL
767          (XML_ERROR_SYNTAX ("modify_ticket",
768                             "Error in status"));
769         log_event_fail ("ticket", "Ticket", ticket_id, "modified");
770         break;
771       case 5:
772         SEND_TO_CLIENT_OR_FAIL
773          (XML_ERROR_SYNTAX ("modify_ticket",
774                             "Fixed STATUS requires a FIXED_NOTE"));
775         log_event_fail ("ticket", "Ticket", ticket_id, "modified");
776         break;
777       case 6:
778         SEND_TO_CLIENT_OR_FAIL
779          (XML_ERROR_SYNTAX ("modify_ticket",
780                             "Closed STATUS requires a CLOSED_NOTE"));
781         log_event_fail ("ticket", "Ticket", ticket_id, "modified");
782         break;
783       case 7:
784         SEND_TO_CLIENT_OR_FAIL
785          (XML_ERROR_SYNTAX ("modify_ticket",
786                             "Open STATUS requires an OPEN_NOTE"));
787         log_event_fail ("ticket", "Ticket", ticket_id, "modified");
788         break;
789       case 99:
790         SEND_TO_CLIENT_OR_FAIL
791          (XML_ERROR_SYNTAX ("modify_ticket",
792                             "Permission denied"));
793         log_event_fail ("ticket", "Ticket", ticket_id, "modified");
794         break;
795       case -1:
796       default:
797         SEND_TO_CLIENT_OR_FAIL
798          (XML_INTERNAL_ERROR ("modify_ticket"));
799         log_event_fail ("ticket", "Ticket", ticket_id, "modified");
800         break;
801     }
802 
803   modify_ticket_reset ();
804 }
805 
806 /**
807  * @brief End element.
808  *
809  * @param[in]  gmp_parser   GMP parser.
810  * @param[in]  error        Error parameter.
811  * @param[in]  name         Element name.
812  *
813  * @return 0 success, 1 command finished.
814  */
815 int
modify_ticket_element_end(gmp_parser_t * gmp_parser,GError ** error,const gchar * name)816 modify_ticket_element_end (gmp_parser_t *gmp_parser, GError **error,
817                            const gchar *name)
818 {
819   xml_handle_end_element (modify_ticket_data.context, name);
820   if (modify_ticket_data.context->done)
821     {
822       modify_ticket_run (gmp_parser, error);
823       return 1;
824     }
825   return 0;
826 }
827 
828 /**
829  * @brief Add text to element.
830  *
831  * @param[in]  text         Text.
832  * @param[in]  text_len     Text length.
833  */
834 void
modify_ticket_element_text(const gchar * text,gsize text_len)835 modify_ticket_element_text (const gchar *text, gsize text_len)
836 {
837   xml_handle_text (modify_ticket_data.context, text, text_len);
838 }
839 
840 
841 /* Result ticket support. */
842 
843 /**
844  * @brief Buffer ticket XML for a result.
845  *
846  * @param[in]  buffer   Buffer.
847  * @param[in]  result   Result.
848  *
849  * @return 0 success, -1 internal error.
850  */
851 int
buffer_result_tickets_xml(GString * buffer,result_t result)852 buffer_result_tickets_xml (GString *buffer, result_t result)
853 {
854   iterator_t tickets;
855   int ret;
856 
857   ret = init_result_ticket_iterator (&tickets, result);
858 
859   if (ret == 0)
860     {
861       buffer_xml_append_printf (buffer, "<tickets>");
862       while (next (&tickets))
863         buffer_xml_append_printf (buffer,
864                                   "<ticket id=\"%s\"/>",
865                                   result_ticket_iterator_ticket_id
866                                    (&tickets));
867       buffer_xml_append_printf (buffer, "</tickets>");
868       cleanup_iterator (&tickets);
869     }
870 
871   return ret;
872 }
873