Tizen 2.0 Release
[framework/web/wrt-commons.git] / modules / event / src / event_delivery_detail.cpp
1 /*
2  * Copyright (c) 2011 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  * @file        wrt_event_delivery_detail.cpp
18  * @author      Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
19  * @version     1.0
20  * @brief       This file is the implementation file of event delivery EFL detail class
21  */
22 #include <dpl/event/event_delivery_detail.h>
23 #include <dpl/event/event_delivery_injector.h>
24 #include <dpl/framework_appcore.h>
25 #include <dpl/framework_vconf.h>
26 #include <dpl/scoped_array.h>
27 #include <dpl/assert.h>
28 #include <dpl/log/log.h>
29 #include <heynoti.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <fcntl.h>
33 #include <fstream>
34 #include <string>
35 #include <cstdio>
36
37 namespace // anonymous
38 {
39 const char *GENERIC_NOTI_ROOT_PATH = "/tmp/noti/generic";
40 } // namespace anonymous
41
42 namespace DPL
43 {
44 namespace Event
45 {
46
47 const char *EventDeliverySystemDetail::NOTI_EVENT_ID_GENERIC_0 = "GenericEvent0_";
48 const char *EventDeliverySystemDetail::NOTI_EVENT_ID_GENERIC_1 = "GenericEvent1_";
49 const char *EventDeliverySystemDetail::NOTI_EVENT_ID_GENERIC_2 = "GenericEvent2_";
50 const char *EventDeliverySystemDetail::NOTI_EVENT_ID_GENERIC_3 = "GenericEvent3_";
51 const char *EventDeliverySystemDetail::NOTI_EVENT_ID_GENERIC_4 = "GenericEvent4_";
52
53 // Global noti signal names
54 const char *GlobalNotiHibernationEnterSignal = "HIBERNATION_ENTER";
55 const char *GlobalNotiHibernationLeaveSignal = "HIBERNATION_LEAVE";
56
57 EventDeliverySystemDetail::EventDeliverySystemDetail()
58 {
59     // Open noti subsystem
60     LogInfo("Initializing core_util_noti subsystem...");
61
62     m_notiHandle = heynoti_init();
63     Assert(m_notiHandle != -1);
64
65     // Assume that there is ECORE environment running, attach noti library to it
66     LogPedantic("Attaching core_util_noti subsystem to ECORE...");
67
68     int ret = heynoti_attach_handler(m_notiHandle);
69     Assert(ret != -1);
70
71     (void)ret;
72
73     LogInfo("core_util_noti subsystem successfuly initialized.");
74 }
75
76 EventDeliverySystemDetail::~EventDeliverySystemDetail()
77 {
78     // All signal handlers should be deattached
79     Assert(m_notiSignalList.empty());
80     Assert(m_settingSignalList.empty());
81     Assert(m_globalNotiSignalList.empty());
82
83     // Detach noti library from ECORE environment
84     LogPedantic("Detaching core_util_noti subsystem from ECORE...");
85
86     int ret = heynoti_detach_handler(m_notiHandle);
87     Assert(ret != -1);
88
89     (void)ret;
90
91     // Close noti sybsystem
92     LogInfo("Deinitializing core_util_noti subsystem...");
93
94     Assert(m_notiHandle != -1);
95     heynoti_close(m_notiHandle);
96
97     LogInfo("core_util_noti subsystem successfuly deinitialized.");
98 }
99
100 std::string EventDeliverySystemDetail::ReadFile(const std::string &fileName) const
101 {
102     LogPedantic("Reading event file: " << fileName << "...");
103
104     std::ifstream fileStream(fileName.c_str(), std::ios::binary);
105
106     if (fileStream.fail())
107         return std::string("");
108
109     fileStream.seekg (0, std::ios::end);
110     std::streamoff length = fileStream.tellg();
111     fileStream.seekg (0, std::ios::beg);
112
113     ScopedArray<char> buffer(new char[length]);
114     fileStream.read(buffer.Get(), static_cast<size_t>(length));
115
116     if (fileStream.fail())
117         return std::string();
118
119     LogPedantic("Successfuly read: " << fileName << ".");
120
121     return std::string(buffer.Get(), buffer.Get() + length);
122 }
123
124 void EventDeliverySystemDetail::OnNotiGlobalSignal(void *notiData)
125 {
126     Assert(notiData);
127     NotiSignal *notiSignal = static_cast<NotiSignal *>(notiData);
128     notiSignal->GetReceiver()->OnNotiSignal(notiSignal);
129 }
130
131 void EventDeliverySystemDetail::OnSettingSignal(keynode_t *keyNode, void *userParam)
132 {
133     SettingSignal *settingSignal = static_cast<SettingSignal *>(userParam);
134     (void)settingSignal;
135
136     LogPedantic("Got setting signal for key: " << settingSignal->GetKey());
137
138     std::string key = vconf_keynode_get_name(keyNode);
139
140     if (key == VCONFKEY_SETAPPL_STATE_DATA_ROAMING_BOOL)
141     {
142         int value = vconf_keynode_get_bool(keyNode);
143         EventMessages::RoamingChanged message(value > 0);
144         EventDeliverySystemInjector::Instance().Publish(message);
145     }
146     else if (key == VCONFKEY_TELEPHONY_SVC_ROAM)
147     {
148         int result = 0;
149         if(vconf_get_int(VCONFKEY_TELEPHONY_SVC_ROAM, &result) != 0)
150         {
151             LogPedantic("Cannot get current roaming status");
152             return;
153         }
154         else
155         {
156             bool homeNetwork = (result != VCONFKEY_TELEPHONY_SVC_ROAM_ON);
157             EventMessages::NetworkTypeChanged message1(homeNetwork);
158             EventDeliverySystemInjector::Instance().Publish(message1);
159         }
160     }
161     else
162     {
163         LogPedantic("Unexpected setting signal key: " << key << "!");
164         return;
165     }
166 }
167
168 void EventDeliverySystemDetail::OnGlobalNotiSignal(void *globalNotiData)
169 {
170     GlobalNotiSignal *globalNotiSignal = static_cast<GlobalNotiSignal *>(globalNotiData);
171
172     LogPedantic("Got global noti signal for key: " << globalNotiSignal->GetKey());
173
174     std::string key = globalNotiSignal->GetKey();
175
176     if (key == GlobalNotiHibernationEnterSignal)
177     {
178         // We need to disconnect from VCONF
179         for (SettingSignalList::iterator iterator = globalNotiSignal->GetReceiver()->m_settingSignalList.begin();
180              iterator != globalNotiSignal->GetReceiver()->m_settingSignalList.end(); ++iterator)
181         {
182             // Unegister from VCONF signals
183             int ret = vconf_ignore_key_changed(iterator->GetKey().c_str(), OnSettingSignal);
184
185             if (ret == -1)
186                 LogPedantic("Failed to unlisten setting: " << key << ", errno = " << errno << ".");
187         }
188
189         // Publish
190         EventMessages::HibernationEnter message;
191         EventDeliverySystemInjector::Instance().Publish(message);
192     }
193     else if (key == GlobalNotiHibernationLeaveSignal)
194     {
195         // We need to reconnect to VCONF
196         for (SettingSignalList::iterator iterator = globalNotiSignal->GetReceiver()->m_settingSignalList.begin();
197              iterator != globalNotiSignal->GetReceiver()->m_settingSignalList.end(); ++iterator)
198         {
199             // Register for VCONF signals
200             int ret = vconf_notify_key_changed(iterator->GetKey().c_str(), OnSettingSignal, &*iterator);
201
202             if (ret == -1)
203                 LogPedantic("Failed to listen setting: key = " << key << ", errno = " << errno << ".");
204         }
205
206         // Publish
207         EventMessages::HibernationLeave message;
208         EventDeliverySystemInjector::Instance().Publish(message);
209     }
210     else
211     {
212         LogPedantic("Unexpected global noti signal key: " << key << "!");
213         return;
214     }
215 }
216
217 void EventDeliverySystemDetail::OnNotiSignal(NotiSignal *notiSignal)
218 {
219     LogPedantic("Got core_util_noti signal.");
220
221     if (notiSignal->GetEventName().substr(0, strlen(NOTI_EVENT_ID_GENERIC_0)) == NOTI_EVENT_ID_GENERIC_0)
222     {
223         LogPedantic("GeneticEvent0 message signal.");
224
225         EventDeliverySystemInjector::Instance().PublishMetaType(notiSignal->GetGcid(), ReadFile(GetGenericNotiFilePath(notiSignal->GetEventName())));
226     }
227     else if (notiSignal->GetEventName().substr(0, strlen(NOTI_EVENT_ID_GENERIC_1)) == NOTI_EVENT_ID_GENERIC_1)
228     {
229         LogPedantic("GeneticEvent1 message signal.");
230
231         EventDeliverySystemInjector::Instance().PublishMetaType(notiSignal->GetGcid(), ReadFile(GetGenericNotiFilePath(notiSignal->GetEventName())));
232     }
233     else if (notiSignal->GetEventName().substr(0, strlen(NOTI_EVENT_ID_GENERIC_2)) == NOTI_EVENT_ID_GENERIC_2)
234     {
235         LogPedantic("GeneticEvent2 message signal.");
236
237         EventDeliverySystemInjector::Instance().PublishMetaType(notiSignal->GetGcid(), ReadFile(GetGenericNotiFilePath(notiSignal->GetEventName())));
238     }
239     else if (notiSignal->GetEventName().substr(0, strlen(NOTI_EVENT_ID_GENERIC_3)) == NOTI_EVENT_ID_GENERIC_3)
240     {
241         LogPedantic("GeneticEvent3 message signal.");
242
243         EventDeliverySystemInjector::Instance().PublishMetaType(notiSignal->GetGcid(), ReadFile(GetGenericNotiFilePath(notiSignal->GetEventName())));
244     }
245     else if (notiSignal->GetEventName().substr(0, strlen(NOTI_EVENT_ID_GENERIC_4)) == NOTI_EVENT_ID_GENERIC_4)
246     {
247         LogPedantic("GeneticEvent4 message signal.");
248
249         EventDeliverySystemInjector::Instance().PublishMetaType(notiSignal->GetGcid(), ReadFile(GetGenericNotiFilePath(notiSignal->GetEventName())));
250     }
251 }
252
253 void EventDeliverySystemDetail::RegisterFileNotiCallback(const char *gcid, const std::string &eventName)
254 {
255     LogPedantic("Registering core_util_noti callback: gcid = " << (gcid ? gcid : "<NULL>") << ", eventName = " << eventName << ".");
256     Assert(m_notiHandle != -1);
257
258     // Check if already registered for signal
259     NotiSignalList::const_iterator iterator;
260
261     for (iterator = m_notiSignalList.begin(); iterator != m_notiSignalList.end(); ++iterator)
262     {
263         if (iterator->GetEventName() == eventName)
264             return;
265     }
266
267     // Make real noti path
268     std::string filePath = GetGenericNotiFilePath(eventName);
269
270     LogPedantic("Listening file: " << filePath << ".");
271
272     // New noti signal
273     m_notiSignalList.push_back(NotiSignal(this, gcid, eventName));
274     NotiSignal *notiSignal = &m_notiSignalList.back();
275
276     // Register for noti signals
277     int ret = heynoti_subscribe_file(m_notiHandle, filePath.c_str(), OnNotiGlobalSignal, notiSignal, IN_CLOSE_WRITE);
278
279     if (ret == -1)
280     {
281         LogPedantic("Failed to listen file: " << filePath << ".");
282         return;
283     }
284
285     LogPedantic("Successfuly registered listening file: " << filePath << ".");
286 }
287
288 void EventDeliverySystemDetail::UnregisterFileNotiCallback(const std::string &eventName)
289 {
290     LogPedantic("Unegistering core_util_noti callback: eventName = " << eventName << ".");
291
292     Assert(m_notiHandle != -1);
293
294     NotiSignalList::iterator iterator;
295
296     for (iterator = m_notiSignalList.begin(); iterator != m_notiSignalList.end(); ++iterator)
297     {
298         if (iterator->GetEventName() == eventName)
299             break;
300     }
301
302     if (iterator == m_notiSignalList.end())
303         return;
304
305     // Remove registered slot
306     m_notiSignalList.erase(iterator);
307
308     // Make real noti path
309     std::string filePath = GetGenericNotiFilePath(eventName);
310
311     LogPedantic("Unlistening file: " << filePath << ".");
312
313     // Register for noti signals
314     int ret = heynoti_unsubscribe_file(m_notiHandle, filePath.c_str(), OnNotiGlobalSignal);
315
316     if (ret == -1)
317     {
318         LogPedantic("Failed to unlisten file: " << filePath << ".");
319         return;
320     }
321 }
322
323 void EventDeliverySystemDetail::RegisterSettingCallback(const std::string &key)
324 {
325     LogPedantic("Registering setting: key = " << key << ".");
326
327     // Check if already registered for signal
328     SettingSignalList::const_iterator iterator;
329
330     for (iterator = m_settingSignalList.begin(); iterator != m_settingSignalList.end(); ++iterator)
331     {
332         if (iterator->GetKey() == key)
333             return;
334     }
335
336     // New noti signal
337     m_settingSignalList.push_back(SettingSignal(this, key));
338     SettingSignal *settingSignal = &m_settingSignalList.back();
339
340     // Register for setting signals
341     int ret = vconf_notify_key_changed(key.c_str(), OnSettingSignal, settingSignal);
342
343     if (ret == -1)
344     {
345         LogPedantic("Failed to listen setting: key = " << key << ", errno = " << errno << ".");
346         return;
347     }
348
349     LogPedantic("Successfuly registered setting: key = " << key << ".");
350 }
351
352 void EventDeliverySystemDetail::UnregisterSettingCallback(const std::string &key)
353 {
354     LogPedantic("Unegistering setting: key = " << key << ".");
355
356     SettingSignalList::iterator iterator;
357
358     for (iterator = m_settingSignalList.begin(); iterator != m_settingSignalList.end(); ++iterator)
359     {
360         if (iterator->GetKey() == key)
361             break;
362     }
363
364     if (iterator == m_settingSignalList.end())
365         return;
366
367     // Remove registered slot
368     m_settingSignalList.erase(iterator);
369
370     // Register for noti signals
371     int ret = vconf_ignore_key_changed(key.c_str(), OnSettingSignal);
372
373     if (ret == -1)
374     {
375         LogPedantic("Failed to unlisten setting: " << key << ", errno = " << errno << ".");
376         return;
377     }
378 }
379
380 void EventDeliverySystemDetail::RegisterGlobalNotiCallback(const std::string &key)
381 {
382     LogPedantic("Registering global noti: key = " << key << ".");
383
384     // Check if already registered for signal
385     GlobalNotiSignalList::const_iterator iterator;
386
387     for (iterator = m_globalNotiSignalList.begin(); iterator != m_globalNotiSignalList.end(); ++iterator)
388     {
389         if (iterator->GetKey() == key)
390             return;
391     }
392
393     // New noti signal
394     m_globalNotiSignalList.push_back(GlobalNotiSignal(this, key));
395     GlobalNotiSignal *globalNotiSignal = &m_globalNotiSignalList.back();
396
397     // Register for global noti signals
398     int ret = heynoti_subscribe(m_notiHandle, key.c_str(), OnGlobalNotiSignal, globalNotiSignal);
399
400     if (ret == -1)
401     {
402         LogPedantic("Failed to listen global noti: key = " << key << ", errno = " << errno << ".");
403         return;
404     }
405
406     LogPedantic("Successfuly registered global noti: key = " << key << ".");
407 }
408
409 void EventDeliverySystemDetail::UnregisterGlobalNotiCallback(const std::string &key)
410 {
411     LogPedantic("Unegistering global noti: key = " << key << ".");
412
413     GlobalNotiSignalList::iterator iterator;
414
415     for (iterator = m_globalNotiSignalList.begin(); iterator != m_globalNotiSignalList.end(); ++iterator)
416     {
417         if (iterator->GetKey() == key)
418             break;
419     }
420
421     if (iterator == m_globalNotiSignalList.end())
422         return;
423
424     // Remove registered slot
425     m_globalNotiSignalList.erase(iterator);
426
427     // Register for noti signals
428     int ret = heynoti_unsubscribe(m_notiHandle, key.c_str(), OnGlobalNotiSignal);
429
430     if (ret == -1)
431     {
432         LogPedantic("Failed to unlisten global noti: " << key << ", errno = " << errno << ".");
433         return;
434     }
435 }
436
437 void EventDeliverySystemDetail::SignalGenericNoti(const std::string &eventName, const std::string &contents) const
438 {
439     LogPedantic("Signaling core_util_noti with: eventName = " << eventName << ", buffer = " << contents << ".");
440
441     Assert(m_notiHandle != -1);
442
443     // Make real noto path
444     std::string filePath = GetGenericNotiFilePath(eventName);
445
446     LogPedantic("Signaling file: " << filePath << ".");
447
448     // Emit noti signal with user data
449     int fd = open(filePath.c_str(), O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR);
450
451     if (fd == -1)
452     {
453         LogPedantic("Failed to signal file: " << filePath << ".");
454         return;
455     }
456
457     // Write contents of signal to file
458     std::string::size_type written = 0;
459
460     while (written < contents.size())
461     {
462         int done = TEMP_FAILURE_RETRY(write(fd, static_cast<const void *>(&contents[written]), contents.size() - written));
463
464         if (done <= 0)
465         {
466             LogPedantic("File stream broken: " << filePath << ".");
467             break;
468         }
469
470         written += done;
471     }
472
473     // Close signal file
474     int ret = close(fd);
475
476     if (ret == -1)
477     {
478         LogPedantic("Failed to close signal file: " << filePath << ".");
479         return;
480     }
481 }
482
483 std::string EventDeliverySystemDetail::GetGenericNotiFilePath(const std::string &eventName) const
484 {
485     // Make sure that the path exists
486     if (access(GENERIC_NOTI_ROOT_PATH, F_OK) == -1)
487     {
488         LogPedantic("No root path found. Creating root path...");
489
490         // Create path
491         if (mkdir(GENERIC_NOTI_ROOT_PATH, 0755) == -1)
492         {
493             LogPedantic("Failed to create root path!");
494             return std::string("~") + eventName;
495         }
496
497         LogPedantic("Root path created.");
498     }
499
500     return std::string(GENERIC_NOTI_ROOT_PATH) + "/" + eventName;
501 }
502
503 void EventDeliverySystemDetail::Listen(const EventMessages::RoamingChanged &event)
504 {
505     LogPedantic("RoamingChanged message listen.");
506
507     (void)event;
508     RegisterSettingCallback(VCONFKEY_SETAPPL_STATE_DATA_ROAMING_BOOL);
509 }
510
511 void EventDeliverySystemDetail::Listen(const EventMessages::NetworkTypeChanged &event)
512 {
513     LogPedantic("NetworkTypeChanged message listen.");
514
515     (void)event;
516     RegisterSettingCallback(VCONFKEY_TELEPHONY_SVC_ROAM);
517 }
518
519 void EventDeliverySystemDetail::Listen(const EventMessages::HibernationEnter &event)
520 {
521     LogPedantic("HibernationEnter message listen.");
522
523     (void)event;
524     RegisterGlobalNotiCallback(GlobalNotiHibernationEnterSignal);
525 }
526
527 void EventDeliverySystemDetail::Listen(const EventMessages::HibernationLeave &event)
528 {
529     LogPedantic("HibernationLeave message listen.");
530
531     (void)event;
532     RegisterGlobalNotiCallback(GlobalNotiHibernationLeaveSignal);
533 }
534
535 void EventDeliverySystemDetail::Unlisten(const EventMessages::RoamingChanged &event)
536 {
537     LogPedantic("RoamingChanged message unlisten.");
538
539     (void)event;
540     UnregisterSettingCallback(VCONFKEY_SETAPPL_STATE_DATA_ROAMING_BOOL);
541 }
542
543 void EventDeliverySystemDetail::Unlisten(const EventMessages::NetworkTypeChanged &event)
544 {
545     LogPedantic("NetworkTypeChanged message unlisten.");
546
547     (void)event;
548     UnregisterSettingCallback(VCONFKEY_TELEPHONY_SVC_ROAM);
549 }
550
551 void EventDeliverySystemDetail::Unlisten(const EventMessages::HibernationEnter &event)
552 {
553     LogPedantic("HibernationEnter message unlisten.");
554
555     (void)event;
556     UnregisterGlobalNotiCallback(GlobalNotiHibernationEnterSignal);
557 }
558
559 void EventDeliverySystemDetail::Unlisten(const EventMessages::HibernationLeave &event)
560 {
561     LogPedantic("HibernationLeave message unlisten.");
562
563     (void)event;
564     UnregisterGlobalNotiCallback(GlobalNotiHibernationLeaveSignal);
565 }
566
567 }
568 } // namespace DPL