Tizen 2.0 Release
[framework/connectivity/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 append_ndef(DBusMessageIter *iter, void *user_data)
102 {
103         GList *records = user_data;
104
105         __near_ndef_append_records(iter, records);
106 }
107
108 static void ndef_agent_push_records(struct near_ndef_agent *agent,
109                                                         GList *records)
110 {
111         DBusMessageIter iter, dict;
112         DBusMessage *message;
113
114         DBG("");
115
116         if (agent->sender == NULL || agent->path == NULL)
117                 return;
118
119         DBG("Sending NDEF to %s %s", agent->path, agent->sender);
120
121         message = dbus_message_new_method_call(agent->sender, agent->path,
122                                         NFC_NDEF_AGENT_INTERFACE,
123                                         "GetNDEF");
124         if (message == NULL)
125                 return;
126
127         dbus_message_iter_init_append(message, &iter);
128
129         near_dbus_dict_open(&iter, &dict);
130         near_dbus_dict_append_array(&dict, "Records",
131                                 DBUS_TYPE_STRING, append_record_path, records);
132         near_dbus_dict_append_array(&dict, "NDEF",
133                                 DBUS_TYPE_BYTE, append_ndef, records);
134         near_dbus_dict_close(&iter, &dict);
135
136         DBG("sending...");
137
138         dbus_message_set_no_reply(message, TRUE);
139
140         g_dbus_send_message(connection, message);
141 }
142
143 void __near_agent_ndef_parse_records(GList *records)
144 {
145         GList *list;
146         struct near_ndef_record *record;
147         struct near_ndef_agent *agent;
148         char *type;
149
150         DBG("");
151
152         for (list = records, agent = NULL; list; list = list->next) {
153                 record = list->data;
154                 type  = __near_ndef_record_get_type(record);
155
156                 if (type == NULL)
157                         continue;
158
159                 DBG("Looking for type %s", type);
160
161                 agent = g_hash_table_lookup(ndef_app_hash, type);
162                 if (agent != NULL)
163                         break;
164         }
165
166         if (agent == NULL)
167                 return;
168
169         ndef_agent_push_records(agent, records);
170
171         return;
172 }
173
174 int __near_agent_ndef_register(const char *sender, const char *path,
175                                                 const char *record_type)
176 {
177         struct near_ndef_agent *agent;
178
179         DBG("%s registers path %s for %s", sender, path, record_type);
180
181         if (g_hash_table_lookup(ndef_app_hash, record_type) != NULL)
182                 return -EEXIST;
183
184         agent = g_try_malloc0(sizeof(struct near_ndef_agent));
185         if (agent == NULL)
186                 return -ENOMEM;
187
188         agent->sender = g_strdup(sender);
189         agent->path = g_strdup(path);
190         agent->record_type = g_strdup(record_type);
191         
192         if (agent->sender == NULL || agent->path == NULL ||
193             agent->record_type == NULL) {
194                 g_free(agent);
195                 return -ENOMEM;
196         }
197
198         agent->watch = g_dbus_add_disconnect_watch(connection, sender,
199                                                 ndef_agent_disconnect, agent, NULL);
200         g_hash_table_insert(ndef_app_hash, agent->record_type, agent);
201
202         return 0;
203 }
204
205 int __near_agent_ndef_unregister(const char *sender, const char *path,
206                                                 const char *record_type)
207 {
208         struct near_ndef_agent *agent;
209
210         DBG("sender %s path %s type %s", sender, path, record_type);
211
212         agent = g_hash_table_lookup(ndef_app_hash, record_type);
213         if (agent == NULL)
214                 return -EINVAL;
215
216         if (strcmp(agent->path, path) != 0 || strcmp(agent->sender, sender) != 0)
217                 return -EINVAL;
218
219         g_hash_table_remove(ndef_app_hash, record_type);
220
221         return 0;
222 }
223
224 static guint handover_agent_watch = 0;
225 static gchar *handover_agent_path = NULL;
226 static gchar *handover_agent_sender = NULL;
227
228 static void handover_agent_free(void)
229 {
230         if (handover_agent_watch > 0) {
231                 g_dbus_remove_watch(connection, handover_agent_watch);
232                 handover_agent_watch = 0;
233         }
234
235         g_free(handover_agent_sender);
236         handover_agent_sender = NULL;
237
238         g_free(handover_agent_path);
239         handover_agent_path = NULL;
240 }
241
242 static void handover_agent_disconnect(DBusConnection *conn, void *data)
243 {
244         DBG("data %p", data);
245
246         handover_agent_watch = 0;
247
248         handover_agent_free();
249 }
250
251 static void handover_agent_release(void)
252 {
253         DBusMessage *message;
254
255         if (handover_agent_watch == 0)
256                 return;
257
258         message = dbus_message_new_method_call(handover_agent_sender,
259                                                 handover_agent_path,
260                                                 "org.neard.HandoverAgent",
261                                                 "Release");
262         if (message != NULL)
263                 g_dbus_send_message(connection, message);
264
265         handover_agent_free();
266 }
267
268 int __near_agent_handover_register(const char *sender, const char *path)
269 {
270         DBG("sender %s path %s", sender, path);
271
272         if (handover_agent_path != NULL)
273                 return -EEXIST;
274
275         handover_agent_watch = g_dbus_add_disconnect_watch(connection, sender,
276                                         handover_agent_disconnect, NULL, NULL);
277         if (handover_agent_watch == 0)
278                 return -ENOMEM;
279
280         handover_agent_sender = g_strdup(sender);
281         handover_agent_path = g_strdup(path);
282
283         return 0;
284 }
285
286 int __near_agent_handover_unregister(const char *sender, const char *path)
287 {
288         DBG("sender %s path %s", sender, path);
289
290         if (handover_agent_path == NULL)
291                 return -ESRCH;
292
293         handover_agent_free();
294
295         return 0;
296 }
297
298 int __near_agent_init(void)
299 {
300         DBG("");
301
302         connection = near_dbus_get_connection();
303         if (connection == NULL)
304                 return -1;
305
306         ndef_app_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
307                                                 g_free, ndef_agent_free);
308
309         return 0;
310 }
311
312 void __near_agent_cleanup(void)
313 {
314         DBG("");
315
316         g_hash_table_destroy(ndef_app_hash);
317         ndef_app_hash = NULL;
318
319         handover_agent_release();
320
321         dbus_connection_unref(connection);
322 }