1/***
2  This file is part of PulseAudio.
3
4  Copyright 2004-2006 Lennart Poettering
5
6  PulseAudio is free software; you can redistribute it and/or modify
7  it under the terms of the GNU Lesser General Public License as published
8  by the Free Software Foundation; either version 2.1 of the License,
9  or (at your option) any later version.
10
11  PulseAudio is distributed in the hope that it will be useful, but
12  WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  General Public License for more details.
15
16  You should have received a copy of the GNU Lesser General Public License
17  along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
18***/
19
20#ifdef HAVE_CONFIG_H
21#include <config.h>
22#endif
23
24#include <stdio.h>
25#include <getopt.h>
26#include <assert.h>
27#include <locale.h>
28
29#include <xcb/xcb.h>
30
31#include <pulse/util.h>
32#include <pulse/client-conf.h>
33
34#include <pulsecore/core-util.h>
35#include <pulsecore/i18n.h>
36#include <pulsecore/log.h>
37#include <pulsecore/authkey.h>
38#include <pulsecore/native-common.h>
39#include <pulsecore/x11prop.h>
40
41int main(int argc, char *argv[]) {
42    const char *dname = NULL, *sink = NULL, *source = NULL, *server = NULL, *cookie_file = PA_NATIVE_COOKIE_FILE;
43    int c, ret = 1, screen = 0;
44    xcb_connection_t *xcb = NULL;
45    enum { DUMP, EXPORT, IMPORT, REMOVE } mode = DUMP;
46
47    setlocale(LC_ALL, "");
48#ifdef ENABLE_NLS
49    bindtextdomain(GETTEXT_PACKAGE, PULSE_LOCALEDIR);
50#endif
51
52    while ((c = getopt(argc, argv, "deiD:S:O:I:c:hr")) != -1) {
53        switch (c) {
54            case 'D' :
55                dname = optarg;
56                break;
57            case 'h':
58                printf(_("%s [-D display] [-S server] [-O sink] [-I source] [-c file]  [-d|-e|-i|-r]\n\n"
59                       " -d    Show current PulseAudio data attached to X11 display (default)\n"
60                       " -e    Export local PulseAudio data to X11 display\n"
61                       " -i    Import PulseAudio data from X11 display to local environment variables and cookie file.\n"
62                       " -r    Remove PulseAudio data from X11 display\n"),
63                       pa_path_get_filename(argv[0]));
64                ret = 0;
65                goto finish;
66            case 'd':
67                mode = DUMP;
68                break;
69            case 'e':
70                mode = EXPORT;
71                break;
72            case 'i':
73                mode = IMPORT;
74                break;
75            case 'r':
76                mode = REMOVE;
77                break;
78            case 'c':
79                cookie_file = optarg;
80                break;
81            case 'I':
82                source = optarg;
83                break;
84            case 'O':
85                sink = optarg;
86                break;
87            case 'S':
88                server = optarg;
89                break;
90            default:
91                fprintf(stderr, _("Failed to parse command line.\n"));
92                goto finish;
93        }
94    }
95
96    if (!(xcb = xcb_connect(dname, &screen))) {
97        pa_log(_("xcb_connect() failed"));
98        goto finish;
99    }
100
101    if (xcb_connection_has_error(xcb)) {
102        pa_log(_("xcb_connection_has_error() returned true"));
103        goto finish;
104    }
105
106    switch (mode) {
107        case DUMP: {
108            char t[1024];
109            if (pa_x11_get_prop(xcb, screen, "PULSE_SERVER", t, sizeof(t)))
110                printf(_("Server: %s\n"), t);
111            if (pa_x11_get_prop(xcb, screen, "PULSE_SOURCE", t, sizeof(t)))
112                printf(_("Source: %s\n"), t);
113            if (pa_x11_get_prop(xcb, screen, "PULSE_SINK", t, sizeof(t)))
114                printf(_("Sink: %s\n"), t);
115            if (pa_x11_get_prop(xcb, screen, "PULSE_COOKIE", t, sizeof(t)))
116                printf(_("Cookie: %s\n"), t);
117
118            break;
119        }
120
121        case IMPORT: {
122            char t[1024];
123            if (pa_x11_get_prop(xcb, screen, "PULSE_SERVER", t, sizeof(t)))
124                printf("PULSE_SERVER='%s'\nexport PULSE_SERVER\n", t);
125            if (pa_x11_get_prop(xcb, screen, "PULSE_SOURCE", t, sizeof(t)))
126                printf("PULSE_SOURCE='%s'\nexport PULSE_SOURCE\n", t);
127            if (pa_x11_get_prop(xcb, screen, "PULSE_SINK", t, sizeof(t)))
128                printf("PULSE_SINK='%s'\nexport PULSE_SINK\n", t);
129
130            if (pa_x11_get_prop(xcb, screen, "PULSE_COOKIE", t, sizeof(t))) {
131                uint8_t cookie[PA_NATIVE_COOKIE_LENGTH];
132                size_t l;
133                if ((l = pa_parsehex(t, cookie, sizeof(cookie))) != sizeof(cookie)) {
134                    fprintf(stderr, _("Failed to parse cookie data\n"));
135                    goto finish;
136                }
137
138                if (pa_authkey_save(cookie_file, cookie, l) < 0) {
139                    fprintf(stderr, _("Failed to save cookie data\n"));
140                    goto finish;
141                }
142            }
143
144            break;
145        }
146
147        case EXPORT: {
148            pa_client_conf *conf = pa_client_conf_new();
149            uint8_t cookie[PA_NATIVE_COOKIE_LENGTH];
150            char hx[PA_NATIVE_COOKIE_LENGTH*2+1];
151            assert(conf);
152
153            pa_client_conf_load(conf, false, true);
154
155            pa_x11_del_prop(xcb, screen, "PULSE_SERVER");
156            pa_x11_del_prop(xcb, screen, "PULSE_SINK");
157            pa_x11_del_prop(xcb, screen, "PULSE_SOURCE");
158            pa_x11_del_prop(xcb, screen, "PULSE_ID");
159            pa_x11_del_prop(xcb, screen, "PULSE_COOKIE");
160
161            if (server)
162                pa_x11_set_prop(xcb, screen, "PULSE_SERVER", server);
163            else if (conf->default_server)
164                pa_x11_set_prop(xcb, screen, "PULSE_SERVER", conf->default_server);
165            else {
166                char hn[256];
167                if (!pa_get_fqdn(hn, sizeof(hn))) {
168                    fprintf(stderr, _("Failed to get FQDN.\n"));
169                    goto finish;
170                }
171
172                pa_x11_set_prop(xcb, screen, "PULSE_SERVER", hn);
173            }
174
175            if (sink)
176                pa_x11_set_prop(xcb, screen, "PULSE_SINK", sink);
177            else if (conf->default_sink)
178                pa_x11_set_prop(xcb, screen, "PULSE_SINK", conf->default_sink);
179
180            if (source)
181                pa_x11_set_prop(xcb, screen, "PULSE_SOURCE", source);
182            if (conf->default_source)
183                pa_x11_set_prop(xcb, screen, "PULSE_SOURCE", conf->default_source);
184
185            pa_client_conf_free(conf);
186
187            if (pa_authkey_load(cookie_file, true, cookie, sizeof(cookie)) < 0) {
188                fprintf(stderr, _("Failed to load cookie data\n"));
189                goto finish;
190            }
191
192            pa_x11_set_prop(xcb, screen, "PULSE_COOKIE", pa_hexstr(cookie, sizeof(cookie), hx, sizeof(hx)));
193            break;
194        }
195
196        case REMOVE:
197            pa_x11_del_prop(xcb, screen, "PULSE_SERVER");
198            pa_x11_del_prop(xcb, screen, "PULSE_SINK");
199            pa_x11_del_prop(xcb, screen, "PULSE_SOURCE");
200            pa_x11_del_prop(xcb, screen, "PULSE_ID");
201            pa_x11_del_prop(xcb, screen, "PULSE_COOKIE");
202            pa_x11_del_prop(xcb, screen, "PULSE_SESSION_ID");
203            break;
204
205        default:
206            fprintf(stderr, _("Not yet implemented.\n"));
207            goto finish;
208    }
209
210    ret = 0;
211
212finish:
213
214    if (xcb) {
215        xcb_flush(xcb);
216        xcb_disconnect(xcb);
217    }
218
219    return ret;
220}
221