b5220e042d7eb67cc71b6974e05cbf9d46138c71
[platform/core/uifw/autofill.git] / client / autofill.c
1 /*
2  * Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <dlog.h>
21 #include <unistd.h>
22 #include <Eina.h>
23 #include <autofill.h>
24 #include <rpc-port.h>
25 #include "autofill_private.h"
26 #include "autofill_proxy.h"
27
28 #define AUTOFILL_DAEMON_APP_ID "org.tizen.autofilld"
29
30 #ifdef LOG_TAG
31 #undef LOG_TAG
32 #endif
33 #define LOG_TAG "AUTOFILL"
34
35 static int _autofill_context_count = 0;
36
37 //LCOV_EXCL_START
38 static bool fill_response_item_cb(rpc_port_autofill_response_item_h response_items, void *user_data)
39 {
40     char *id = NULL;
41     char *presentation_text = NULL;
42     char *value = NULL;
43     autofill_fill_response_group_h res_group = (autofill_fill_response_group_h)user_data;
44
45     if (!res_group)
46         return true;
47
48     rpc_port_autofill_response_item_get_id(response_items, &id);
49     rpc_port_autofill_response_item_get_presentation_text(response_items, &presentation_text);
50     rpc_port_autofill_response_item_get_value(response_items, &value);
51
52     LOGD("id : %s, presentation text : %s, value : %s", id, presentation_text, value);
53
54     autofill_fill_response_item_h ritem;
55
56     autofill_fill_response_item_create(&ritem);
57     autofill_fill_response_item_set_id(ritem, id);
58     autofill_fill_response_item_set_presentation_text(ritem, presentation_text);
59     autofill_fill_response_item_set_value(ritem, value);
60
61     autofill_fill_response_group_add_item(res_group, ritem);
62
63     if (id)
64         free(id);
65
66     if (presentation_text)
67         free(presentation_text);
68
69     if (value)
70         free(value);
71
72     autofill_fill_response_item_destroy(ritem);
73
74     return true;
75 }
76
77 static bool fill_response_group_cb(rpc_port_autofill_response_group_h response_groups, void *user_data)
78 {
79     autofill_fill_response_h rh = (autofill_fill_response_h)user_data;
80     autofill_fill_response_group_h res_group;
81
82     autofill_fill_response_group_create(&res_group);
83
84     rpc_port_autofill_response_group_foreach_response_items(response_groups, fill_response_item_cb, res_group);
85
86     autofill_fill_response_add_group(rh, res_group);
87
88     autofill_fill_response_group_destroy(res_group);
89
90     return true;
91 }
92
93 static void __fill_response_recv_cb(void *user_data, rpc_port_autofill_fill_response_h response_h)
94 {
95     char *app_id = NULL;
96     char *view_id = NULL;
97     autofill_h ah = user_data;
98     autofill_fill_response_h rh;
99
100     autofill_fill_response_create(&rh);
101
102     rpc_port_autofill_fill_response_get_app_id(response_h, &app_id);
103     rpc_port_autofill_fill_response_get_view_id(response_h, &view_id);
104
105     LOGD("app id : %s, view id : %s", app_id, view_id);
106
107     if (app_id) {
108         autofill_fill_response_set_app_id(rh, app_id);
109         free(app_id);
110     }
111
112     if (view_id) {
113         autofill_fill_response_set_view_id(rh, view_id);
114         free(view_id);
115     }
116
117     rpc_port_autofill_fill_response_foreach_response_groups(response_h, fill_response_group_cb, rh);
118
119     if (ah->autofill_fill_response_received_cb)
120         ah->autofill_fill_response_received_cb(ah, rh, ah->autofill_fill_response_data);
121
122     autofill_fill_response_destroy(rh);
123 }
124
125 static void __auth_info_recv_cb(void *user_data, rpc_port_autofill_auth_info_h auth_info_h)
126 {
127     autofill_auth_info_h aih;
128     autofill_h ah = user_data;
129
130     autofill_auth_info_create(&aih);
131
132     bool autofill_data_present = false;
133     bool authentication_needed = false;
134     char *app_id = NULL;
135     char *view_id = NULL;
136     char *service_name = NULL;
137     char *service_logo_image_path = NULL;
138     char *service_message = NULL;
139
140     rpc_port_autofill_auth_info_get_app_id(auth_info_h, &app_id);
141     rpc_port_autofill_auth_info_get_view_id(auth_info_h, &view_id);
142     rpc_port_autofill_auth_info_get_exist_autofill_data(auth_info_h, &autofill_data_present);
143     rpc_port_autofill_auth_info_get_need_authentication(auth_info_h, &authentication_needed);
144     rpc_port_autofill_auth_info_get_service_name(auth_info_h, &service_name);
145     rpc_port_autofill_auth_info_get_service_logo_image_path(auth_info_h, &service_logo_image_path);
146     rpc_port_autofill_auth_info_get_service_message(auth_info_h, &service_message);
147
148     LOGD("app id : %s, view id : %s, service name : %s", app_id, view_id, service_name);
149
150     autofill_auth_info_set_app_id(aih, app_id);
151     autofill_auth_info_set_view_id(aih, view_id);
152     autofill_auth_info_set_autofill_data_present(aih, autofill_data_present);
153     autofill_auth_info_set_authentication_needed(aih, authentication_needed);
154     autofill_auth_info_set_service_name(aih, service_name);
155     autofill_auth_info_set_service_logo_image_path(aih, service_logo_image_path);
156     autofill_auth_info_set_service_message(aih, service_message);
157
158     if (app_id)
159         free(app_id);
160
161     if (view_id)
162         free(view_id);
163
164     if (service_name)
165         free(service_name);
166
167     if (service_logo_image_path)
168         free(service_logo_image_path);
169
170     if (service_message)
171         free(service_message);
172
173     if (ah) {
174         if (ah->autofill_auth_info_received_cb)
175             ah->autofill_auth_info_received_cb(ah, aih, ah->autofill_fill_response_data);
176     }
177     else {
178         LOGW("no user data");
179     }
180
181     autofill_auth_info_destroy(aih);
182 }
183 //LCOV_EXCL_STOP
184
185 static void __on_connected(rpc_port_proxy_AutofillAppPort_h h, void *user_data)
186 {
187     autofill_h ah = user_data;
188     if (!ah) {
189         LOGW("no user data");
190         return;
191     }
192
193     ah->connected = true;
194
195     LOGI("connected");
196     rpc_port_AutofillAppPort_autofill_fill_response_received_cb_h fill_response_received_cb = rpc_port_AutofillAppPort_autofill_fill_response_received_cb_create(__fill_response_recv_cb, false, ah);
197     rpc_port_AutofillAppPort_autofill_auth_info_received_cb_h auth_info_received_cb = rpc_port_AutofillAppPort_autofill_auth_info_received_cb_create(__auth_info_recv_cb, false, ah);
198
199     int r = rpc_port_proxy_AutofillAppPort_invoke_Register(h, ah->context_id, auth_info_received_cb, fill_response_received_cb);
200     if (r != 0)
201         LOGW("[ERROR] Failed to invoke Register");
202
203     if (ah->connection_callback)
204         ah->connection_callback(ah, AUTOFILL_CONNECTION_STATUS_CONNECTED, ah->connection_userdata);
205 }
206
207 //LCOV_EXCL_START
208 static void __on_disconnected(rpc_port_proxy_AutofillAppPort_h h, void *user_data)
209 {
210     LOGD("disconnected");
211
212     autofill_h ah = user_data;
213     if (ah) {
214         ah->connected = false;
215
216         if (ah && ah->connection_callback)
217             ah->connection_callback(ah, AUTOFILL_CONNECTION_STATUS_DISCONNECTED, ah->connection_userdata);
218
219         ah->rpc_h = NULL;
220     }
221 }
222
223 static void __on_rejected(rpc_port_proxy_AutofillAppPort_h h, void *user_data)
224 {
225     LOGD("rejected");
226
227     autofill_h ah = user_data;
228
229     if (ah && ah->connection_callback)
230         ah->connection_callback(ah, AUTOFILL_CONNECTION_STATUS_REJECTED, ah->connection_userdata);
231 }
232 //LCOV_EXCL_STOP
233
234 EXPORT_API int autofill_create(autofill_h *ah)
235 {
236     int ret;
237
238     if (!ah)
239         return AUTOFILL_ERROR_INVALID_PARAMETER;
240
241     rpc_port_proxy_AutofillAppPort_callback_s rpc_callback = {
242         .connected = __on_connected,
243         .disconnected = __on_disconnected,
244         .rejected = __on_rejected
245     };
246
247     struct autofill_s *as = (autofill_h)calloc(1, sizeof(struct autofill_s));
248     if (!as)
249         return AUTOFILL_ERROR_OUT_OF_MEMORY;
250
251     ret = rpc_port_proxy_AutofillAppPort_create(AUTOFILL_DAEMON_APP_ID, &rpc_callback, as, &as->rpc_h);
252     if (ret != RPC_PORT_ERROR_NONE) {
253         LOGW("[ERROR] Failed to create rpc port. err = %d", ret);
254         free(as);
255         return AUTOFILL_ERROR_OUT_OF_MEMORY;
256     }
257
258     as->context_id = _autofill_context_count++;
259     *ah = as;
260
261     return AUTOFILL_ERROR_NONE;
262 }
263
264 EXPORT_API int autofill_destroy(autofill_h ah)
265 {
266     if (!ah)
267         return AUTOFILL_ERROR_INVALID_PARAMETER;
268
269     ah->connection_callback = NULL;
270     ah->autofill_fill_response_received_cb = NULL;
271     ah->autofill_auth_info_received_cb = NULL;
272
273     if (ah->rpc_h) {
274         rpc_port_proxy_AutofillAppPort_destroy(ah->rpc_h);
275         ah->rpc_h = NULL;
276     }
277
278     return AUTOFILL_ERROR_NONE;
279 }
280
281 EXPORT_API int autofill_connect(autofill_h ah, autofill_connection_status_changed_cb callback, void *user_data)
282 {
283     LOGD("autofill connect. handle : %p", ah);
284
285     int ret;
286
287     if (!ah || !callback) {
288         LOGW("[ERROR] Invalid parameter");
289         return AUTOFILL_ERROR_INVALID_PARAMETER;
290     }
291
292     if (!ah->rpc_h) {
293         return AUTOFILL_ERROR_OPERATION_FAILED;
294     }
295
296     ah->connection_callback = callback;
297     ah->connection_userdata = user_data;
298
299     ret = rpc_port_proxy_AutofillAppPort_connect(ah->rpc_h);
300     if (ret != RPC_PORT_ERROR_NONE) {
301         switch(ret) {
302             case RPC_PORT_ERROR_IO_ERROR:
303                 LOGW("[ERROR] Failed to connect rpc port. I/O Error");
304                 break;
305             case RPC_PORT_ERROR_OUT_OF_MEMORY:
306                 LOGW("[ERROR] Failed to connect rpc port. Out of memory");
307                 break;
308             case RPC_PORT_ERROR_INVALID_PARAMETER:
309                 LOGW("[ERROR] Failed to connect rpc port. Invalid parameter");
310                 break;
311             case RPC_PORT_ERROR_PERMISSION_DENIED:
312                 LOGW("[ERROR] Failed to connect rpc port. Permission denied");
313                 break;
314             default:
315                 LOGW("[ERROR] Failed to connect rpc port. errcode = %d", ret);
316                 break;
317         }
318         return AUTOFILL_ERROR_OPERATION_FAILED;
319     }
320     else {
321         return AUTOFILL_ERROR_NONE;
322     }
323 }
324
325 EXPORT_API int autofill_commit(autofill_h ah, autofill_save_view_info_h vi)
326 {
327     rpc_port_autofill_save_view_info_h vih;
328     char *id = NULL;
329     char *label = NULL;
330     char *value = NULL;
331     autofill_hint_e autofill_hint;
332     bool sensitive_data;
333
334     if (!ah || !vi) {
335         LOGW("[ERROR] Invalid parameter");
336         return AUTOFILL_ERROR_INVALID_PARAMETER;
337     }
338
339     if (!ah->rpc_h) {
340         return AUTOFILL_ERROR_OPERATION_FAILED;
341     }
342
343     if (!ah->connected) {
344         LOGW("[ERROR] Not connected");
345         return AUTOFILL_ERROR_OPERATION_FAILED;
346     }
347
348     rpc_port_autofill_save_view_info_create(&vih);
349     rpc_port_autofill_save_view_info_set_view_id(vih, vi->view_id);
350
351     Eina_List *l;
352     autofill_save_item_h it;
353     EINA_LIST_FOREACH(vi->autofill_save_item_list, l, it)
354     {
355         autofill_save_item_get_id(it, &id);
356         autofill_save_item_get_label(it, &label);
357         autofill_save_item_get_value(it, &value);
358         autofill_save_item_get_autofill_hint(it, &autofill_hint);
359         autofill_save_item_get_sensitive_data(it, &sensitive_data);
360
361         LOGD("it : %p, id : %s, label : %s, hint : %d, sensitive : %d", it, id, label, autofill_hint, sensitive_data);
362
363         rpc_port_autofill_save_item_h aih;
364         rpc_port_autofill_save_item_create(&aih);
365         rpc_port_autofill_save_item_set_id(aih, id);
366         rpc_port_autofill_save_item_set_label(aih, label);
367         rpc_port_autofill_save_item_set_value(aih, value);
368         rpc_port_autofill_save_item_set_autofill_hint(aih, (int)autofill_hint);
369         rpc_port_autofill_save_item_set_is_sensitive_data(aih, sensitive_data);
370         rpc_port_autofill_save_view_info_add_items(vih, aih);
371
372         if (id) {
373             free(id);
374             id = NULL;
375         }
376
377         if (label) {
378             free(label);
379             label = NULL;
380         }
381
382         if (value) {
383             free(value);
384             value = NULL;
385         }
386
387         rpc_port_autofill_save_item_destroy(aih);
388     }
389
390     LOGD("app id : %s, view id : %s", vi->app_id, vi->view_id);
391
392     int ret = rpc_port_proxy_AutofillAppPort_invoke_commit(ah->rpc_h, ah->context_id, vih);
393
394     rpc_port_autofill_save_view_info_destroy(vih);
395
396     if (ret != RPC_PORT_ERROR_NONE) {
397         LOGW("[ERROR] Failed to commit. rpc err = %d", ret);
398         return AUTOFILL_ERROR_OPERATION_FAILED;
399     }
400     else {
401         return AUTOFILL_ERROR_NONE;
402     }
403 }