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