daemon: implementation of project load
[ladish.git] / daemon / save.c
blob70b6ec8457ee9aca9019bfa86736fb4b8ea00a57
1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
2 /*
3 * LADI Session Handler (ladish)
5 * Copyright (C) 2010 Nedko Arnaudov <nedko@arnaudov.name>
7 **************************************************************************
8 * This file contains implementation save releated helper functions
9 **************************************************************************
11 * LADI Session Handler is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * LADI Session Handler is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with LADI Session Handler. If not, see <http://www.gnu.org/licenses/>
23 * or write to the Free Software Foundation, Inc.,
24 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include <unistd.h>
29 #include "save.h"
30 #include "escape.h"
31 #include "studio.h"
33 bool ladish_write_string(int fd, const char * string)
35 size_t len;
37 len = strlen(string);
39 if (write(fd, string, len) != len)
41 log_error("write() failed to write config file.");
42 return false;
45 return true;
48 bool ladish_write_indented_string(int fd, int indent, const char * string)
50 ASSERT(indent >= 0);
51 while (indent--)
53 if (!ladish_write_string(fd, LADISH_XML_BASE_INDENT))
55 return false;
59 if (!ladish_write_string(fd, string))
61 return false;
64 return true;
67 #define fd (((struct ladish_write_context *)context)->fd)
68 #define indent (((struct ladish_write_context *)context)->indent)
70 static
71 bool
72 write_dict_entry(
73 void * context,
74 const char * key,
75 const char * value)
77 if (!ladish_write_indented_string(fd, indent, "<key name=\""))
79 return false;
82 if (!ladish_write_string(fd, key))
84 return false;
87 if (!ladish_write_string(fd, "\">"))
89 return false;
92 if (!ladish_write_string(fd, value))
94 return false;
97 if (!ladish_write_string(fd, "</key>\n"))
99 return false;
102 return true;
105 static
106 bool
107 ladish_save_vgraph_client_begin(
108 void * context,
109 ladish_graph_handle graph,
110 ladish_client_handle client_handle,
111 const char * client_name,
112 void ** client_iteration_context_ptr_ptr)
114 uuid_t uuid;
115 char str[37];
117 ladish_client_get_uuid(client_handle, uuid);
118 uuid_unparse(uuid, str);
120 log_info("saving vgraph client '%s' (%s)", client_name, str);
122 if (!ladish_write_indented_string(fd, indent, "<client name=\""))
124 return false;
127 if (!ladish_write_string(fd, client_name))
129 return false;
132 if (!ladish_write_string(fd, "\" uuid=\""))
134 return false;
137 if (!ladish_write_string(fd, str))
139 return false;
142 if (!ladish_write_string(fd, "\">\n"))
144 return false;
147 if (!ladish_write_indented_string(fd, indent + 1, "<ports>\n"))
149 return false;
152 return true;
155 static
156 bool
157 ladish_save_vgraph_client_end(
158 void * context,
159 ladish_graph_handle graph,
160 ladish_client_handle client_handle,
161 const char * client_name,
162 void * client_iteration_context_ptr)
164 if (!ladish_write_indented_string(fd, indent + 1, "</ports>\n"))
166 return false;
169 if (!ladish_write_dict(fd, indent + 1, ladish_client_get_dict(client_handle)))
171 return false;
174 if (!ladish_write_indented_string(fd, indent, "</client>\n"))
176 return false;
179 return true;
182 static bool ladish_get_vgraph_port_uuids(ladish_graph_handle vgraph, ladish_port_handle port, uuid_t uuid, uuid_t link_uuid)
184 bool link;
186 if (vgraph != ladish_studio_get_studio_graph())
188 link = false; /* room ports are saved using their fixed uuids */
190 else
192 link = ladish_port_is_link(port);
193 if (link)
195 /* get the generated port uuid that is used for identification in the virtual graph */
196 ladish_graph_get_port_uuid(vgraph, port, uuid);
200 if (!link || link_uuid != NULL)
202 /* get the real port uuid that is same in both room and studio graphs */
203 ladish_port_get_uuid(port, link ? link_uuid : uuid);
206 return link;
209 static
210 bool
211 ladish_save_vgraph_port(
212 void * context,
213 ladish_graph_handle graph,
214 void * client_iteration_context_ptr,
215 ladish_client_handle client_handle,
216 const char * client_name,
217 ladish_port_handle port_handle,
218 const char * port_name,
219 uint32_t port_type,
220 uint32_t port_flags)
222 uuid_t uuid;
223 bool link;
224 uuid_t link_uuid;
225 char str[37];
226 char link_str[37];
227 ladish_dict_handle dict;
229 link = ladish_get_vgraph_port_uuids(graph, port_handle, uuid, link_uuid);
230 uuid_unparse(uuid, str);
231 if (link)
233 uuid_unparse(link_uuid, link_str);
234 log_info("saving vgraph link port '%s':'%s' (%s link=%s)", client_name, port_name, str, link_str);
236 else
238 log_info("saving vgraph port '%s':'%s' (%s)", client_name, port_name, str);
241 if (!ladish_write_indented_string(fd, indent + 2, "<port name=\""))
243 return false;
246 if (!ladish_write_string(fd, port_name))
248 return false;
251 if (!ladish_write_string(fd, "\" uuid=\""))
253 return false;
256 if (!ladish_write_string(fd, str))
258 return false;
261 if (link)
263 if (!ladish_write_string(fd, "\" link_uuid=\""))
265 return false;
268 if (!ladish_write_string(fd, link_str))
270 return false;
274 dict = ladish_port_get_dict(port_handle);
275 if (ladish_dict_is_empty(dict))
277 if (!ladish_write_string(fd, "\" />\n"))
279 return false;
282 else
284 if (!ladish_write_string(fd, "\">\n"))
286 return false;
289 if (!ladish_write_dict(fd, indent + 3, dict))
291 return false;
294 if (!ladish_write_indented_string(fd, indent + 2, "</port>\n"))
296 return false;
300 return true;
303 static
304 bool
305 ladish_save_vgraph_connection(
306 void * context,
307 ladish_graph_handle graph,
308 ladish_port_handle port1_handle,
309 ladish_port_handle port2_handle,
310 ladish_dict_handle dict)
312 uuid_t uuid;
313 char str[37];
315 log_info("saving vgraph connection");
317 if (!ladish_write_indented_string(fd, indent, "<connection port1=\""))
319 return false;
322 ladish_get_vgraph_port_uuids(graph, port1_handle, uuid, NULL);
323 uuid_unparse(uuid, str);
325 if (!ladish_write_string(fd, str))
327 return false;
330 if (!ladish_write_string(fd, "\" port2=\""))
332 return false;
335 ladish_get_vgraph_port_uuids(graph, port2_handle, uuid, NULL);
336 uuid_unparse(uuid, str);
338 if (!ladish_write_string(fd, str))
340 return false;
343 if (ladish_dict_is_empty(dict))
345 if (!ladish_write_string(fd, "\" />\n"))
347 return false;
350 else
352 if (!ladish_write_string(fd, "\">\n"))
354 return false;
357 if (!ladish_write_dict(fd, indent + 1, dict))
359 return false;
362 if (!ladish_write_indented_string(fd, indent, "</connection>\n"))
364 return false;
368 return true;
371 static bool ladish_save_app(void * context, const char * name, bool running, const char * command, bool terminal, uint8_t level, pid_t pid)
373 char buf[100];
374 const char * unescaped_string;
375 char * escaped_string;
376 char * escaped_buffer;
377 bool ret;
379 log_info("saving app: name='%s', %srunning, %s, level %u, commandline='%s'", name, running ? "" : "not ", terminal ? "terminal" : "shell", (unsigned int)level, command);
381 ret = false;
383 escaped_buffer = malloc(ladish_max(strlen(name), strlen(command)) * 3 + 1); /* encode each char in three bytes (percent encoding) */
384 if (escaped_buffer == NULL)
386 log_error("malloc() failed.");
387 goto exit;
390 if (!ladish_write_indented_string(fd, indent, "<application name=\""))
392 goto free_buffer;
395 unescaped_string = name;
396 escaped_string = escaped_buffer;
397 escape(&unescaped_string, &escaped_string);
398 *escaped_string = 0;
399 if (!ladish_write_string(fd, escaped_buffer))
401 goto free_buffer;
404 if (!ladish_write_string(fd, "\" terminal=\""))
406 goto free_buffer;
409 if (!ladish_write_string(fd, terminal ? "true" : "false"))
411 goto free_buffer;
414 if (!ladish_write_string(fd, "\" level=\""))
416 goto free_buffer;
419 sprintf(buf, "%u", (unsigned int)level);
421 if (!ladish_write_string(fd, buf))
423 goto free_buffer;
426 if (!ladish_write_string(fd, "\" autorun=\""))
428 goto free_buffer;
431 if (!ladish_write_string(fd, running ? "true" : "false"))
433 goto free_buffer;
436 if (!ladish_write_string(fd, "\">"))
438 goto free_buffer;
441 unescaped_string = command;
442 escaped_string = escaped_buffer;
443 escape(&unescaped_string, &escaped_string);
444 *escaped_string = 0;
445 if (!ladish_write_string(fd, escaped_buffer))
447 goto free_buffer;
450 if (!ladish_write_string(fd, "</application>\n"))
452 goto free_buffer;
455 ret = true;
457 free_buffer:
458 free(escaped_buffer);
460 exit:
461 return ret;
464 static
465 bool
466 ladish_write_room_port(
467 void * context,
468 ladish_port_handle port,
469 const char * name,
470 uint32_t type,
471 uint32_t flags)
473 uuid_t uuid;
474 char str[37];
475 bool midi;
476 const char * type_str;
477 bool playback;
478 const char * direction_str;
479 ladish_dict_handle dict;
481 ladish_port_get_uuid(port, uuid);
482 uuid_unparse(uuid, str);
484 playback = (flags & JACKDBUS_PORT_FLAG_INPUT) != 0;
485 ASSERT(playback || (flags & JACKDBUS_PORT_FLAG_OUTPUT) != 0); /* playback or capture */
486 ASSERT(!(playback && (flags & JACKDBUS_PORT_FLAG_OUTPUT) != 0)); /* but not both */
487 direction_str = playback ? "playback" : "capture";
489 midi = type == JACKDBUS_PORT_TYPE_MIDI;
490 ASSERT(midi || type == JACKDBUS_PORT_TYPE_AUDIO); /* midi or audio */
491 ASSERT(!(midi && type == JACKDBUS_PORT_TYPE_AUDIO)); /* but not both */
492 type_str = midi ? "midi" : "audio";
494 log_info("saving room %s %s port '%s' (%s)", direction_str, type_str, name, str);
496 if (!ladish_write_indented_string(fd, indent, "<port name=\""))
498 return false;
501 if (!ladish_write_string(fd, name))
503 return false;
506 if (!ladish_write_string(fd, "\" uuid=\""))
508 return false;
511 if (!ladish_write_string(fd, str))
513 return false;
516 if (!ladish_write_string(fd, "\" type=\""))
518 return false;
521 if (!ladish_write_string(fd, type_str))
523 return false;
526 if (!ladish_write_string(fd, "\" direction=\""))
528 return false;
531 if (!ladish_write_string(fd, direction_str))
533 return false;
536 dict = ladish_port_get_dict(port);
537 if (ladish_dict_is_empty(dict))
539 if (!ladish_write_string(fd, "\" />\n"))
541 return false;
544 else
546 if (!ladish_write_string(fd, "\">\n"))
548 return false;
551 if (!ladish_write_dict(fd, indent + 1, dict))
553 return false;
556 if (!ladish_write_indented_string(fd, indent, "</port>\n"))
558 return false;
562 return true;
565 static
566 bool
567 ladish_save_jack_client_begin(
568 void * context,
569 ladish_graph_handle graph_handle,
570 ladish_client_handle client_handle,
571 const char * client_name,
572 void ** client_iteration_context_ptr_ptr)
574 uuid_t uuid;
575 char str[37];
577 ladish_client_get_uuid(client_handle, uuid);
578 uuid_unparse(uuid, str);
580 log_info("saving jack client '%s' (%s)", client_name, str);
582 if (!ladish_write_indented_string(fd, indent, "<client name=\""))
584 return false;
587 if (!ladish_write_string(fd, client_name))
589 return false;
592 if (!ladish_write_string(fd, "\" uuid=\""))
594 return false;
597 if (!ladish_write_string(fd, str))
599 return false;
602 if (!ladish_write_string(fd, "\">\n"))
604 return false;
607 if (!ladish_write_indented_string(fd, indent + 1, "<ports>\n"))
609 return false;
612 return true;
615 static
616 bool
617 ladish_save_jack_client_end(
618 void * context,
619 ladish_graph_handle graph_handle,
620 ladish_client_handle client_handle,
621 const char * client_name,
622 void * client_iteration_context_ptr)
624 if (!ladish_write_indented_string(fd, indent + 1, "</ports>\n"))
626 return false;
629 if (!ladish_write_indented_string(fd, indent, "</client>\n"))
631 return false;
634 return true;
637 static
638 bool
639 ladish_save_jack_port(
640 void * context,
641 ladish_graph_handle graph_handle,
642 void * client_iteration_context_ptr,
643 ladish_client_handle client_handle,
644 const char * client_name,
645 ladish_port_handle port_handle,
646 const char * port_name,
647 uint32_t port_type,
648 uint32_t port_flags)
650 uuid_t uuid;
651 char str[37];
653 ladish_port_get_uuid(port_handle, uuid);
654 uuid_unparse(uuid, str);
656 log_info("saving jack port '%s':'%s' (%s)", client_name, port_name, str);
658 if (!ladish_write_indented_string(fd, indent + 2, "<port name=\""))
660 return false;
663 if (!ladish_write_string(fd, port_name))
665 return false;
668 if (!ladish_write_string(fd, "\" uuid=\""))
670 return false;
673 if (!ladish_write_string(fd, str))
675 return false;
678 if (!ladish_write_string(fd, "\" />\n"))
680 return false;
683 return true;
686 #undef indent
687 #undef fd
689 bool ladish_write_dict(int fd, int indent, ladish_dict_handle dict)
691 struct ladish_write_context context;
693 if (ladish_dict_is_empty(dict))
695 return true;
698 context.fd = fd;
699 context.indent = indent + 1;
701 if (!ladish_write_indented_string(fd, indent, "<dict>\n"))
703 return false;
706 if (!ladish_dict_iterate(dict, &context, write_dict_entry))
708 return false;
711 if (!ladish_write_indented_string(fd, indent, "</dict>\n"))
713 return false;
716 return true;
719 bool ladish_write_vgraph(int fd, int indent, ladish_graph_handle vgraph, ladish_app_supervisor_handle app_supervisor)
721 struct ladish_write_context context;
723 context.fd = fd;
724 context.indent = indent + 1;
726 if (!ladish_write_indented_string(fd, indent, "<clients>\n"))
728 return false;
731 if (!ladish_graph_iterate_nodes(
732 vgraph,
733 true,
734 NULL,
735 &context,
736 ladish_save_vgraph_client_begin,
737 ladish_save_vgraph_port,
738 ladish_save_vgraph_client_end))
740 log_error("ladish_graph_iterate_nodes() failed");
741 return false;
744 if (!ladish_write_indented_string(fd, indent, "</clients>\n"))
746 return false;
749 if (!ladish_write_indented_string(fd, indent, "<connections>\n"))
751 return false;
754 if (!ladish_graph_iterate_connections(vgraph, true, &context, ladish_save_vgraph_connection))
756 log_error("ladish_graph_iterate_connections() failed");
757 return false;
760 if (!ladish_write_indented_string(fd, indent, "</connections>\n"))
762 return false;
765 if (!ladish_write_indented_string(fd, indent, "<applications>\n"))
767 return false;
770 if (!ladish_app_supervisor_enum(app_supervisor, &context, ladish_save_app))
772 return false;
775 if (!ladish_write_indented_string(fd, indent, "</applications>\n"))
777 return false;
780 return true;
783 bool ladish_write_room_link_ports(int fd, int indent, ladish_room_handle room)
785 struct ladish_write_context context;
787 context.fd = fd;
788 context.indent = indent;
790 if (!ladish_room_iterate_link_ports(room, &context, ladish_write_room_port))
792 log_error("ladish_room_iterate_link_ports() failed");
793 return false;
796 return true;
799 bool ladish_write_jgraph(int fd, int indent, ladish_graph_handle vgraph)
801 struct ladish_write_context context;
803 if (!ladish_write_indented_string(fd, indent, "<clients>\n"))
805 return false;
808 context.fd = fd;
809 context.indent = indent + 1;
811 if (!ladish_graph_iterate_nodes(
812 ladish_studio_get_jack_graph(),
813 true,
814 vgraph,
815 &context,
816 ladish_save_jack_client_begin,
817 ladish_save_jack_port,
818 ladish_save_jack_client_end))
820 log_error("ladish_graph_iterate_nodes() failed");
821 return false;
824 if (!ladish_write_indented_string(fd, indent, "</clients>\n"))
826 return false;
829 return true;