x11: add a few helper functions for multi-clipboard
[vd_agent.git] / console-kit.c
blobeb15939cd8db52df17c11da1eb829c8ed7e7e610
1 /* console-kit.h vdagentd ConsoleKit integration code
3 Copyright 2010 Red Hat, Inc.
5 Red Hat Authors:
6 Hans de Goede <hdegoede@redhat.com>
8 This program is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "console-kit.h"
23 #include <dbus/dbus.h>
24 #include <stdbool.h>
25 #include <unistd.h>
26 #include <stdlib.h>
27 #include <string.h>
29 struct console_kit {
30 DBusConnection *connection;
31 int fd;
32 char *seat;
33 char *active_session;
34 FILE *errfile;
37 static char *console_kit_get_first_seat(struct console_kit *ck);
38 static char *console_kit_check_active_session_change(struct console_kit *ck);
40 struct console_kit *console_kit_create(FILE *errfile)
42 struct console_kit *ck;
43 DBusError error;
44 char match[1024];
46 ck = calloc(1, sizeof(*ck));
47 if (!ck)
48 return NULL;
50 ck->errfile = errfile;
52 dbus_error_init(&error);
53 ck->connection = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
54 if (ck->connection == NULL || dbus_error_is_set(&error)) {
55 if (dbus_error_is_set(&error)) {
56 fprintf(ck->errfile, "Unable to connect to system bus: %s\n",
57 error.message);
58 dbus_error_free(&error);
59 } else
60 fprintf(ck->errfile, "Unable to connect to system bus\n");
61 free(ck);
62 return NULL;
65 if (!dbus_connection_get_unix_fd(ck->connection, &ck->fd)) {
66 fprintf(ck->errfile, "Unable to get connection fd\n");
67 console_kit_destroy(ck);
68 return NULL;
71 if (!console_kit_get_first_seat(ck)) {
72 console_kit_destroy(ck);
73 return NULL;
76 /* Register for active session changes */
77 snprintf(match, sizeof(match),
78 "type='signal',interface='org.freedesktop.ConsoleKit.Seat',"
79 "path='%s',member='ActiveSessionChanged'", ck->seat);
80 dbus_error_init(&error);
81 dbus_bus_add_match(ck->connection, match, &error);
82 if (dbus_error_is_set(&error)) {
83 fprintf(ck->errfile, "Match Error (%s)\n", error.message);
84 console_kit_destroy(ck);
85 return NULL;
88 return ck;
91 void console_kit_destroy(struct console_kit *ck)
93 if (!ck)
94 return;
96 dbus_connection_close(ck->connection);
97 free(ck->seat);
98 free(ck->active_session);
99 free(ck);
102 int console_kit_get_fd(struct console_kit *ck)
104 return ck->fd;
107 static char *console_kit_get_first_seat(struct console_kit *ck)
109 DBusError error;
110 DBusMessage *message = NULL;
111 DBusMessage *reply = NULL;
112 DBusMessageIter iter, subiter;
113 int type;
114 char *seat = NULL;
116 message = dbus_message_new_method_call("org.freedesktop.ConsoleKit",
117 "/org/freedesktop/ConsoleKit/Manager",
118 "org.freedesktop.ConsoleKit.Manager",
119 "GetSeats");
120 if (message == NULL) {
121 fprintf(ck->errfile, "Unable to create dbus message\n");
122 goto exit;
125 dbus_error_init(&error);
126 reply = dbus_connection_send_with_reply_and_block(ck->connection,
127 message,
129 &error);
130 if (reply == NULL || dbus_error_is_set(&error)) {
131 if (dbus_error_is_set(&error)) {
132 fprintf(ck->errfile, "GetSeats failed: %s\n",
133 error.message);
134 dbus_error_free(&error);
135 } else
136 fprintf(ck->errfile, "GetSeats failed\n");
137 goto exit;
140 dbus_message_iter_init(reply, &iter);
141 type = dbus_message_iter_get_arg_type(&iter);
142 if (type != DBUS_TYPE_ARRAY) {
143 fprintf(ck->errfile,
144 "expected an array return value, got a '%c' instead\n", type);
145 goto exit;
148 dbus_message_iter_recurse(&iter, &subiter);
149 type = dbus_message_iter_get_arg_type(&subiter);
150 if (type != DBUS_TYPE_OBJECT_PATH) {
151 fprintf(ck->errfile,
152 "expected an object path element, got a '%c' instead\n", type);
153 goto exit;
156 dbus_message_iter_get_basic(&subiter, &seat);
157 ck->seat = strdup(seat);
159 exit:
160 if (reply != NULL) {
161 dbus_message_unref(reply);
164 if (message != NULL) {
165 dbus_message_unref(message);
168 return ck->seat;
171 const char *console_kit_get_active_session(struct console_kit *ck)
173 DBusError error;
174 DBusMessage *message = NULL;
175 DBusMessage *reply = NULL;
176 char *session = NULL;
178 if (!ck)
179 return NULL;
181 if (ck->active_session)
182 return console_kit_check_active_session_change(ck);
184 message = dbus_message_new_method_call("org.freedesktop.ConsoleKit",
185 ck->seat,
186 "org.freedesktop.ConsoleKit.Seat",
187 "GetActiveSession");
188 if (message == NULL) {
189 fprintf(ck->errfile, "Unable to create dbus message\n");
190 goto exit;
193 dbus_error_init(&error);
194 reply = dbus_connection_send_with_reply_and_block(ck->connection,
195 message,
197 &error);
198 if (reply == NULL || dbus_error_is_set(&error)) {
199 if (dbus_error_is_set(&error)) {
200 fprintf(ck->errfile, "GetActiveSession failed: %s\n",
201 error.message);
202 dbus_error_free(&error);
203 } else
204 fprintf(ck->errfile, "GetActiveSession failed\n");
205 goto exit;
208 dbus_error_init(&error);
209 if (!dbus_message_get_args(reply,
210 &error,
211 DBUS_TYPE_OBJECT_PATH, &session,
212 DBUS_TYPE_INVALID)) {
213 if (dbus_error_is_set(&error)) {
214 fprintf(ck->errfile, "error getting ssid from reply: %s\n",
215 error.message);
216 dbus_error_free(&error);
217 } else
218 fprintf(ck->errfile, "error getting ssid from reply\n");
219 session = NULL;
220 goto exit;
223 ck->active_session = strdup(session);
225 exit:
226 if (reply != NULL) {
227 dbus_message_unref(reply);
230 if (message != NULL) {
231 dbus_message_unref(message);
234 /* In case the session was changed while we were running */
235 return console_kit_check_active_session_change(ck);
238 char *console_kit_session_for_pid(struct console_kit *ck, uint32_t pid)
240 DBusError error;
241 DBusMessage *message = NULL;
242 DBusMessage *reply = NULL;
243 DBusMessageIter args;
244 char *ssid = NULL;
246 if (!ck)
247 return NULL;
249 message = dbus_message_new_method_call("org.freedesktop.ConsoleKit",
250 "/org/freedesktop/ConsoleKit/Manager",
251 "org.freedesktop.ConsoleKit.Manager",
252 "GetSessionForUnixProcess");
253 if (message == NULL) {
254 fprintf(ck->errfile, "Unable to create dbus message\n");
255 goto exit;
258 dbus_message_iter_init_append(message, &args);
259 if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_UINT32, &pid)) {
260 fprintf(ck->errfile, "Unable to append dbus message args\n");
261 goto exit;
264 dbus_error_init(&error);
265 reply = dbus_connection_send_with_reply_and_block(ck->connection,
266 message,
268 &error);
269 if (reply == NULL || dbus_error_is_set(&error)) {
270 if (dbus_error_is_set(&error)) {
271 fprintf(ck->errfile, "GetSessionForUnixProcess failed: %s\n",
272 error.message);
273 dbus_error_free(&error);
274 } else
275 fprintf(ck->errfile, "GetSessionForUnixProces failed\n");
276 goto exit;
279 dbus_error_init(&error);
280 if (!dbus_message_get_args(reply,
281 &error,
282 DBUS_TYPE_OBJECT_PATH, &ssid,
283 DBUS_TYPE_INVALID)) {
284 if (dbus_error_is_set(&error)) {
285 fprintf(ck->errfile, "error getting ssid from reply: %s\n",
286 error.message);
287 dbus_error_free(&error);
288 } else
289 fprintf(ck->errfile, "error getting ssid from reply\n");
290 ssid = NULL;
291 goto exit;
294 ssid = strdup(ssid);
296 exit:
297 if (reply != NULL) {
298 dbus_message_unref(reply);
301 if (message != NULL) {
302 dbus_message_unref(message);
305 return ssid;
308 static char *console_kit_check_active_session_change(struct console_kit *ck)
310 DBusMessage *message = NULL;
311 DBusMessageIter iter;
312 char *session;
313 int type;
315 /* non blocking read of the next available message */
316 dbus_connection_read_write(ck->connection, 0);
317 while ((message = dbus_connection_pop_message(ck->connection))) {
318 if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL) {
319 const char *member = dbus_message_get_member (message);
320 if (!strcmp(member, "NameAcquired")) {
321 dbus_message_unref(message);
322 continue;
324 if (strcmp(member, "ActiveSessionChanged")) {
325 fprintf(ck->errfile, "unexpected signal member: %s\n", member);
326 dbus_message_unref(message);
327 continue;
329 } else {
330 fprintf(ck->errfile, "received non signal message!\n");
331 dbus_message_unref(message);
332 continue;
335 free(ck->active_session);
336 ck->active_session = NULL;
338 dbus_message_iter_init(message, &iter);
339 type = dbus_message_iter_get_arg_type(&iter);
340 /* Session should be an object path, but there is a bug in
341 ConsoleKit where it sends a string rather then an object_path
342 accept object_path too in case the bug ever gets fixed */
343 if (type != DBUS_TYPE_STRING && type != DBUS_TYPE_OBJECT_PATH) {
344 fprintf(ck->errfile,
345 "ActiveSessionChanged message has unexpected type: '%c'\n",
346 type);
347 dbus_message_unref(message);
348 continue;
351 dbus_message_iter_get_basic(&iter, &session);
352 ck->active_session = strdup(session);
353 dbus_message_unref(message);
355 /* non blocking read of the next available message */
356 dbus_connection_read_write(ck->connection, 0);
359 return ck->active_session;