1 /* vi: set et sw=4 ts=4 cino=t0,(0: */
2 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 /*
4  * This file is part of mission-control
5  *
6  * Copyright (C) 2005-2009 Nokia Corporation.
7  * Copyright (C) 2005-2009 Collabora Ltd.
8  *
9  * Contact: Alberto Mardegan  <alberto.mardegan@nokia.com>
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public License
13  * version 2.1 as published by the Free Software Foundation.
14  *
15  * This library is distributed in the hope that it will be useful, but
16  * WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23  * 02110-1301 USA
24  *
25  */
26 
27 #include "config.h"
28 
29 #include "mcd-misc.h"
30 #include <errno.h>
31 #include <glib/gstdio.h>
32 #include <fcntl.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <unistd.h>
36 #include <telepathy-glib/telepathy-glib.h>
37 
38 #include "mcd-debug.h"
39 
40 #include "_gen/register-dbus-glib-marshallers-body.h"
41 
42 #include <dbus/dbus.h>
43 #include <dbus/dbus-glib-lowlevel.h>
44 
45 /*
46  * Miscellaneus functions
47  */
48 
49 GHashTable *
_mcd_deepcopy_asv(GHashTable * asv)50 _mcd_deepcopy_asv (GHashTable *asv)
51 {
52     GHashTable *copy;
53 
54     copy = g_hash_table_new_full (g_str_hash, g_str_equal,
55                                   g_free,
56                                   (GDestroyNotify)tp_g_value_slice_free);
57     tp_g_hash_table_update (copy, asv, (GBoxedCopyFunc) g_strdup,
58                             (GBoxedCopyFunc) tp_g_value_slice_dup);
59     return copy;
60 }
61 
62 gchar *
_mcd_build_error_string(const GError * error)63 _mcd_build_error_string (const GError *error)
64 {
65     GEnumValue *value;
66     GEnumClass *klass;
67     const gchar *prefix;
68 
69     if (error->domain == TP_ERROR)
70     {
71         klass = g_type_class_ref (TP_TYPE_ERROR);
72         prefix = TP_ERROR_PREFIX;
73     }
74     else
75         return NULL;
76     value = g_enum_get_value (klass, error->code);
77     g_type_class_unref (klass);
78 
79     if (G_LIKELY (value && value->value_nick))
80         return g_strconcat (prefix, ".", value->value_nick, NULL);
81     else
82         return NULL;
83 }
84 
85 typedef struct
86 {
87     McdReadyCb callback;
88     gpointer user_data;
89 } McdReadyCbData;
90 
91 typedef struct
92 {
93     gpointer strukt;
94     GSList *callbacks;
95 } McdReadyData;
96 
97 static void
mcd_object_invoke_ready_callbacks(McdReadyData * rd,const GError * error)98 mcd_object_invoke_ready_callbacks (McdReadyData *rd, const GError *error)
99 {
100     GSList *list;
101 
102     for (list = rd->callbacks; list != NULL; list = list->next)
103     {
104         McdReadyCbData *cb = list->data;
105 
106         cb->callback (rd->strukt, error, cb->user_data);
107         g_slice_free (McdReadyCbData, cb);
108     }
109     g_slist_free (rd->callbacks);
110 }
111 
112 static void
mcd_ready_data_free(McdReadyData * rd)113 mcd_ready_data_free (McdReadyData *rd)
114 {
115     if (rd->strukt)
116     {
117         GError error = { TP_ERROR, TP_ERROR_CANCELLED, "Object disposed" };
118         mcd_object_invoke_ready_callbacks (rd, &error);
119     }
120     g_slice_free (McdReadyData, rd);
121 }
122 
123 void
_mcd_object_call_when_ready(gpointer object,GQuark quark,McdReadyCb callback,gpointer user_data)124 _mcd_object_call_when_ready (gpointer object, GQuark quark, McdReadyCb callback,
125                              gpointer user_data)
126 {
127     _mcd_object_call_on_struct_when_ready (object, object, quark, callback,
128                                            user_data);
129 }
130 
131 void
_mcd_object_call_on_struct_when_ready(gpointer object,gpointer strukt,GQuark quark,McdReadyCb callback,gpointer user_data)132 _mcd_object_call_on_struct_when_ready (gpointer object, gpointer strukt,
133                                        GQuark quark, McdReadyCb callback,
134                                        gpointer user_data)
135 {
136     McdReadyData *rd;
137     McdReadyCbData *cb;
138 
139     g_return_if_fail (G_IS_OBJECT (object));
140     g_return_if_fail (quark != 0);
141     g_return_if_fail (callback != NULL);
142 
143     cb = g_slice_new (McdReadyCbData);
144     cb->callback = callback;
145     cb->user_data = user_data;
146 
147     rd = g_object_get_qdata ((GObject *)object, quark);
148     if (!rd)
149     {
150         rd = g_slice_new (McdReadyData);
151         rd->strukt = strukt;
152         rd->callbacks = NULL;
153         g_object_set_qdata_full ((GObject *)object, quark, rd,
154                                  (GDestroyNotify)mcd_ready_data_free);
155     }
156     rd->callbacks = g_slist_prepend (rd->callbacks, cb);
157 }
158 
159 void
_mcd_object_ready(gpointer object,GQuark quark,const GError * error)160 _mcd_object_ready (gpointer object, GQuark quark, const GError *error)
161 {
162     McdReadyData *rd;
163 
164     /* steal the qdata so the callbacks won't be invoked again, even if the
165      * object becomes ready or is finalized while still invoking them */
166     rd = g_object_steal_qdata ((GObject *)object, quark);
167     if (!rd) return;
168 
169     g_object_ref (object);
170 
171     mcd_object_invoke_ready_callbacks (rd, error);
172     rd->strukt = NULL; /* so the callbacks won't be invoked again */
173     mcd_ready_data_free (rd);
174 
175     g_object_unref (object);
176 }
177 
178 gboolean
mcd_ensure_directory(const gchar * dir,GError ** error)179 mcd_ensure_directory (const gchar *dir,
180                       GError **error)
181 {
182     DEBUG ("%s", dir);
183 
184     if (g_mkdir_with_parents (dir, 0700) != 0)
185     {
186         g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE,
187                      "Unable to create directory '%s': %s",
188                      dir, g_strerror (errno));
189         return FALSE;
190     }
191 
192     return TRUE;
193 }
194 
195 int
_mcd_chmod_private(const gchar * filename)196 _mcd_chmod_private (const gchar *filename)
197 {
198     struct stat buf;
199     int ret;
200 
201     ret = g_stat (filename, &buf);
202 
203     if (ret < 0)
204     {
205         DEBUG ("g_stat(%s): %s", filename, g_strerror (errno));
206         return ret;
207     }
208 
209     if ((buf.st_mode & 0077) != 0)
210     {
211         DEBUG ("chmod go-rwx %s", filename);
212         ret = g_chmod (filename, (buf.st_mode & ~0077));
213 
214         if (ret < 0)
215         {
216             DEBUG ("g_chmod: %s", g_strerror (errno));
217         }
218     }
219 
220     return ret;
221 }
222 
223 gboolean
mcd_nullable_variant_equal(GVariant * a,GVariant * b)224 mcd_nullable_variant_equal (GVariant *a,
225                             GVariant *b)
226 {
227     if (a == b)
228         return TRUE;
229 
230     if (a == NULL || b == NULL)
231         return FALSE;
232 
233     return g_variant_equal (a, b);
234 }
235