Add requirement of python-xml for test subpackage
[profile/ivi/neard.git] / src / agent.c
1 /*
2  *
3  *  neard - Near Field Communication manager
4  *
5  *  Copyright (C) 2012  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <errno.h>
29 #include <string.h>
30
31 #include <glib.h>
32
33 #include <gdbus.h>
34
35 #include "near.h"
36
37 static DBusConnection *connection = NULL;
38 static GHashTable *ndef_app_hash;
39
40 struct near_ndef_agent {
41         char *sender;
42         char *path;
43         char *record_type;
44         guint watch;
45 };
46
47 static void ndef_agent_free(gpointer data)
48 {
49         DBusMessage *message;
50         struct near_ndef_agent *agent = data;
51
52         DBG("");
53
54         if (agent == NULL)
55                 return;
56
57         DBG("%s %s %s", agent->sender, agent->path, NFC_NDEF_AGENT_INTERFACE);
58
59         message = dbus_message_new_method_call(agent->sender, agent->path,
60                                         NFC_NDEF_AGENT_INTERFACE, "Release");
61         if (message == NULL)
62                 return;
63
64         dbus_message_set_no_reply(message, TRUE);
65
66         g_dbus_send_message(connection, message);
67
68         g_dbus_remove_watch(connection, agent->watch);
69
70         g_free(agent->sender);
71         g_free(agent->path);
72 }
73
74 static void ndef_agent_disconnect(DBusConnection *conn, void *user_data)
75 {
76         struct near_ndef_agent *agent = user_data;
77
78         DBG("agent %s disconnected", agent->path);
79
80         g_hash_table_remove(ndef_app_hash, agent->record_type);
81 }
82
83 static void append_record_path(DBusMessageIter *iter, void *user_data)
84 {
85         GList *records = user_data, *list;
86         struct near_ndef_record *record;
87         char *path;
88
89         for (list = records; list; list = list->next) {
90                 record = list->data;
91
92                 path = __near_ndef_record_get_path(record);
93                 if (path == NULL)
94                         continue;
95
96                 dbus_message_iter_append_basic(iter,
97                                         DBUS_TYPE_STRING, &path);
98         }
99 }
100
101 static void ndef_agent_push_records(struct near_ndef_agent *agent,
102                                                         GList *records)
103 {
104         DBusMessageIter iter, dict;
105         DBusMessage *message;
106
107         DBG("");
108
109         if (agent->sender == NULL || agent->path == NULL)
110                 return;
111
112         DBG("Sending NDEF to %s %s", agent->path, agent->sender);
113
114         message = dbus_message_new_method_call(agent->sender, agent->path,
115                                         NFC_NDEF_AGENT_INTERFACE,
116                                         "GetNDEF");
117         if (message == NULL)
118                 return;
119
120         dbus_message_iter_init_append(message, &iter);
121
122         near_dbus_dict_open(&iter, &dict);
123         near_dbus_dict_append_array(&dict, "Records",
124                                 DBUS_TYPE_STRING, append_record_path, records);
125         near_dbus_dict_close(&iter, &dict);
126
127         DBG("sending...");
128
129         dbus_message_set_no_reply(message, TRUE);
130
131         g_dbus_send_message(connection, message);
132 }
133
134 void __near_agent_ndef_parse_records(GList *records)
135 {
136         GList *list;
137         struct near_ndef_record *record;
138         struct near_ndef_agent *agent;
139         char *type;
140
141         DBG("");
142
143         for (list = records, agent = NULL; list; list = list->next) {
144                 record = list->data;
145                 type  = __near_ndef_record_get_type(record);
146
147                 DBG("Looking for type %s", type);
148
149                 agent = g_hash_table_lookup(ndef_app_hash, type);
150                 if (agent != NULL)
151                         break;
152         }
153
154         if (agent == NULL)
155                 return;
156
157         ndef_agent_push_records(agent, records);
158
159         return;
160 }
161
162 int __near_agent_ndef_register(const char *sender, const char *path,
163                                                 const char *record_type)
164 {
165         struct near_ndef_agent *agent;
166
167         DBG("%s registers path %s for %s", sender, path, record_type);
168
169         if (g_hash_table_lookup(ndef_app_hash, record_type) != NULL)
170                 return -EEXIST;
171
172         agent = g_try_malloc0(sizeof(struct near_ndef_agent));
173         if (agent == NULL)
174                 return -ENOMEM;
175
176         agent->sender = g_strdup(sender);
177         agent->path = g_strdup(path);
178         agent->record_type = g_strdup(record_type);
179         
180         if (agent->sender == NULL || agent->path == NULL ||
181             agent->record_type == NULL) {
182                 g_free(agent);
183                 return -ENOMEM;
184         }
185
186         agent->watch = g_dbus_add_disconnect_watch(connection, sender,
187                                                 ndef_agent_disconnect, agent, NULL);
188         g_hash_table_insert(ndef_app_hash, agent->record_type, agent);
189
190         return 0;
191 }
192
193 int __near_agent_ndef_unregister(const char *sender, const char *path,
194                                                 const char *record_type)
195 {
196         struct near_ndef_agent *agent;
197
198         DBG("sender %s path %s type %s", sender, path, record_type);
199
200         agent = g_hash_table_lookup(ndef_app_hash, record_type);
201         if (agent == NULL)
202                 return -EINVAL;
203
204         if (strcmp(agent->path, path) != 0 || strcmp(agent->sender, sender) != 0)
205                 return -EINVAL;
206
207         g_hash_table_remove(ndef_app_hash, record_type);
208
209         return 0;
210 }
211
212 static guint handover_agent_watch = 0;
213 static gchar *handover_agent_path = NULL;
214 static gchar *handover_agent_sender = NULL;
215
216 static void handover_agent_free(void)
217 {
218         handover_agent_watch = 0;
219
220         g_free(handover_agent_sender);
221         handover_agent_sender = NULL;
222
223         g_free(handover_agent_path);
224         handover_agent_path = NULL;
225 }
226
227 static void handover_agent_disconnect(DBusConnection *conn, void *data)
228 {
229         DBG("data %p", data);
230
231         handover_agent_free();
232 }
233
234 int __near_agent_handover_register(const char *sender, const char *path)
235 {
236         DBG("sender %s path %s", sender, path);
237
238         if (handover_agent_path != NULL)
239                 return -EEXIST;
240
241         handover_agent_sender = g_strdup(sender);
242         handover_agent_path = g_strdup(path);
243
244         handover_agent_watch = g_dbus_add_disconnect_watch(connection, sender,
245                                         handover_agent_disconnect, NULL, NULL);
246
247         return 0;
248 }
249
250 int __near_agent_handover_unregister(const char *sender, const char *path)
251 {
252         DBG("sender %s path %s", sender, path);
253
254         if (handover_agent_path == NULL)
255                 return -ESRCH;
256
257         if (handover_agent_watch > 0)
258                 g_dbus_remove_watch(connection, handover_agent_watch);
259
260         handover_agent_free();
261
262         return 0;
263 }
264
265 int __near_agent_init(void)
266 {
267         DBG("");
268
269         connection = near_dbus_get_connection();
270         if (connection == NULL)
271                 return -1;
272
273         ndef_app_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
274                                                 g_free, ndef_agent_free);
275
276         return 0;
277 }
278
279 void __near_agent_cleanup(void)
280 {
281         DBG("");
282
283         g_hash_table_destroy(ndef_app_hash);
284         ndef_app_hash = NULL;
285
286         handover_agent_free();
287
288         dbus_connection_unref(connection);
289 }