sink-input: Add volume_writable to pa_sink_input.
[profile/ivi/pulseaudio-panda.git] / src / pulsecore / cli-command.c
1 /***
2   This file is part of PulseAudio.
3
4   Copyright 2004-2006 Lennart Poettering
5   Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6
7   PulseAudio is free software; you can redistribute it and/or modify
8   it under the terms of the GNU Lesser General Public License as published
9   by the Free Software Foundation; either version 2.1 of the License,
10   or (at your option) any later version.
11
12   PulseAudio is distributed in the hope that it will be useful, but
13   WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   General Public License for more details.
16
17   You should have received a copy of the GNU Lesser General Public License
18   along with PulseAudio; if not, write to the Free Software
19   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20   USA.
21 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <errno.h>
31 #include <unistd.h>
32 #include <ltdl.h>
33 #include <sys/stat.h>
34 #include <dirent.h>
35 #include <time.h>
36
37 #include <pulse/xmalloc.h>
38 #include <pulse/error.h>
39
40 #include <pulsecore/module.h>
41 #include <pulsecore/sink.h>
42 #include <pulsecore/source.h>
43 #include <pulsecore/client.h>
44 #include <pulsecore/sink-input.h>
45 #include <pulsecore/source-output.h>
46 #include <pulsecore/tokenizer.h>
47 #include <pulsecore/strbuf.h>
48 #include <pulsecore/namereg.h>
49 #include <pulsecore/cli-text.h>
50 #include <pulsecore/core-scache.h>
51 #include <pulsecore/sample-util.h>
52 #include <pulsecore/sound-file.h>
53 #include <pulsecore/play-memchunk.h>
54 #include <pulsecore/sound-file-stream.h>
55 #include <pulsecore/shared.h>
56 #include <pulsecore/core-util.h>
57 #include <pulsecore/core-error.h>
58 #include <pulsecore/modinfo.h>
59 #include <pulsecore/dynarray.h>
60
61 #include "cli-command.h"
62
63 struct command {
64     const char *name;
65     int (*proc) (pa_core *c, pa_tokenizer*t, pa_strbuf *buf, pa_bool_t *fail);
66     const char *help;
67     unsigned args;
68 };
69
70 #define META_INCLUDE ".include"
71 #define META_FAIL ".fail"
72 #define META_NOFAIL ".nofail"
73 #define META_IFEXISTS ".ifexists"
74 #define META_ELSE ".else"
75 #define META_ENDIF ".endif"
76
77 enum {
78     IFSTATE_NONE = -1,
79     IFSTATE_FALSE = 0,
80     IFSTATE_TRUE = 1,
81 };
82
83 /* Prototypes for all available commands */
84 static int pa_cli_command_exit(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
85 static int pa_cli_command_help(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
86 static int pa_cli_command_modules(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
87 static int pa_cli_command_clients(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
88 static int pa_cli_command_cards(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
89 static int pa_cli_command_sinks(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
90 static int pa_cli_command_sources(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
91 static int pa_cli_command_sink_inputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
92 static int pa_cli_command_source_outputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
93 static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
94 static int pa_cli_command_info(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
95 static int pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
96 static int pa_cli_command_unload(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
97 static int pa_cli_command_describe(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
98 static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
99 static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
100 static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
101 static int pa_cli_command_sink_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
102 static int pa_cli_command_source_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
103 static int pa_cli_command_sink_input_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
104 static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
105 static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
106 static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
107 static int pa_cli_command_kill_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
108 static int pa_cli_command_kill_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
109 static int pa_cli_command_scache_play(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
110 static int pa_cli_command_scache_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
111 static int pa_cli_command_scache_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
112 static int pa_cli_command_scache_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
113 static int pa_cli_command_scache_load_dir(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
114 static int pa_cli_command_play_file(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
115 static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
116 static int pa_cli_command_list_shared_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
117 static int pa_cli_command_move_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
118 static int pa_cli_command_move_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
119 static int pa_cli_command_vacuum(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
120 static int pa_cli_command_suspend_sink(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
121 static int pa_cli_command_suspend_source(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
122 static int pa_cli_command_suspend(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
123 static int pa_cli_command_log_level(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
124 static int pa_cli_command_log_meta(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
125 static int pa_cli_command_log_time(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
126 static int pa_cli_command_log_backtrace(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
127 static int pa_cli_command_update_sink_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
128 static int pa_cli_command_update_source_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
129 static int pa_cli_command_update_sink_input_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
130 static int pa_cli_command_update_source_output_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
131 static int pa_cli_command_card_profile(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
132 static int pa_cli_command_sink_port(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
133 static int pa_cli_command_source_port(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
134
135 /* A method table for all available commands */
136
137 static const struct command commands[] = {
138     { "exit",                    pa_cli_command_exit,               "Terminate the daemon",         1 },
139     { "help",                    pa_cli_command_help,               "Show this help",               1 },
140     { "list-modules",            pa_cli_command_modules,            "List loaded modules",          1 },
141     { "list-sinks",              pa_cli_command_sinks,              "List loaded sinks",            1 },
142     { "list-sources",            pa_cli_command_sources,            "List loaded sources",          1 },
143     { "list-clients",            pa_cli_command_clients,            "List loaded clients",          1 },
144     { "list-sink-inputs",        pa_cli_command_sink_inputs,        "List sink inputs",             1 },
145     { "list-source-outputs",     pa_cli_command_source_outputs,     "List source outputs",          1 },
146     { "list-cards",              pa_cli_command_cards,              "List cards",                   1 },
147     { "stat",                    pa_cli_command_stat,               "Show memory block statistics", 1 },
148     { "info",                    pa_cli_command_info,               "Show comprehensive status",    1 },
149     { "ls",                      pa_cli_command_info,               NULL,                           1 },
150     { "list",                    pa_cli_command_info,               NULL,                           1 },
151     { "load-module",             pa_cli_command_load,               "Load a module (args: name, arguments)", 3},
152     { "unload-module",           pa_cli_command_unload,             "Unload a module (args: index)", 2},
153     { "describe-module",         pa_cli_command_describe,           "Describe a module (arg: name)", 2},
154     { "set-sink-volume",         pa_cli_command_sink_volume,        "Set the volume of a sink (args: index|name, volume)", 3},
155     { "set-sink-input-volume",   pa_cli_command_sink_input_volume,  "Set the volume of a sink input (args: index, volume)", 3},
156     { "set-source-volume",       pa_cli_command_source_volume,      "Set the volume of a source (args: index|name, volume)", 3},
157     { "set-sink-mute",           pa_cli_command_sink_mute,          "Set the mute switch of a sink (args: index|name, bool)", 3},
158     { "set-sink-input-mute",     pa_cli_command_sink_input_mute,    "Set the mute switch of a sink input (args: index, bool)", 3},
159     { "set-source-mute",         pa_cli_command_source_mute,        "Set the mute switch of a source (args: index|name, bool)", 3},
160     { "update-sink-proplist",    pa_cli_command_update_sink_proplist, "Update the properties of a sink (args: index|name, properties)", 3},
161     { "update-source-proplist",  pa_cli_command_update_source_proplist, "Update the properties of a source (args: index|name, properties)", 3},
162     { "update-sink-input-proplist", pa_cli_command_update_sink_input_proplist, "Update the properties of a sink input (args: index, properties)", 3},
163     { "update-source-output-proplist", pa_cli_command_update_source_output_proplist, "Update the properties of a source_output (args: index, properties)", 3},
164     { "set-default-sink",        pa_cli_command_sink_default,       "Set the default sink (args: index|name)", 2},
165     { "set-default-source",      pa_cli_command_source_default,     "Set the default source (args: index|name)", 2},
166     { "kill-client",             pa_cli_command_kill_client,        "Kill a client (args: index)", 2},
167     { "kill-sink-input",         pa_cli_command_kill_sink_input,    "Kill a sink input (args: index)", 2},
168     { "kill-source-output",      pa_cli_command_kill_source_output, "Kill a source output (args: index)", 2},
169     { "list-samples",            pa_cli_command_scache_list,        "List all entries in the sample cache", 1},
170     { "play-sample",             pa_cli_command_scache_play,        "Play a sample from the sample cache (args: name, sink|index)", 3},
171     { "remove-sample",           pa_cli_command_scache_remove,      "Remove a sample from the sample cache (args: name)", 2},
172     { "load-sample",             pa_cli_command_scache_load,        "Load a sound file into the sample cache (args: name, filename)", 3},
173     { "load-sample-lazy",        pa_cli_command_scache_load,        "Lazily load a sound file into the sample cache (args: name, filename)", 3},
174     { "load-sample-dir-lazy",    pa_cli_command_scache_load_dir,    "Lazily load all files in a directory into the sample cache (args: pathname)", 2},
175     { "play-file",               pa_cli_command_play_file,          "Play a sound file (args: filename, sink|index)", 3},
176     { "dump",                    pa_cli_command_dump,               "Dump daemon configuration", 1},
177     { "shared",                  pa_cli_command_list_shared_props,  NULL, 1},
178     { "move-sink-input",         pa_cli_command_move_sink_input,    "Move sink input to another sink (args: index, sink)", 3},
179     { "move-source-output",      pa_cli_command_move_source_output, "Move source output to another source (args: index, source)", 3},
180     { "vacuum",                  pa_cli_command_vacuum,             NULL, 1},
181     { "suspend-sink",            pa_cli_command_suspend_sink,       "Suspend sink (args: index|name, bool)", 3},
182     { "suspend-source",          pa_cli_command_suspend_source,     "Suspend source (args: index|name, bool)", 3},
183     { "suspend",                 pa_cli_command_suspend,            "Suspend all sinks and all sources (args: bool)", 2},
184     { "set-card-profile",        pa_cli_command_card_profile,       "Change the profile of a card (args: index, name)", 3},
185     { "set-sink-port",           pa_cli_command_sink_port,          "Change the port of a sink (args: index, name)", 3},
186     { "set-source-port",         pa_cli_command_source_port,        "Change the port of a source (args: index, name)", 3},
187     { "set-log-level",           pa_cli_command_log_level,          "Change the log level (args: numeric level)", 2},
188     { "set-log-meta",            pa_cli_command_log_meta,           "Show source code location in log messages (args: bool)", 2},
189     { "set-log-time",            pa_cli_command_log_time,           "Show timestamps in log messages (args: bool)", 2},
190     { "set-log-backtrace",       pa_cli_command_log_backtrace,      "Show backtrace in log messages (args: frames)", 2},
191     { NULL, NULL, NULL, 0 }
192 };
193
194 static const char whitespace[] = " \t\n\r";
195 static const char linebreak[] = "\n\r";
196
197 static uint32_t parse_index(const char *n) {
198     uint32_t idx;
199
200     if (pa_atou(n, &idx) < 0)
201         return (uint32_t) PA_IDXSET_INVALID;
202
203     return idx;
204 }
205
206 static int pa_cli_command_exit(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
207     pa_core_assert_ref(c);
208     pa_assert(t);
209     pa_assert(buf);
210     pa_assert(fail);
211
212     if (pa_core_exit(c, FALSE, 0) < 0)
213         pa_strbuf_puts(buf, "Not allowed to terminate daemon.\n");
214
215     return 0;
216 }
217
218 static int pa_cli_command_help(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
219     const struct command*command;
220
221     pa_core_assert_ref(c);
222     pa_assert(t);
223     pa_assert(buf);
224     pa_assert(fail);
225
226     pa_strbuf_puts(buf, "Available commands:\n");
227
228     for (command = commands; command->name; command++)
229         if (command->help)
230             pa_strbuf_printf(buf, "    %-25s %s\n", command->name, command->help);
231     return 0;
232 }
233
234 static int pa_cli_command_modules(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
235     char *s;
236
237     pa_core_assert_ref(c);
238     pa_assert(t);
239     pa_assert(buf);
240     pa_assert(fail);
241
242     pa_assert_se(s = pa_module_list_to_string(c));
243     pa_strbuf_puts(buf, s);
244     pa_xfree(s);
245     return 0;
246 }
247
248 static int pa_cli_command_clients(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
249     char *s;
250
251     pa_core_assert_ref(c);
252     pa_assert(t);
253     pa_assert(buf);
254     pa_assert(fail);
255
256     pa_assert_se(s = pa_client_list_to_string(c));
257     pa_strbuf_puts(buf, s);
258     pa_xfree(s);
259     return 0;
260 }
261
262 static int pa_cli_command_cards(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
263     char *s;
264
265     pa_core_assert_ref(c);
266     pa_assert(t);
267     pa_assert(buf);
268     pa_assert(fail);
269
270     pa_assert_se(s = pa_card_list_to_string(c));
271     pa_strbuf_puts(buf, s);
272     pa_xfree(s);
273     return 0;
274 }
275
276 static int pa_cli_command_sinks(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
277     char *s;
278
279     pa_core_assert_ref(c);
280     pa_assert(t);
281     pa_assert(buf);
282     pa_assert(fail);
283
284     pa_assert_se(s = pa_sink_list_to_string(c));
285     pa_strbuf_puts(buf, s);
286     pa_xfree(s);
287     return 0;
288 }
289
290 static int pa_cli_command_sources(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
291     char *s;
292
293     pa_core_assert_ref(c);
294     pa_assert(t);
295     pa_assert(buf);
296     pa_assert(fail);
297
298     pa_assert_se(s = pa_source_list_to_string(c));
299     pa_strbuf_puts(buf, s);
300     pa_xfree(s);
301     return 0;
302 }
303
304 static int pa_cli_command_sink_inputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
305     char *s;
306
307     pa_core_assert_ref(c);
308     pa_assert(t);
309     pa_assert(buf);
310     pa_assert(fail);
311
312     pa_assert_se(s = pa_sink_input_list_to_string(c));
313     pa_strbuf_puts(buf, s);
314     pa_xfree(s);
315     return 0;
316 }
317
318 static int pa_cli_command_source_outputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
319     char *s;
320
321     pa_core_assert_ref(c);
322     pa_assert(t);
323     pa_assert(buf);
324     pa_assert(fail);
325
326     pa_assert_se(s = pa_source_output_list_to_string(c));
327     pa_strbuf_puts(buf, s);
328     pa_xfree(s);
329     return 0;
330 }
331
332 static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
333     char ss[PA_SAMPLE_SPEC_SNPRINT_MAX];
334     char cm[PA_CHANNEL_MAP_SNPRINT_MAX];
335     char bytes[PA_BYTES_SNPRINT_MAX];
336     const pa_mempool_stat *mstat;
337     unsigned k;
338     pa_sink *def_sink;
339     pa_source *def_source;
340
341     static const char* const type_table[PA_MEMBLOCK_TYPE_MAX] = {
342         [PA_MEMBLOCK_POOL] = "POOL",
343         [PA_MEMBLOCK_POOL_EXTERNAL] = "POOL_EXTERNAL",
344         [PA_MEMBLOCK_APPENDED] = "APPENDED",
345         [PA_MEMBLOCK_USER] = "USER",
346         [PA_MEMBLOCK_FIXED] = "FIXED",
347         [PA_MEMBLOCK_IMPORTED] = "IMPORTED",
348     };
349
350     pa_core_assert_ref(c);
351     pa_assert(t);
352     pa_assert(buf);
353     pa_assert(fail);
354
355     mstat = pa_mempool_get_stat(c->mempool);
356
357     pa_strbuf_printf(buf, "Memory blocks currently allocated: %u, size: %s.\n",
358                      (unsigned) pa_atomic_load(&mstat->n_allocated),
359                      pa_bytes_snprint(bytes, sizeof(bytes), (unsigned) pa_atomic_load(&mstat->allocated_size)));
360
361     pa_strbuf_printf(buf, "Memory blocks allocated during the whole lifetime: %u, size: %s.\n",
362                      (unsigned) pa_atomic_load(&mstat->n_accumulated),
363                      pa_bytes_snprint(bytes, sizeof(bytes), (unsigned) pa_atomic_load(&mstat->accumulated_size)));
364
365     pa_strbuf_printf(buf, "Memory blocks imported from other processes: %u, size: %s.\n",
366                      (unsigned) pa_atomic_load(&mstat->n_imported),
367                      pa_bytes_snprint(bytes, sizeof(bytes), (unsigned) pa_atomic_load(&mstat->imported_size)));
368
369     pa_strbuf_printf(buf, "Memory blocks exported to other processes: %u, size: %s.\n",
370                      (unsigned) pa_atomic_load(&mstat->n_exported),
371                      pa_bytes_snprint(bytes, sizeof(bytes), (unsigned) pa_atomic_load(&mstat->exported_size)));
372
373     pa_strbuf_printf(buf, "Total sample cache size: %s.\n",
374                      pa_bytes_snprint(bytes, sizeof(bytes), (unsigned) pa_scache_total_size(c)));
375
376     pa_strbuf_printf(buf, "Default sample spec: %s\n",
377                      pa_sample_spec_snprint(ss, sizeof(ss), &c->default_sample_spec));
378
379     pa_strbuf_printf(buf, "Default channel map: %s\n",
380                      pa_channel_map_snprint(cm, sizeof(cm), &c->default_channel_map));
381
382     def_sink = pa_namereg_get_default_sink(c);
383     def_source = pa_namereg_get_default_source(c);
384     pa_strbuf_printf(buf, "Default sink name: %s\n"
385                      "Default source name: %s\n",
386                      def_sink ? def_sink->name : "none",
387                      def_source ? def_source->name : "none");
388
389     for (k = 0; k < PA_MEMBLOCK_TYPE_MAX; k++)
390         pa_strbuf_printf(buf,
391                          "Memory blocks of type %s: %u allocated/%u accumulated.\n",
392                          type_table[k],
393                          (unsigned) pa_atomic_load(&mstat->n_allocated_by_type[k]),
394                          (unsigned) pa_atomic_load(&mstat->n_accumulated_by_type[k]));
395
396     return 0;
397 }
398
399 static int pa_cli_command_info(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
400     pa_core_assert_ref(c);
401     pa_assert(t);
402     pa_assert(buf);
403     pa_assert(fail);
404
405     pa_cli_command_stat(c, t, buf, fail);
406     pa_cli_command_modules(c, t, buf, fail);
407     pa_cli_command_sinks(c, t, buf, fail);
408     pa_cli_command_sources(c, t, buf, fail);
409     pa_cli_command_clients(c, t, buf, fail);
410     pa_cli_command_cards(c, t, buf, fail);
411     pa_cli_command_sink_inputs(c, t, buf, fail);
412     pa_cli_command_source_outputs(c, t, buf, fail);
413     pa_cli_command_scache_list(c, t, buf, fail);
414     return 0;
415 }
416
417 static int pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
418     const char *name;
419
420     pa_core_assert_ref(c);
421     pa_assert(t);
422     pa_assert(buf);
423     pa_assert(fail);
424
425     if (!(name = pa_tokenizer_get(t, 1))) {
426         pa_strbuf_puts(buf, "You need to specify the module name and optionally arguments.\n");
427         return -1;
428     }
429
430     if (!pa_module_load(c, name,  pa_tokenizer_get(t, 2))) {
431         pa_strbuf_puts(buf, "Module load failed.\n");
432         return -1;
433     }
434
435     return 0;
436 }
437
438 static int pa_cli_command_unload(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
439     pa_module *m;
440     uint32_t idx;
441     const char *i;
442     char *e;
443
444     pa_core_assert_ref(c);
445     pa_assert(t);
446     pa_assert(buf);
447     pa_assert(fail);
448
449     if (!(i = pa_tokenizer_get(t, 1))) {
450         pa_strbuf_puts(buf, "You need to specify the module index.\n");
451         return -1;
452     }
453
454     idx = (uint32_t) strtoul(i, &e, 10);
455     if (*e || !(m = pa_idxset_get_by_index(c->modules, idx))) {
456         pa_strbuf_puts(buf, "Invalid module index.\n");
457         return -1;
458     }
459
460     pa_module_unload_request(m, FALSE);
461     return 0;
462 }
463
464 static int pa_cli_command_describe(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
465     const char *name;
466     pa_modinfo *i;
467
468     pa_core_assert_ref(c);
469     pa_assert(t);
470     pa_assert(buf);
471     pa_assert(fail);
472
473     if (!(name = pa_tokenizer_get(t, 1))) {
474         pa_strbuf_puts(buf, "You need to specify the module name.\n");
475         return -1;
476     }
477
478     if ((i = pa_modinfo_get_by_name(name))) {
479
480         pa_strbuf_printf(buf, "Name: %s\n", name);
481
482         if (!i->description && !i->version && !i->author && !i->usage)
483             pa_strbuf_printf(buf, "No module information available\n");
484         else {
485             if (i->version)
486                 pa_strbuf_printf(buf, "Version: %s\n", i->version);
487             if (i->description)
488                 pa_strbuf_printf(buf, "Description: %s\n", i->description);
489             if (i->author)
490                 pa_strbuf_printf(buf, "Author: %s\n", i->author);
491             if (i->usage)
492                 pa_strbuf_printf(buf, "Usage: %s\n", i->usage);
493             pa_strbuf_printf(buf, "Load Once: %s\n", pa_yes_no(i->load_once));
494             if (i->deprecated)
495                 pa_strbuf_printf(buf, "Warning, deprecated: %s\n", i->deprecated);
496         }
497
498         pa_modinfo_free(i);
499     } else
500         pa_strbuf_puts(buf, "Failed to open module.\n");
501
502     return 0;
503 }
504
505 static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
506     const char *n, *v;
507     pa_sink *sink;
508     uint32_t volume;
509     pa_cvolume cvolume;
510
511     pa_core_assert_ref(c);
512     pa_assert(t);
513     pa_assert(buf);
514     pa_assert(fail);
515
516     if (!(n = pa_tokenizer_get(t, 1))) {
517         pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n");
518         return -1;
519     }
520
521     if (!(v = pa_tokenizer_get(t, 2))) {
522         pa_strbuf_puts(buf, "You need to specify a volume >= 0. (0 is muted, 0x10000 is normal volume)\n");
523         return -1;
524     }
525
526     if (pa_atou(v, &volume) < 0) {
527         pa_strbuf_puts(buf, "Failed to parse volume.\n");
528         return -1;
529     }
530
531     if (!PA_VOLUME_IS_VALID(volume)) {
532         pa_strbuf_puts(buf, "Volume outside permissible range.\n");
533         return -1;
534     }
535
536     if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK))) {
537         pa_strbuf_puts(buf, "No sink found by this name or index.\n");
538         return -1;
539     }
540
541     pa_cvolume_set(&cvolume, 1, volume);
542     pa_sink_set_volume(sink, &cvolume, TRUE, TRUE);
543     return 0;
544 }
545
546 static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
547     const char *n, *v;
548     pa_sink_input *si;
549     pa_volume_t volume;
550     pa_cvolume cvolume;
551     uint32_t idx;
552
553     pa_core_assert_ref(c);
554     pa_assert(t);
555     pa_assert(buf);
556     pa_assert(fail);
557
558     if (!(n = pa_tokenizer_get(t, 1))) {
559         pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n");
560         return -1;
561     }
562
563     if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
564         pa_strbuf_puts(buf, "Failed to parse index.\n");
565         return -1;
566     }
567
568     if (!(v = pa_tokenizer_get(t, 2))) {
569         pa_strbuf_puts(buf, "You need to specify a volume >= 0. (0 is muted, 0x10000 is normal volume)\n");
570         return -1;
571     }
572
573     if (pa_atou(v, &volume) < 0) {
574         pa_strbuf_puts(buf, "Failed to parse volume.\n");
575         return -1;
576     }
577
578     if (!PA_VOLUME_IS_VALID(volume)) {
579         pa_strbuf_puts(buf, "Volume outside permissible range.\n");
580         return -1;
581     }
582
583     if (!(si = pa_idxset_get_by_index(c->sink_inputs, idx))) {
584         pa_strbuf_puts(buf, "No sink input found with this index.\n");
585         return -1;
586     }
587
588     if (!si->volume_writable) {
589         pa_strbuf_puts(buf, "This sink input's volume can't be changed.\n");
590         return -1;
591     }
592
593     pa_cvolume_set(&cvolume, 1, volume);
594     pa_sink_input_set_volume(si, &cvolume, TRUE, TRUE);
595     return 0;
596 }
597
598 static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
599     const char *n, *v;
600     pa_source *source;
601     uint32_t volume;
602     pa_cvolume cvolume;
603
604     pa_core_assert_ref(c);
605     pa_assert(t);
606     pa_assert(buf);
607     pa_assert(fail);
608
609     if (!(n = pa_tokenizer_get(t, 1))) {
610         pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n");
611         return -1;
612     }
613
614     if (!(v = pa_tokenizer_get(t, 2))) {
615         pa_strbuf_puts(buf, "You need to specify a volume >= 0. (0 is muted, 0x10000 is normal volume)\n");
616         return -1;
617     }
618
619     if (pa_atou(v, &volume) < 0) {
620         pa_strbuf_puts(buf, "Failed to parse volume.\n");
621         return -1;
622     }
623
624     if (!PA_VOLUME_IS_VALID(volume)) {
625         pa_strbuf_puts(buf, "Volume outside permissible range.\n");
626         return -1;
627     }
628
629     if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE))) {
630         pa_strbuf_puts(buf, "No source found by this name or index.\n");
631         return -1;
632     }
633
634     pa_cvolume_set(&cvolume, 1, volume);
635     pa_source_set_volume(source, &cvolume, TRUE);
636     return 0;
637 }
638
639 static int pa_cli_command_sink_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
640     const char *n, *m;
641     pa_sink *sink;
642     int mute;
643
644     pa_core_assert_ref(c);
645     pa_assert(t);
646     pa_assert(buf);
647     pa_assert(fail);
648
649     if (!(n = pa_tokenizer_get(t, 1))) {
650         pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n");
651         return -1;
652     }
653
654     if (!(m = pa_tokenizer_get(t, 2))) {
655         pa_strbuf_puts(buf, "You need to specify a mute switch setting (0/1).\n");
656         return -1;
657     }
658
659     if ((mute = pa_parse_boolean(m)) < 0) {
660         pa_strbuf_puts(buf, "Failed to parse mute switch.\n");
661         return -1;
662     }
663
664     if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK))) {
665         pa_strbuf_puts(buf, "No sink found by this name or index.\n");
666         return -1;
667     }
668
669     pa_sink_set_mute(sink, mute, TRUE);
670     return 0;
671 }
672
673 static int pa_cli_command_source_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
674     const char *n, *m;
675     pa_source *source;
676     int mute;
677
678     pa_core_assert_ref(c);
679     pa_assert(t);
680     pa_assert(buf);
681     pa_assert(fail);
682
683     if (!(n = pa_tokenizer_get(t, 1))) {
684         pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n");
685         return -1;
686     }
687
688     if (!(m = pa_tokenizer_get(t, 2))) {
689         pa_strbuf_puts(buf, "You need to specify a mute switch setting (0/1).\n");
690         return -1;
691     }
692
693     if ((mute = pa_parse_boolean(m)) < 0) {
694         pa_strbuf_puts(buf, "Failed to parse mute switch.\n");
695         return -1;
696     }
697
698     if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE))) {
699         pa_strbuf_puts(buf, "No sink found by this name or index.\n");
700         return -1;
701     }
702
703     pa_source_set_mute(source, mute, TRUE);
704     return 0;
705 }
706
707 static int pa_cli_command_update_sink_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
708     const char *n, *s;
709     pa_sink *sink;
710     pa_proplist *p;
711
712     pa_core_assert_ref(c);
713     pa_assert(t);
714     pa_assert(buf);
715     pa_assert(fail);
716
717     if (!(n = pa_tokenizer_get(t, 1))) {
718         pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n");
719         return -1;
720     }
721
722     if (!(s = pa_tokenizer_get(t, 2))) {
723         pa_strbuf_puts(buf, "You need to specify a \"key=value\" argument.\n");
724         return -1;
725     }
726
727     if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK))) {
728         pa_strbuf_puts(buf, "No sink found by this name or index.\n");
729         return -1;
730     }
731
732     if (!(p = pa_proplist_from_string(s))) {
733         pa_strbuf_puts(buf, "Failed to parse proplist.\n");
734         return -1;
735     }
736
737     pa_sink_update_proplist(sink, PA_UPDATE_REPLACE, p);
738
739     pa_proplist_free(p);
740
741     return 0;
742 }
743
744 static int pa_cli_command_update_source_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
745     const char *n, *s;
746     pa_source *source;
747     pa_proplist *p;
748
749     pa_core_assert_ref(c);
750     pa_assert(t);
751     pa_assert(buf);
752     pa_assert(fail);
753
754     if (!(n = pa_tokenizer_get(t, 1))) {
755         pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n");
756         return -1;
757     }
758
759     if (!(s = pa_tokenizer_get(t, 2))) {
760         pa_strbuf_puts(buf, "You need to specify a \"key=value\" argument.\n");
761         return -1;
762     }
763
764     if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE))) {
765         pa_strbuf_puts(buf, "No source found by this name or index.\n");
766         return -1;
767     }
768
769     if (!(p = pa_proplist_from_string(s))) {
770         pa_strbuf_puts(buf, "Failed to parse proplist.\n");
771         return -1;
772     }
773
774     pa_source_update_proplist(source, PA_UPDATE_REPLACE, p);
775
776     pa_proplist_free(p);
777
778     return 0;
779 }
780
781 static int pa_cli_command_update_sink_input_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
782     const char *n, *s;
783     pa_sink_input *si;
784     uint32_t idx;
785     pa_proplist *p;
786
787     pa_core_assert_ref(c);
788     pa_assert(t);
789     pa_assert(buf);
790     pa_assert(fail);
791
792     if (!(n = pa_tokenizer_get(t, 1))) {
793         pa_strbuf_puts(buf, "You need to specify a sink input either by index.\n");
794         return -1;
795     }
796
797     if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
798         pa_strbuf_puts(buf, "Failed to parse index.\n");
799         return -1;
800     }
801
802     if (!(s = pa_tokenizer_get(t, 2))) {
803         pa_strbuf_puts(buf, "You need to specify a \"key=value\" argument.\n");
804         return -1;
805     }
806
807     if (!(si = pa_idxset_get_by_index(c->sink_inputs, (uint32_t) idx))) {
808         pa_strbuf_puts(buf, "No sink input found with this index.\n");
809         return -1;
810     }
811
812     if (!(p = pa_proplist_from_string(s))) {
813         pa_strbuf_puts(buf, "Failed to parse proplist.\n");
814         return -1;
815     }
816
817     pa_sink_input_update_proplist(si, PA_UPDATE_REPLACE, p);
818
819     pa_proplist_free(p);
820
821     return 0;
822 }
823
824 static int pa_cli_command_update_source_output_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
825     const char *n, *s;
826     pa_source_output *so;
827     uint32_t idx;
828     pa_proplist *p;
829
830     pa_core_assert_ref(c);
831     pa_assert(t);
832     pa_assert(buf);
833     pa_assert(fail);
834
835     if (!(n = pa_tokenizer_get(t, 1))) {
836         pa_strbuf_puts(buf, "You need to specify a source output by its index.\n");
837         return -1;
838     }
839
840     if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
841         pa_strbuf_puts(buf, "Failed to parse index.\n");
842         return -1;
843     }
844
845     if (!(s = pa_tokenizer_get(t, 2))) {
846         pa_strbuf_puts(buf, "You need to specify a \"key=value\" argument.\n");
847         return -1;
848     }
849
850     if (!(so = pa_idxset_get_by_index(c->source_outputs, (uint32_t) idx))) {
851         pa_strbuf_puts(buf, "No source output found with this index.\n");
852         return -1;
853     }
854
855     if (!(p = pa_proplist_from_string(s))) {
856         pa_strbuf_puts(buf, "Failed to parse proplist.\n");
857         return -1;
858     }
859
860     pa_source_output_update_proplist(so, PA_UPDATE_REPLACE, p);
861
862     pa_proplist_free(p);
863
864     return 0;
865 }
866
867 static int pa_cli_command_sink_input_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
868     const char *n, *v;
869     pa_sink_input *si;
870     uint32_t idx;
871     int mute;
872
873     pa_core_assert_ref(c);
874     pa_assert(t);
875     pa_assert(buf);
876     pa_assert(fail);
877
878     if (!(n = pa_tokenizer_get(t, 1))) {
879         pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n");
880         return -1;
881     }
882
883     if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
884         pa_strbuf_puts(buf, "Failed to parse index.\n");
885         return -1;
886     }
887
888     if (!(v = pa_tokenizer_get(t, 2))) {
889         pa_strbuf_puts(buf, "You need to specify a mute switch setting (0/1).\n");
890         return -1;
891     }
892
893     if ((mute = pa_parse_boolean(v)) < 0) {
894         pa_strbuf_puts(buf, "Failed to parse mute switch.\n");
895         return -1;
896     }
897
898     if (!(si = pa_idxset_get_by_index(c->sink_inputs, (uint32_t) idx))) {
899         pa_strbuf_puts(buf, "No sink input found with this index.\n");
900         return -1;
901     }
902
903     pa_sink_input_set_mute(si, mute, TRUE);
904     return 0;
905 }
906
907 static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
908     const char *n;
909     pa_sink *s;
910
911     pa_core_assert_ref(c);
912     pa_assert(t);
913     pa_assert(buf);
914     pa_assert(fail);
915
916     if (!(n = pa_tokenizer_get(t, 1))) {
917         pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n");
918         return -1;
919     }
920
921     if ((s = pa_namereg_get(c, n, PA_NAMEREG_SINK)))
922         pa_namereg_set_default_sink(c, s);
923     else
924         pa_strbuf_printf(buf, "Sink %s does not exist.\n", n);
925
926     return 0;
927 }
928
929 static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
930     const char *n;
931     pa_source *s;
932
933     pa_core_assert_ref(c);
934     pa_assert(t);
935     pa_assert(buf);
936     pa_assert(fail);
937
938     if (!(n = pa_tokenizer_get(t, 1))) {
939         pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n");
940         return -1;
941     }
942
943     if ((s = pa_namereg_get(c, n, PA_NAMEREG_SOURCE)))
944         pa_namereg_set_default_source(c, s);
945     else
946         pa_strbuf_printf(buf, "Source %s does not exist.\n", n);
947     return 0;
948 }
949
950 static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
951     const char *n;
952     pa_client *client;
953     uint32_t idx;
954
955     pa_core_assert_ref(c);
956     pa_assert(t);
957     pa_assert(buf);
958     pa_assert(fail);
959
960     if (!(n = pa_tokenizer_get(t, 1))) {
961         pa_strbuf_puts(buf, "You need to specify a client by its index.\n");
962         return -1;
963     }
964
965     if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
966         pa_strbuf_puts(buf, "Failed to parse index.\n");
967         return -1;
968     }
969
970     if (!(client = pa_idxset_get_by_index(c->clients, idx))) {
971         pa_strbuf_puts(buf, "No client found by this index.\n");
972         return -1;
973     }
974
975     pa_client_kill(client);
976     return 0;
977 }
978
979 static int pa_cli_command_kill_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
980     const char *n;
981     pa_sink_input *sink_input;
982     uint32_t idx;
983
984     pa_core_assert_ref(c);
985     pa_assert(t);
986     pa_assert(buf);
987     pa_assert(fail);
988
989     if (!(n = pa_tokenizer_get(t, 1))) {
990         pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n");
991         return -1;
992     }
993
994     if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
995         pa_strbuf_puts(buf, "Failed to parse index.\n");
996         return -1;
997     }
998
999     if (!(sink_input = pa_idxset_get_by_index(c->sink_inputs, idx))) {
1000         pa_strbuf_puts(buf, "No sink input found by this index.\n");
1001         return -1;
1002     }
1003
1004     pa_sink_input_kill(sink_input);
1005     return 0;
1006 }
1007
1008 static int pa_cli_command_kill_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1009     const char *n;
1010     pa_source_output *source_output;
1011     uint32_t idx;
1012
1013     pa_core_assert_ref(c);
1014     pa_assert(t);
1015     pa_assert(buf);
1016     pa_assert(fail);
1017
1018     if (!(n = pa_tokenizer_get(t, 1))) {
1019         pa_strbuf_puts(buf, "You need to specify a source output by its index.\n");
1020         return -1;
1021     }
1022
1023     if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
1024         pa_strbuf_puts(buf, "Failed to parse index.\n");
1025         return -1;
1026     }
1027
1028     if (!(source_output = pa_idxset_get_by_index(c->source_outputs, idx))) {
1029         pa_strbuf_puts(buf, "No source output found by this index.\n");
1030         return -1;
1031     }
1032
1033     pa_source_output_kill(source_output);
1034     return 0;
1035 }
1036
1037 static int pa_cli_command_scache_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1038     char *s;
1039
1040     pa_core_assert_ref(c);
1041     pa_assert(t);
1042     pa_assert(buf);
1043     pa_assert(fail);
1044
1045     pa_assert_se(s = pa_scache_list_to_string(c));
1046     pa_strbuf_puts(buf, s);
1047     pa_xfree(s);
1048
1049     return 0;
1050 }
1051
1052 static int pa_cli_command_scache_play(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1053     const char *n, *sink_name;
1054     pa_sink *sink;
1055     uint32_t idx;
1056
1057     pa_core_assert_ref(c);
1058     pa_assert(t);
1059     pa_assert(buf);
1060     pa_assert(fail);
1061
1062     if (!(n = pa_tokenizer_get(t, 1)) || !(sink_name = pa_tokenizer_get(t, 2))) {
1063         pa_strbuf_puts(buf, "You need to specify a sample name and a sink name.\n");
1064         return -1;
1065     }
1066
1067     if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK))) {
1068         pa_strbuf_puts(buf, "No sink by that name.\n");
1069         return -1;
1070     }
1071
1072     if (pa_scache_play_item(c, n, sink, PA_VOLUME_NORM, NULL, &idx) < 0) {
1073         pa_strbuf_puts(buf, "Failed to play sample.\n");
1074         return -1;
1075     }
1076
1077     pa_strbuf_printf(buf, "Playing on sink input #%i\n", idx);
1078
1079     return 0;
1080 }
1081
1082 static int pa_cli_command_scache_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1083     const char *n;
1084
1085     pa_core_assert_ref(c);
1086     pa_assert(t);
1087     pa_assert(buf);
1088     pa_assert(fail);
1089
1090     if (!(n = pa_tokenizer_get(t, 1))) {
1091         pa_strbuf_puts(buf, "You need to specify a sample name.\n");
1092         return -1;
1093     }
1094
1095     if (pa_scache_remove_item(c, n) < 0) {
1096         pa_strbuf_puts(buf, "Failed to remove sample.\n");
1097         return -1;
1098     }
1099
1100     return 0;
1101 }
1102
1103 static int pa_cli_command_scache_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1104     const char *fname, *n;
1105     int r;
1106
1107     pa_core_assert_ref(c);
1108     pa_assert(t);
1109     pa_assert(buf);
1110     pa_assert(fail);
1111
1112     if (!(fname = pa_tokenizer_get(t, 2)) || !(n = pa_tokenizer_get(t, 1))) {
1113         pa_strbuf_puts(buf, "You need to specify a file name and a sample name.\n");
1114         return -1;
1115     }
1116
1117     if (strstr(pa_tokenizer_get(t, 0), "lazy"))
1118         r = pa_scache_add_file_lazy(c, n, fname, NULL);
1119     else
1120         r = pa_scache_add_file(c, n, fname, NULL);
1121
1122     if (r < 0)
1123         pa_strbuf_puts(buf, "Failed to load sound file.\n");
1124
1125     return 0;
1126 }
1127
1128 static int pa_cli_command_scache_load_dir(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1129     const char *pname;
1130
1131     pa_core_assert_ref(c);
1132     pa_assert(t);
1133     pa_assert(buf);
1134     pa_assert(fail);
1135
1136     if (!(pname = pa_tokenizer_get(t, 1))) {
1137         pa_strbuf_puts(buf, "You need to specify a path name.\n");
1138         return -1;
1139     }
1140
1141     if (pa_scache_add_directory_lazy(c, pname) < 0) {
1142         pa_strbuf_puts(buf, "Failed to load directory.\n");
1143         return -1;
1144     }
1145
1146     return 0;
1147 }
1148
1149 static int pa_cli_command_play_file(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1150     const char *fname, *sink_name;
1151     pa_sink *sink;
1152
1153     pa_core_assert_ref(c);
1154     pa_assert(t);
1155     pa_assert(buf);
1156     pa_assert(fail);
1157
1158     if (!(fname = pa_tokenizer_get(t, 1)) || !(sink_name = pa_tokenizer_get(t, 2))) {
1159         pa_strbuf_puts(buf, "You need to specify a file name and a sink name.\n");
1160         return -1;
1161     }
1162
1163     if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK))) {
1164         pa_strbuf_puts(buf, "No sink by that name.\n");
1165         return -1;
1166     }
1167
1168
1169     return pa_play_file(sink, fname, NULL);
1170 }
1171
1172 static int pa_cli_command_list_shared_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1173     pa_core_assert_ref(c);
1174     pa_assert(t);
1175     pa_assert(buf);
1176     pa_assert(fail);
1177
1178     pa_shared_dump(c, buf);
1179     return 0;
1180 }
1181
1182 static int pa_cli_command_vacuum(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1183     pa_core_assert_ref(c);
1184     pa_assert(t);
1185     pa_assert(buf);
1186     pa_assert(fail);
1187
1188     pa_mempool_vacuum(c->mempool);
1189
1190     return 0;
1191 }
1192
1193 static int pa_cli_command_move_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1194     const char *n, *k;
1195     pa_sink_input *si;
1196     pa_sink *sink;
1197     uint32_t idx;
1198
1199     pa_core_assert_ref(c);
1200     pa_assert(t);
1201     pa_assert(buf);
1202     pa_assert(fail);
1203
1204     if (!(n = pa_tokenizer_get(t, 1))) {
1205         pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n");
1206         return -1;
1207     }
1208
1209     if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
1210         pa_strbuf_puts(buf, "Failed to parse index.\n");
1211         return -1;
1212     }
1213
1214     if (!(k = pa_tokenizer_get(t, 2))) {
1215         pa_strbuf_puts(buf, "You need to specify a sink.\n");
1216         return -1;
1217     }
1218
1219     if (!(si = pa_idxset_get_by_index(c->sink_inputs, (uint32_t) idx))) {
1220         pa_strbuf_puts(buf, "No sink input found with this index.\n");
1221         return -1;
1222     }
1223
1224     if (!(sink = pa_namereg_get(c, k, PA_NAMEREG_SINK))) {
1225         pa_strbuf_puts(buf, "No sink found by this name or index.\n");
1226         return -1;
1227     }
1228
1229     if (pa_sink_input_move_to(si, sink, TRUE) < 0) {
1230         pa_strbuf_puts(buf, "Moved failed.\n");
1231         return -1;
1232     }
1233     return 0;
1234 }
1235
1236 static int pa_cli_command_move_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1237     const char *n, *k;
1238     pa_source_output *so;
1239     pa_source *source;
1240     uint32_t idx;
1241
1242     pa_core_assert_ref(c);
1243     pa_assert(t);
1244     pa_assert(buf);
1245     pa_assert(fail);
1246
1247     if (!(n = pa_tokenizer_get(t, 1))) {
1248         pa_strbuf_puts(buf, "You need to specify a source output by its index.\n");
1249         return -1;
1250     }
1251
1252     if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
1253         pa_strbuf_puts(buf, "Failed to parse index.\n");
1254         return -1;
1255     }
1256
1257     if (!(k = pa_tokenizer_get(t, 2))) {
1258         pa_strbuf_puts(buf, "You need to specify a source.\n");
1259         return -1;
1260     }
1261
1262     if (!(so = pa_idxset_get_by_index(c->source_outputs, (uint32_t) idx))) {
1263         pa_strbuf_puts(buf, "No source output found with this index.\n");
1264         return -1;
1265     }
1266
1267     if (!(source = pa_namereg_get(c, k, PA_NAMEREG_SOURCE))) {
1268         pa_strbuf_puts(buf, "No source found by this name or index.\n");
1269         return -1;
1270     }
1271
1272     if (pa_source_output_move_to(so, source, TRUE) < 0) {
1273         pa_strbuf_puts(buf, "Moved failed.\n");
1274         return -1;
1275     }
1276     return 0;
1277 }
1278
1279 static int pa_cli_command_suspend_sink(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1280     const char *n, *m;
1281     pa_sink *sink;
1282     int suspend, r;
1283
1284     pa_core_assert_ref(c);
1285     pa_assert(t);
1286     pa_assert(buf);
1287     pa_assert(fail);
1288
1289     if (!(n = pa_tokenizer_get(t, 1))) {
1290         pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n");
1291         return -1;
1292     }
1293
1294     if (!(m = pa_tokenizer_get(t, 2))) {
1295         pa_strbuf_puts(buf, "You need to specify a suspend switch setting (0/1).\n");
1296         return -1;
1297     }
1298
1299     if ((suspend = pa_parse_boolean(m)) < 0) {
1300         pa_strbuf_puts(buf, "Failed to parse suspend switch.\n");
1301         return -1;
1302     }
1303
1304     if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK))) {
1305         pa_strbuf_puts(buf, "No sink found by this name or index.\n");
1306         return -1;
1307     }
1308
1309     if ((r = pa_sink_suspend(sink, suspend, PA_SUSPEND_USER)) < 0)
1310         pa_strbuf_printf(buf, "Failed to resume/suspend sink: %s\n", pa_strerror(r));
1311
1312     return 0;
1313 }
1314
1315 static int pa_cli_command_suspend_source(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1316     const char *n, *m;
1317     pa_source *source;
1318     int suspend, r;
1319
1320     pa_core_assert_ref(c);
1321     pa_assert(t);
1322     pa_assert(buf);
1323     pa_assert(fail);
1324
1325     if (!(n = pa_tokenizer_get(t, 1))) {
1326         pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n");
1327         return -1;
1328     }
1329
1330     if (!(m = pa_tokenizer_get(t, 2))) {
1331         pa_strbuf_puts(buf, "You need to specify a suspend switch setting (0/1).\n");
1332         return -1;
1333     }
1334
1335     if ((suspend = pa_parse_boolean(m)) < 0) {
1336         pa_strbuf_puts(buf, "Failed to parse suspend switch.\n");
1337         return -1;
1338     }
1339
1340     if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE))) {
1341         pa_strbuf_puts(buf, "No source found by this name or index.\n");
1342         return -1;
1343     }
1344
1345     if ((r = pa_source_suspend(source, suspend, PA_SUSPEND_USER)) < 0)
1346         pa_strbuf_printf(buf, "Failed to resume/suspend source: %s\n", pa_strerror(r));
1347
1348     return 0;
1349 }
1350
1351 static int pa_cli_command_suspend(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1352     const char *m;
1353     int suspend, r;
1354
1355     pa_core_assert_ref(c);
1356     pa_assert(t);
1357     pa_assert(buf);
1358     pa_assert(fail);
1359
1360     if (!(m = pa_tokenizer_get(t, 1))) {
1361         pa_strbuf_puts(buf, "You need to specify a suspend switch setting (0/1).\n");
1362         return -1;
1363     }
1364
1365     if ((suspend = pa_parse_boolean(m)) < 0) {
1366         pa_strbuf_puts(buf, "Failed to parse suspend switch.\n");
1367         return -1;
1368     }
1369
1370     if ((r = pa_sink_suspend_all(c, suspend, PA_SUSPEND_USER)) < 0)
1371         pa_strbuf_printf(buf, "Failed to resume/suspend all sinks: %s\n", pa_strerror(r));
1372
1373     if ((r = pa_source_suspend_all(c, suspend, PA_SUSPEND_USER)) < 0)
1374         pa_strbuf_printf(buf, "Failed to resume/suspend all sources: %s\n", pa_strerror(r));
1375
1376     return 0;
1377 }
1378
1379 static int pa_cli_command_log_level(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1380     const char *m;
1381     uint32_t level;
1382
1383     pa_core_assert_ref(c);
1384     pa_assert(t);
1385     pa_assert(buf);
1386     pa_assert(fail);
1387
1388     if (!(m = pa_tokenizer_get(t, 1))) {
1389         pa_strbuf_puts(buf, "You need to specify a log level (0..4).\n");
1390         return -1;
1391     }
1392
1393     if (pa_atou(m, &level) < 0 || level >= PA_LOG_LEVEL_MAX) {
1394         pa_strbuf_puts(buf, "Failed to parse log level.\n");
1395         return -1;
1396     }
1397
1398     pa_log_set_level(level);
1399
1400     return 0;
1401 }
1402
1403 static int pa_cli_command_log_meta(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1404     const char *m;
1405     pa_bool_t b;
1406
1407     pa_core_assert_ref(c);
1408     pa_assert(t);
1409     pa_assert(buf);
1410     pa_assert(fail);
1411
1412     if (!(m = pa_tokenizer_get(t, 1))) {
1413         pa_strbuf_puts(buf, "You need to specify a boolean.\n");
1414         return -1;
1415     }
1416
1417     if ((b = pa_parse_boolean(m)) < 0) {
1418         pa_strbuf_puts(buf, "Failed to parse log meta switch.\n");
1419         return -1;
1420     }
1421
1422     pa_log_set_flags(PA_LOG_PRINT_META, b ? PA_LOG_SET : PA_LOG_UNSET);
1423
1424     return 0;
1425 }
1426
1427 static int pa_cli_command_log_time(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1428     const char *m;
1429     pa_bool_t b;
1430
1431     pa_core_assert_ref(c);
1432     pa_assert(t);
1433     pa_assert(buf);
1434     pa_assert(fail);
1435
1436     if (!(m = pa_tokenizer_get(t, 1))) {
1437         pa_strbuf_puts(buf, "You need to specify a boolean.\n");
1438         return -1;
1439     }
1440
1441     if ((b = pa_parse_boolean(m)) < 0) {
1442         pa_strbuf_puts(buf, "Failed to parse log meta switch.\n");
1443         return -1;
1444     }
1445
1446     pa_log_set_flags(PA_LOG_PRINT_TIME, b ? PA_LOG_SET : PA_LOG_UNSET);
1447
1448     return 0;
1449 }
1450
1451 static int pa_cli_command_log_backtrace(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1452     const char *m;
1453     uint32_t nframes;
1454
1455     pa_core_assert_ref(c);
1456     pa_assert(t);
1457     pa_assert(buf);
1458     pa_assert(fail);
1459
1460     if (!(m = pa_tokenizer_get(t, 1))) {
1461         pa_strbuf_puts(buf, "You need to specify a backtrace level.\n");
1462         return -1;
1463     }
1464
1465     if (pa_atou(m, &nframes) < 0 || nframes >= 1000) {
1466         pa_strbuf_puts(buf, "Failed to parse backtrace level.\n");
1467         return -1;
1468     }
1469
1470     pa_log_set_show_backtrace(nframes);
1471
1472     return 0;
1473 }
1474
1475 static int pa_cli_command_card_profile(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1476     const char *n, *p;
1477     pa_card *card;
1478
1479     pa_core_assert_ref(c);
1480     pa_assert(t);
1481     pa_assert(buf);
1482     pa_assert(fail);
1483
1484     if (!(n = pa_tokenizer_get(t, 1))) {
1485         pa_strbuf_puts(buf, "You need to specify a card either by its name or its index.\n");
1486         return -1;
1487     }
1488
1489     if (!(p = pa_tokenizer_get(t, 2))) {
1490         pa_strbuf_puts(buf, "You need to specify a profile by its name.\n");
1491         return -1;
1492     }
1493
1494     if (!(card = pa_namereg_get(c, n, PA_NAMEREG_CARD))) {
1495         pa_strbuf_puts(buf, "No card found by this name or index.\n");
1496         return -1;
1497     }
1498
1499     if (pa_card_set_profile(card, p, TRUE) < 0) {
1500         pa_strbuf_printf(buf, "Failed to set card profile to '%s'.\n", p);
1501         return -1;
1502     }
1503
1504     return 0;
1505 }
1506
1507 static int pa_cli_command_sink_port(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1508     const char *n, *p;
1509     pa_sink *sink;
1510
1511     pa_core_assert_ref(c);
1512     pa_assert(t);
1513     pa_assert(buf);
1514     pa_assert(fail);
1515
1516     if (!(n = pa_tokenizer_get(t, 1))) {
1517         pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n");
1518         return -1;
1519     }
1520
1521     if (!(p = pa_tokenizer_get(t, 2))) {
1522         pa_strbuf_puts(buf, "You need to specify a profile by its name.\n");
1523         return -1;
1524     }
1525
1526     if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK))) {
1527         pa_strbuf_puts(buf, "No sink found by this name or index.\n");
1528         return -1;
1529     }
1530
1531     if (pa_sink_set_port(sink, p, TRUE) < 0) {
1532         pa_strbuf_printf(buf, "Failed to set sink port to '%s'.\n", p);
1533         return -1;
1534     }
1535
1536     return 0;
1537 }
1538
1539 static int pa_cli_command_source_port(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1540     const char *n, *p;
1541     pa_source *source;
1542
1543     pa_core_assert_ref(c);
1544     pa_assert(t);
1545     pa_assert(buf);
1546     pa_assert(fail);
1547
1548     if (!(n = pa_tokenizer_get(t, 1))) {
1549         pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n");
1550         return -1;
1551     }
1552
1553     if (!(p = pa_tokenizer_get(t, 2))) {
1554         pa_strbuf_puts(buf, "You need to specify a profile by its name.\n");
1555         return -1;
1556     }
1557
1558     if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE))) {
1559         pa_strbuf_puts(buf, "No source found by this name or index.\n");
1560         return -1;
1561     }
1562
1563     if (pa_source_set_port(source, p, TRUE) < 0) {
1564         pa_strbuf_printf(buf, "Failed to set source port to '%s'.\n", p);
1565         return -1;
1566     }
1567
1568     return 0;
1569 }
1570
1571 static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1572     pa_module *m;
1573     pa_sink *sink;
1574     pa_source *source;
1575     pa_card *card;
1576     pa_bool_t nl;
1577     uint32_t idx;
1578     char txt[256];
1579     time_t now;
1580
1581     pa_core_assert_ref(c);
1582     pa_assert(t);
1583     pa_assert(buf);
1584     pa_assert(fail);
1585
1586     time(&now);
1587
1588 #ifdef HAVE_CTIME_R
1589     pa_strbuf_printf(buf, "### Configuration dump generated at %s\n", ctime_r(&now, txt));
1590 #else
1591     pa_strbuf_printf(buf, "### Configuration dump generated at %s\n", ctime(&now));
1592 #endif
1593
1594     PA_IDXSET_FOREACH(m, c->modules, idx) {
1595
1596         pa_strbuf_printf(buf, "load-module %s", m->name);
1597
1598         if (m->argument)
1599             pa_strbuf_printf(buf, " %s", m->argument);
1600
1601         pa_strbuf_puts(buf, "\n");
1602     }
1603
1604     nl = FALSE;
1605     PA_IDXSET_FOREACH(sink, c->sinks, idx) {
1606
1607         if (!nl) {
1608             pa_strbuf_puts(buf, "\n");
1609             nl = TRUE;
1610         }
1611
1612         pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", sink->name, pa_cvolume_max(pa_sink_get_volume(sink, FALSE)));
1613         pa_strbuf_printf(buf, "set-sink-mute %s %s\n", sink->name, pa_yes_no(pa_sink_get_mute(sink, FALSE)));
1614         pa_strbuf_printf(buf, "suspend-sink %s %s\n", sink->name, pa_yes_no(pa_sink_get_state(sink) == PA_SINK_SUSPENDED));
1615     }
1616
1617     nl = FALSE;
1618     PA_IDXSET_FOREACH(source, c->sources, idx) {
1619
1620         if (!nl) {
1621             pa_strbuf_puts(buf, "\n");
1622             nl = TRUE;
1623         }
1624
1625         pa_strbuf_printf(buf, "set-source-volume %s 0x%03x\n", source->name, pa_cvolume_max(pa_source_get_volume(source, FALSE)));
1626         pa_strbuf_printf(buf, "set-source-mute %s %s\n", source->name, pa_yes_no(pa_source_get_mute(source, FALSE)));
1627         pa_strbuf_printf(buf, "suspend-source %s %s\n", source->name, pa_yes_no(pa_source_get_state(source) == PA_SOURCE_SUSPENDED));
1628     }
1629
1630     nl = FALSE;
1631     PA_IDXSET_FOREACH(card, c->cards, idx) {
1632
1633         if (!nl) {
1634             pa_strbuf_puts(buf, "\n");
1635             nl = TRUE;
1636         }
1637
1638         if (card->active_profile)
1639             pa_strbuf_printf(buf, "set-card-profile %s %s\n", card->name, card->active_profile->name);
1640     }
1641
1642     nl = FALSE;
1643     if ((sink = pa_namereg_get_default_sink(c))) {
1644         if (!nl) {
1645             pa_strbuf_puts(buf, "\n");
1646             nl = TRUE;
1647         }
1648
1649         pa_strbuf_printf(buf, "set-default-sink %s\n", sink->name);
1650     }
1651
1652     if ((source = pa_namereg_get_default_source(c))) {
1653         if (!nl)
1654             pa_strbuf_puts(buf, "\n");
1655
1656         pa_strbuf_printf(buf, "set-default-source %s\n", source->name);
1657     }
1658
1659     pa_strbuf_puts(buf, "\n### EOF\n");
1660
1661     return 0;
1662 }
1663
1664 int pa_cli_command_execute_line_stateful(pa_core *c, const char *s, pa_strbuf *buf, pa_bool_t *fail, int *ifstate) {
1665     const char *cs;
1666
1667     pa_assert(c);
1668     pa_assert(s);
1669     pa_assert(buf);
1670
1671     cs = s+strspn(s, whitespace);
1672
1673     if (*cs == '#' || !*cs)
1674         return 0;
1675     else if (*cs == '.') {
1676         if (!strcmp(cs, META_ELSE)) {
1677             if (!ifstate || *ifstate == IFSTATE_NONE) {
1678                 pa_strbuf_printf(buf, "Meta command %s is not valid in this context\n", cs);
1679                 return -1;
1680             } else if (*ifstate == IFSTATE_TRUE)
1681                 *ifstate = IFSTATE_FALSE;
1682             else
1683                 *ifstate = IFSTATE_TRUE;
1684             return 0;
1685         } else if (!strcmp(cs, META_ENDIF)) {
1686             if (!ifstate || *ifstate == IFSTATE_NONE) {
1687                 pa_strbuf_printf(buf, "Meta command %s is not valid in this context\n", cs);
1688                 return -1;
1689             } else
1690                 *ifstate = IFSTATE_NONE;
1691             return 0;
1692         }
1693         if (ifstate && *ifstate == IFSTATE_FALSE)
1694             return 0;
1695         if (!strcmp(cs, META_FAIL))
1696             *fail = TRUE;
1697         else if (!strcmp(cs, META_NOFAIL))
1698             *fail = FALSE;
1699         else {
1700             size_t l;
1701             l = strcspn(cs, whitespace);
1702
1703             if (l == sizeof(META_INCLUDE)-1 && !strncmp(cs, META_INCLUDE, l)) {
1704                 struct stat st;
1705                 const char *filename = cs+l+strspn(cs+l, whitespace);
1706
1707                 if (stat(filename, &st) < 0) {
1708                     pa_log_warn("stat('%s'): %s", filename, pa_cstrerror(errno));
1709                     if (*fail)
1710                         return -1;
1711                 } else {
1712                     if (S_ISDIR(st.st_mode)) {
1713                         DIR *d;
1714
1715                         if (!(d = opendir(filename))) {
1716                             pa_log_warn("Failed to read '%s': %s", filename, pa_cstrerror(errno));
1717                             if (*fail)
1718                                 return -1;
1719                         } else {
1720                             unsigned i, count;
1721                             char **sorted_files;
1722                             struct dirent *de;
1723                             pa_bool_t failed = FALSE;
1724                             pa_dynarray *files = pa_dynarray_new();
1725
1726                             while ((de = readdir(d))) {
1727                                 char *extn;
1728                                 size_t flen = strlen(de->d_name);
1729
1730                                 if (flen < 4)
1731                                     continue;
1732
1733                                 extn = &de->d_name[flen-3];
1734                                 if (strncmp(extn, ".pa", 3) == 0)
1735                                     pa_dynarray_append(files, pa_sprintf_malloc("%s" PA_PATH_SEP "%s", filename, de->d_name));
1736                             }
1737
1738                             closedir(d);
1739
1740                             count = pa_dynarray_size(files);
1741                             sorted_files = pa_xnew(char*, count);
1742                             for (i = 0; i < count; ++i)
1743                                 sorted_files[i] = pa_dynarray_get(files, i);
1744                             pa_dynarray_free(files, NULL, NULL);
1745
1746                             for (i = 0; i < count; ++i) {
1747                                 for (unsigned j = 0; j < count; ++j) {
1748                                     if (strcmp(sorted_files[i], sorted_files[j]) < 0) {
1749                                         char *tmp = sorted_files[i];
1750                                         sorted_files[i] = sorted_files[j];
1751                                         sorted_files[j] = tmp;
1752                                     }
1753                                 }
1754                             }
1755
1756                             for (i = 0; i < count; ++i) {
1757                                 if (!failed) {
1758                                     if (pa_cli_command_execute_file(c, sorted_files[i], buf, fail) < 0 && *fail)
1759                                         failed = TRUE;
1760                                 }
1761
1762                                 pa_xfree(sorted_files[i]);
1763                             }
1764                             pa_xfree(sorted_files);
1765                             if (failed)
1766                                 return -1;
1767                         }
1768                     } else if (pa_cli_command_execute_file(c, filename, buf, fail) < 0 && *fail) {
1769                         return -1;
1770                     }
1771                 }
1772             } else if (l == sizeof(META_IFEXISTS)-1 && !strncmp(cs, META_IFEXISTS, l)) {
1773                 if (!ifstate) {
1774                     pa_strbuf_printf(buf, "Meta command %s is not valid in this context\n", cs);
1775                     return -1;
1776                 } else if (*ifstate != IFSTATE_NONE) {
1777                     pa_strbuf_printf(buf, "Nested %s commands not supported\n", cs);
1778                     return -1;
1779                 } else {
1780                     const char *filename = cs+l+strspn(cs+l, whitespace);
1781
1782                     /* Search DL_SEARCH_PATH unless the filename is absolute */
1783                     if (filename[0] == PA_PATH_SEP_CHAR) {
1784
1785                         *ifstate = access(filename, F_OK) == 0 ? IFSTATE_TRUE : IFSTATE_FALSE;
1786                         pa_log_debug("Checking for existance of '%s': %s", filename, *ifstate == IFSTATE_TRUE ? "success" : "failure");
1787
1788                     } else {
1789                         const char *paths, *state = NULL;
1790                         char *p;
1791
1792                         if (!(paths = lt_dlgetsearchpath()))
1793                             return -1;
1794
1795                         while ((p = pa_split(paths, ":", &state))) {
1796                             char *pathname;
1797
1798                             pathname = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", p, filename);
1799                             pa_xfree(p);
1800
1801                             *ifstate = access(pathname, F_OK) == 0 ? IFSTATE_TRUE : IFSTATE_FALSE;
1802                             pa_log_debug("Checking for existance of '%s': %s", pathname, *ifstate == IFSTATE_TRUE ? "success" : "failure");
1803
1804                             pa_xfree(pathname);
1805
1806                             if (*ifstate == IFSTATE_TRUE)
1807                                 break;
1808                         }
1809                     }
1810
1811                 }
1812             } else {
1813                 pa_strbuf_printf(buf, "Invalid meta command: %s\n", cs);
1814                 if (*fail) return -1;
1815             }
1816         }
1817     } else {
1818         const struct command*command;
1819         int unknown = 1;
1820         size_t l;
1821
1822         if (ifstate && *ifstate == IFSTATE_FALSE)
1823             return 0;
1824
1825         l = strcspn(cs, whitespace);
1826
1827         for (command = commands; command->name; command++)
1828             if (strlen(command->name) == l && !strncmp(cs, command->name, l)) {
1829                 int ret;
1830                 pa_tokenizer *t = pa_tokenizer_new(cs, command->args);
1831                 pa_assert(t);
1832                 ret = command->proc(c, t, buf, fail);
1833                 pa_tokenizer_free(t);
1834                 unknown = 0;
1835
1836                 if (ret < 0 && *fail)
1837                     return -1;
1838
1839                 break;
1840             }
1841
1842         if (unknown) {
1843             pa_strbuf_printf(buf, "Unknown command: %s\n", cs);
1844             if (*fail)
1845                 return -1;
1846         }
1847     }
1848
1849     return 0;
1850 }
1851
1852 int pa_cli_command_execute_line(pa_core *c, const char *s, pa_strbuf *buf, pa_bool_t *fail) {
1853     return pa_cli_command_execute_line_stateful(c, s, buf, fail, NULL);
1854 }
1855
1856 int pa_cli_command_execute_file_stream(pa_core *c, FILE *f, pa_strbuf *buf, pa_bool_t *fail) {
1857     char line[2048];
1858     int ifstate = IFSTATE_NONE;
1859     int ret = -1;
1860     pa_bool_t _fail = TRUE;
1861
1862     pa_assert(c);
1863     pa_assert(f);
1864     pa_assert(buf);
1865
1866     if (!fail)
1867         fail = &_fail;
1868
1869     while (fgets(line, sizeof(line), f)) {
1870         pa_strip_nl(line);
1871
1872         if (pa_cli_command_execute_line_stateful(c, line, buf, fail, &ifstate) < 0 && *fail)
1873             goto fail;
1874     }
1875
1876     ret = 0;
1877
1878 fail:
1879
1880     return ret;
1881 }
1882
1883 int pa_cli_command_execute_file(pa_core *c, const char *fn, pa_strbuf *buf, pa_bool_t *fail) {
1884     FILE *f = NULL;
1885     int ret = -1;
1886     pa_bool_t _fail = TRUE;
1887
1888     pa_assert(c);
1889     pa_assert(fn);
1890     pa_assert(buf);
1891
1892     if (!fail)
1893         fail = &_fail;
1894
1895     if (!(f = pa_fopen_cloexec(fn, "r"))) {
1896         pa_strbuf_printf(buf, "open('%s') failed: %s\n", fn, pa_cstrerror(errno));
1897         if (!*fail)
1898             ret = 0;
1899         goto fail;
1900     }
1901
1902     pa_log_debug("Parsing script '%s'", fn);
1903     ret = pa_cli_command_execute_file_stream(c, f, buf, fail);
1904
1905 fail:
1906     if (f)
1907         fclose(f);
1908
1909     return ret;
1910 }
1911
1912 int pa_cli_command_execute(pa_core *c, const char *s, pa_strbuf *buf, pa_bool_t *fail) {
1913     const char *p;
1914     int ifstate = IFSTATE_NONE;
1915     pa_bool_t _fail = TRUE;
1916
1917     pa_assert(c);
1918     pa_assert(s);
1919     pa_assert(buf);
1920
1921     if (!fail)
1922         fail = &_fail;
1923
1924     p = s;
1925     while (*p) {
1926         size_t l = strcspn(p, linebreak);
1927         char *line = pa_xstrndup(p, l);
1928
1929         if (pa_cli_command_execute_line_stateful(c, line, buf, fail, &ifstate) < 0 && *fail) {
1930             pa_xfree(line);
1931             return -1;
1932         }
1933         pa_xfree(line);
1934
1935         p += l;
1936         p += strspn(p, linebreak);
1937     }
1938
1939     return 0;
1940 }