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