Line data Source code
1 : /**
2 : * @file
3 : *
4 : * @brief Implementation of notification functions as defined in
5 : * kdbnotification.h
6 : *
7 : * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
8 : *
9 : */
10 :
11 : #include <kdbassert.h>
12 : #include <kdbease.h>
13 : #include <kdbhelper.h>
14 : #include <kdbinvoke.h>
15 : #include <kdbioprivate.h>
16 : #include <kdblogger.h>
17 : #include <kdbnotification.h>
18 : #include <kdbnotificationinternal.h>
19 : #include <kdbplugin.h>
20 : #include <kdbprivate.h> // for elektraGetPluginFunction, elektraPluginFindGlobal, kdb->globalPlugins and plugin->config
21 :
22 : #include <stdio.h>
23 :
24 8 : static void pluginsOpenNotification (KDB * kdb, ElektraNotificationCallback callback, ElektraNotificationCallbackContext * context)
25 : {
26 8 : ELEKTRA_NOT_NULL (kdb);
27 8 : ELEKTRA_NOT_NULL (callback);
28 :
29 8 : KeySet * parameters = ksNew (2, keyNew ("/callback", KEY_FUNC, callback, KEY_END),
30 : keyNew ("/context", KEY_BINARY, KEY_SIZE, sizeof (context), KEY_VALUE, &context, KEY_END), KS_END);
31 :
32 : // iterate over global plugins
33 152 : for (int positionIndex = 0; positionIndex < NR_GLOBAL_POSITIONS; positionIndex++)
34 : {
35 576 : for (int subPositionIndex = 0; subPositionIndex < NR_GLOBAL_SUBPOSITIONS; subPositionIndex++)
36 : {
37 576 : Plugin * plugin = kdb->globalPlugins[positionIndex][subPositionIndex];
38 576 : if (!plugin)
39 : {
40 496 : continue;
41 : }
42 :
43 :
44 80 : elektraDeferredCall (plugin, "openNotification", parameters);
45 : }
46 : }
47 :
48 8 : ksDel (parameters);
49 8 : }
50 :
51 8 : static void pluginsCloseNotification (KDB * kdb)
52 : {
53 8 : ELEKTRA_NOT_NULL (kdb);
54 :
55 : // iterate over global plugins
56 144 : for (int positionIndex = 0; positionIndex < NR_GLOBAL_POSITIONS; positionIndex++)
57 : {
58 576 : for (int subPositionIndex = 0; subPositionIndex < NR_GLOBAL_SUBPOSITIONS; subPositionIndex++)
59 : {
60 576 : Plugin * plugin = kdb->globalPlugins[positionIndex][subPositionIndex];
61 576 : if (!plugin)
62 : {
63 496 : continue;
64 : }
65 :
66 80 : elektraDeferredCall (plugin, "closeNotification", NULL);
67 : }
68 : }
69 8 : }
70 :
71 : /**
72 : * @see kdbnotificationinternal.h ::ElektraNotificationKdbUpdate
73 : */
74 0 : static void elektraNotificationKdbUpdate (KDB * kdb, Key * changedKey)
75 : {
76 0 : KeySet * ks = ksNew (0, KS_END);
77 0 : kdbGet (kdb, ks, changedKey);
78 0 : ksDel (ks);
79 0 : }
80 :
81 10 : int elektraNotificationOpen (KDB * kdb)
82 : {
83 : // Make sure kdb is not null
84 10 : if (!kdb)
85 : {
86 : ELEKTRA_LOG_WARNING ("kdb was not set");
87 : return 0;
88 : }
89 :
90 10 : Plugin * notificationPlugin = elektraPluginFindGlobal (kdb, "internalnotification");
91 : // Allow open only once
92 10 : if (notificationPlugin)
93 : {
94 : ELEKTRA_LOG_WARNING ("elektraNotificationOpen already called for kdb");
95 : return 0;
96 : }
97 :
98 : // Create context for notification callback
99 8 : ElektraNotificationCallbackContext * context = elektraMalloc (sizeof (*context));
100 8 : if (context == NULL)
101 : {
102 : return 0;
103 : }
104 8 : context->kdb = kdb;
105 8 : context->kdbUpdate = &elektraNotificationKdbUpdate;
106 :
107 8 : Key * parent = keyNew ("", KEY_END);
108 8 : KeySet * contract = ksNew (2, keyNew ("system/elektra/ensure/plugins/global/internalnotification", KEY_VALUE, "mounted", KEY_END),
109 : keyNew ("system/elektra/ensure/plugins/global/internalnotification/config/context", KEY_BINARY, KEY_SIZE,
110 : sizeof (context), KEY_VALUE, &context, KEY_END),
111 : KS_END);
112 8 : if (kdbEnsure (kdb, contract, parent) != 0)
113 : {
114 0 : keyDel (parent);
115 : ELEKTRA_LOG_WARNING ("kdbEnsure failed");
116 0 : return 0;
117 : }
118 :
119 8 : notificationPlugin = elektraPluginFindGlobal (kdb, "internalnotification");
120 8 : if (notificationPlugin == NULL)
121 : {
122 : ELEKTRA_LOG_WARNING ("kdbEnsure failed");
123 : return 0;
124 : }
125 :
126 8 : context->notificationPlugin = notificationPlugin;
127 :
128 : // Get notification callback from notification plugin
129 8 : size_t func = elektraPluginGetFunction (notificationPlugin, "notificationCallback");
130 8 : if (!func)
131 : {
132 : // remove notification plugin again
133 0 : contract = ksNew (1, keyNew ("system/elektra/ensure/plugins/global/internalnotification", KEY_VALUE, "unmounted", KEY_END),
134 : KS_END);
135 0 : if (kdbEnsure (kdb, contract, parent) != 0)
136 : {
137 : ELEKTRA_LOG_WARNING ("kdbEnsure failed");
138 : }
139 0 : keyDel (parent);
140 0 : return 0;
141 : }
142 8 : ElektraNotificationCallback notificationCallback = (ElektraNotificationCallback) func;
143 :
144 8 : keyDel (parent);
145 :
146 : // Open notification for plugins
147 8 : pluginsOpenNotification (kdb, notificationCallback, context);
148 :
149 8 : return 1;
150 : }
151 :
152 10 : int elektraNotificationClose (KDB * kdb)
153 : {
154 : // Make sure kdb is not null
155 10 : if (!kdb)
156 : {
157 : ELEKTRA_LOG_WARNING ("kdb was not set");
158 : return 0;
159 : }
160 :
161 10 : Plugin * notificationPlugin = elektraPluginFindGlobal (kdb, "internalnotification");
162 : // Make sure open was called
163 10 : if (notificationPlugin == NULL)
164 : {
165 : ELEKTRA_LOG_WARNING ("elektraNotificationOpen not called before elektraPluginClose");
166 : return 0;
167 : }
168 :
169 8 : Key * contextKey = ksLookupByName (notificationPlugin->config, "user/context", 0);
170 8 : ElektraNotificationCallbackContext * context = *(ElektraNotificationCallbackContext **) keyValue (contextKey);
171 8 : elektraFree (context);
172 :
173 : // Unmount the plugin
174 8 : Key * parent = keyNew ("", KEY_END);
175 8 : KeySet * contract =
176 8 : ksNew (1, keyNew ("system/elektra/ensure/plugins/global/internalnotification", KEY_VALUE, "unmounted", KEY_END), KS_END);
177 8 : if (kdbEnsure (kdb, contract, parent) != 0)
178 : {
179 : ELEKTRA_LOG_WARNING ("kdbEnsure failed");
180 : }
181 8 : keyDel (parent);
182 :
183 : // Close notification for plugins
184 8 : pluginsCloseNotification (kdb);
185 :
186 8 : return 1;
187 : }
188 :
189 : /**
190 : * @internal
191 : * Get notification plugin from kdb.
192 : *
193 : * @param kdb KDB handle
194 : * @return Notification plugin handle or NULL if not present
195 : */
196 8 : static Plugin * getNotificationPlugin (KDB * kdb)
197 : {
198 8 : ELEKTRA_NOT_NULL (kdb);
199 :
200 8 : Plugin * notificationPlugin = elektraPluginFindGlobal (kdb, "internalnotification");
201 8 : if (notificationPlugin)
202 : {
203 : return notificationPlugin;
204 : }
205 : else
206 : {
207 : ELEKTRA_LOG_WARNING (
208 : "notificationPlugin not set. use "
209 : "elektraNotificationOpen before calling other "
210 : "elektraNotification-functions");
211 4 : return NULL;
212 : }
213 : }
214 :
215 4 : ELEKTRA_NOTIFICATION_TYPE_DEFINITION (int, Int)
216 0 : ELEKTRA_NOTIFICATION_TYPE_DEFINITION (unsigned int, UnsignedInt)
217 0 : ELEKTRA_NOTIFICATION_TYPE_DEFINITION (long, Long)
218 0 : ELEKTRA_NOTIFICATION_TYPE_DEFINITION (unsigned long, UnsignedLong)
219 0 : ELEKTRA_NOTIFICATION_TYPE_DEFINITION (float, Float)
220 0 : ELEKTRA_NOTIFICATION_TYPE_DEFINITION (double, Double)
221 :
222 0 : ELEKTRA_NOTIFICATION_TYPE_DEFINITION (kdb_boolean_t, KdbBoolean)
223 0 : ELEKTRA_NOTIFICATION_TYPE_DEFINITION (kdb_char_t, KdbChar)
224 0 : ELEKTRA_NOTIFICATION_TYPE_DEFINITION (kdb_octet_t, KdbOctet)
225 0 : ELEKTRA_NOTIFICATION_TYPE_DEFINITION (kdb_short_t, KdbShort)
226 0 : ELEKTRA_NOTIFICATION_TYPE_DEFINITION (kdb_unsigned_short_t, KdbUnsignedShort)
227 0 : ELEKTRA_NOTIFICATION_TYPE_DEFINITION (kdb_long_t, KdbLong)
228 0 : ELEKTRA_NOTIFICATION_TYPE_DEFINITION (kdb_unsigned_long_t, KdbUnsignedLong)
229 0 : ELEKTRA_NOTIFICATION_TYPE_DEFINITION (kdb_long_long_t, KdbLongLong)
230 0 : ELEKTRA_NOTIFICATION_TYPE_DEFINITION (kdb_unsigned_long_long_t, KdbUnsignedLongLong)
231 0 : ELEKTRA_NOTIFICATION_TYPE_DEFINITION (kdb_float_t, KdbFloat)
232 0 : ELEKTRA_NOTIFICATION_TYPE_DEFINITION (kdb_double_t, KdbDouble)
233 0 : ELEKTRA_NOTIFICATION_TYPE_DEFINITION (kdb_long_double_t, KdbLongDouble)
234 :
235 4 : int elektraNotificationRegisterCallback (KDB * kdb, Key * key, ElektraNotificationChangeCallback callback, void * context)
236 : {
237 4 : if (!kdb || !key || !callback)
238 : {
239 : ELEKTRA_LOG_WARNING ("null pointer passed");
240 : return 0;
241 : }
242 :
243 : // Find notification plugin
244 4 : Plugin * notificationPlugin = getNotificationPlugin (kdb);
245 4 : if (!notificationPlugin)
246 : {
247 : return 0;
248 : }
249 :
250 : // Get register function from plugin
251 2 : size_t func = elektraPluginGetFunction (notificationPlugin, "registerCallback");
252 2 : if (!func)
253 : {
254 : return 0;
255 : }
256 :
257 : // Call register function
258 2 : ElektraNotificationPluginRegisterCallback registerFunc = (ElektraNotificationPluginRegisterCallback) func;
259 2 : return registerFunc (notificationPlugin, key, callback, context);
260 : }
261 :
262 0 : int elektraNotificationRegisterCallbackSameOrBelow (KDB * kdb, Key * key, ElektraNotificationChangeCallback callback, void * context)
263 : {
264 0 : if (!kdb || !key || !callback)
265 : {
266 : ELEKTRA_LOG_WARNING ("null pointer passed");
267 : return 0;
268 : }
269 :
270 : // Find notification plugin
271 0 : Plugin * notificationPlugin = getNotificationPlugin (kdb);
272 0 : if (!notificationPlugin)
273 : {
274 : return 0;
275 : }
276 :
277 : // Get register function from plugin
278 0 : size_t func = elektraPluginGetFunction (notificationPlugin, "registerCallbackSameOrBelow");
279 0 : if (!func)
280 : {
281 : return 0;
282 : }
283 :
284 : // Call register function
285 0 : ElektraNotificationPluginRegisterCallbackSameOrBelow registerFunc = (ElektraNotificationPluginRegisterCallbackSameOrBelow) func;
286 0 : return registerFunc (notificationPlugin, key, callback, context);
287 : }
288 :
289 0 : int elektraNotificationSetConversionErrorCallback (KDB * kdb, ElektraNotificationConversionErrorCallback callback, void * context)
290 : {
291 0 : if (!kdb || !callback)
292 : {
293 : ELEKTRA_LOG_WARNING ("null pointer passed");
294 : return 0;
295 : }
296 :
297 : // Find notification plugin
298 0 : Plugin * notificationPlugin = getNotificationPlugin (kdb);
299 0 : if (!notificationPlugin)
300 : {
301 : return 0;
302 : }
303 :
304 : // Get register function from plugin
305 0 : size_t func = elektraPluginGetFunction (notificationPlugin, "setConversionErrorCallback");
306 0 : if (!func)
307 : {
308 : return 0;
309 : }
310 :
311 : // Call register function
312 0 : ElektraNotificationSetConversionErrorCallback setCallbackFunc = (ElektraNotificationSetConversionErrorCallback) func;
313 0 : setCallbackFunc (notificationPlugin, callback, context);
314 0 : return 1;
315 : }
|