tizen 2.3.1 release
[external/buxton.git] / src / shared / protocol.c
1 /*
2  * This file is part of buxton.
3  *
4  * Copyright (C) 2013 Intel Corporation
5  *
6  * buxton is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as
8  * published by the Free Software Foundation; either version 2.1
9  * of the License, or (at your option) any later version.
10  */
11
12 #ifdef HAVE_CONFIG_H
13         #include "config.h"
14 #endif
15
16 #include <assert.h>
17 #include <errno.h>
18 #include <poll.h>
19 #include <pthread.h>
20 #include <stdlib.h>
21 #include <sys/time.h>
22
23 #include "buxtonclient.h"
24 #include "buxtonkey.h"
25 #include "buxtonresponse.h"
26 #include "buxtonstring.h"
27 #include "hashmap.h"
28 #include "log.h"
29 #include "protocol.h"
30 #include "util.h"
31
32 #define TIMEOUT 3
33
34 static pthread_mutex_t callback_guard = PTHREAD_MUTEX_INITIALIZER;
35 static Hashmap *callbacks = NULL;
36 static Hashmap *notify_callbacks = NULL;
37 static volatile uint32_t _msgid = 0;
38
39 struct notify_value {
40         void *data;
41         BuxtonCallback cb;
42         struct timeval tv;
43         BuxtonControlMessage type;
44         _BuxtonKey *key;
45 };
46
47 static uint32_t get_msgid(void)
48 {
49         return __sync_fetch_and_add(&_msgid, 1);
50 }
51
52 bool setup_callbacks(void)
53 {
54         bool r = false;
55         int s;
56
57         s = pthread_mutex_lock(&callback_guard);
58         if (s) {
59                 return false;
60         }
61
62         if (callbacks && notify_callbacks) {
63                 goto unlock;
64         }
65
66         callbacks = hashmap_new(trivial_hash_func, trivial_compare_func);
67         if (!callbacks) {
68                 goto unlock;
69         }
70
71         notify_callbacks = hashmap_new(trivial_hash_func, trivial_compare_func);
72         if (!notify_callbacks) {
73                 hashmap_free(callbacks);
74                 goto unlock;
75         }
76
77         r = true;
78
79 unlock:
80         s = pthread_mutex_unlock(&callback_guard);
81         if (s) {
82                 return false;
83         }
84
85         return r;
86 }
87
88 void cleanup_callbacks(void)
89 {
90         struct notify_value *nvi;
91         Iterator it;
92 #if UINTPTR_MAX == 0xffffffffffffffff
93         uint64_t hkey;
94 #else
95         uint32_t hkey;
96 #endif
97
98         (void)pthread_mutex_lock(&callback_guard);
99
100         if (callbacks) {
101                 HASHMAP_FOREACH_KEY(nvi, hkey, callbacks, it) {
102                         (void)hashmap_remove(callbacks, (void *)hkey);
103                         key_free(nvi->key);
104                         free(nvi);
105                 }
106                 hashmap_free(callbacks);
107         }
108         callbacks = NULL;
109
110         if (notify_callbacks) {
111                 HASHMAP_FOREACH_KEY(nvi, hkey, notify_callbacks, it) {
112                         (void)hashmap_remove(notify_callbacks, (void *)hkey);
113                         key_free(nvi->key);
114                         free(nvi);
115                 }
116                 hashmap_free(notify_callbacks);
117         }
118         notify_callbacks = NULL;
119
120         (void)pthread_mutex_unlock(&callback_guard);
121 }
122
123 void run_callback(BuxtonCallback callback, void *data, size_t count,
124                   BuxtonData *list, BuxtonControlMessage type, _BuxtonKey *key)
125 {
126         BuxtonArray *array = NULL;
127         _BuxtonResponse response;
128
129         if (!callback) {
130                 goto out;
131         }
132
133         array = buxton_array_new();
134         if (!array) {
135                 goto out;
136         }
137
138         for (int i = 0; i < count; i++)
139                 if (!buxton_array_add(array, &list[i])) {
140                         goto out;
141                 }
142
143         response.type = type;
144         response.data = array;
145         response.key = key;
146         callback(&response, data);
147
148 out:
149         buxton_array_free(&array, NULL);
150 }
151
152 void reap_callbacks(void)
153 {
154         struct notify_value *nvi;
155         struct timeval tv;
156         Iterator it;
157 #if UINTPTR_MAX == 0xffffffffffffffff
158         uint64_t hkey;
159 #else
160         uint32_t hkey;
161 #endif
162
163         (void)gettimeofday(&tv, NULL);
164
165         /* remove timed out callbacks */
166         HASHMAP_FOREACH_KEY(nvi, hkey, callbacks, it) {
167                 if (tv.tv_sec - nvi->tv.tv_sec > TIMEOUT) {
168                         (void)hashmap_remove(callbacks, (void *)hkey);
169                         key_free(nvi->key);
170                         free(nvi);
171                 }
172         }
173 }
174
175 bool send_message(_BuxtonClient *client, uint8_t *send, size_t send_len,
176                   BuxtonCallback callback, void *data, uint32_t msgid,
177                   BuxtonControlMessage type, _BuxtonKey *key)
178 {
179         struct notify_value *nv;
180         _BuxtonKey *k = NULL;
181         int s;
182         bool r = false;
183
184         nv = malloc0(sizeof(struct notify_value));
185         if (!nv) {
186                 goto fail;
187         }
188
189         if (key) {
190                 k = malloc0(sizeof(_BuxtonKey));
191                 if (!k) {
192                         goto fail;
193                 }
194                 if (!buxton_key_copy(key, k)) {
195                         goto fail;
196                 }
197         }
198
199         (void)gettimeofday(&nv->tv, NULL);
200         nv->cb = callback;
201         nv->data = data;
202         nv->type = type;
203         nv->key = k;
204
205         s = pthread_mutex_lock(&callback_guard);
206         if (s) {
207                 goto fail;
208         }
209
210         reap_callbacks();
211
212 #if UINTPTR_MAX == 0xffffffffffffffff
213         s = hashmap_put(callbacks, (void *)((uint64_t)msgid), nv);
214 #else
215         s = hashmap_put(callbacks, (void *)msgid, nv);
216 #endif
217         (void)pthread_mutex_unlock(&callback_guard);
218
219         if (s < 1) {
220                 buxton_debug("Error adding callback for msgid: %llu\n", msgid);
221                 goto fail;
222         }
223
224         /* Now write it off */
225         if (!_write(client->fd, send, send_len)) {
226                 buxton_debug("Write failed for msgid: %llu\n", msgid);
227                 r = false;
228         } else {
229                 r = true;
230         }
231
232         return r;
233
234 fail:
235         free(nv);
236         key_free(k);
237         return false;
238 }
239
240 void handle_callback_response(BuxtonControlMessage msg, uint32_t msgid,
241                               BuxtonData *list, size_t count)
242 {
243         struct notify_value *nv;
244
245         /* use notification callbacks for notification messages */
246         if (msg == BUXTON_CONTROL_CHANGED) {
247 #if UINTPTR_MAX == 0xffffffffffffffff
248                 nv = hashmap_get(notify_callbacks, (void *)((uint64_t)msgid));
249 #else
250                 nv = hashmap_get(notify_callbacks, (void *)msgid);
251 #endif
252                 if (!nv) {
253                         return;
254                 }
255
256                 run_callback((BuxtonCallback)(nv->cb), nv->data, count, list,
257                              BUXTON_CONTROL_CHANGED, nv->key);
258                 return;
259         }
260
261 #if UINTPTR_MAX == 0xffffffffffffffff
262         nv = hashmap_remove(callbacks, (void *)((uint64_t)msgid));
263 #else
264         nv = hashmap_remove(callbacks, (void *)msgid);
265 #endif
266         if (!nv) {
267                 return;
268         }
269
270         if (nv->type == BUXTON_CONTROL_NOTIFY) {
271                 if (list[0].type == INT32 &&
272                     list[0].store.d_int32 == 0) {
273 #if UINTPTR_MAX == 0xffffffffffffffff
274                         if (hashmap_put(notify_callbacks, (void *)((uint64_t)msgid), nv)
275 #else
276                         if (hashmap_put(notify_callbacks, (void *)msgid, nv)
277 #endif
278                             >= 0) {
279                                 return;
280                         }
281                 }
282         } else if (nv->type == BUXTON_CONTROL_UNNOTIFY) {
283                 if (list[0].type == INT32 &&
284                     list[0].store.d_int32 == 0) {
285                         (void)hashmap_remove(notify_callbacks,
286 #if UINTPTR_MAX == 0xffffffffffffffff
287                                              (void *)((uint64_t)list[2].store.d_uint32));
288 #else
289                                              (void *)list[2].store.d_uint32);
290 #endif
291
292                         return;
293                 }
294         }
295
296         /* callback should be run on notfiy or unnotify failure */
297         /* and on any other server message we are waiting for */
298         run_callback((BuxtonCallback)(nv->cb), nv->data, count, list, nv->type,
299                      nv->key);
300
301         key_free(nv->key);
302         free(nv);
303 }
304
305 ssize_t buxton_wire_handle_response(_BuxtonClient *client)
306 {
307         ssize_t l;
308         _cleanup_free_ uint8_t *response = NULL;
309         BuxtonData *r_list = NULL;
310         BuxtonControlMessage r_msg = BUXTON_CONTROL_MIN;
311         ssize_t count = 0;
312         size_t offset = 0;
313         size_t size = BUXTON_MESSAGE_HEADER_LENGTH;
314         uint32_t r_msgid;
315         int s;
316         ssize_t handled = 0;
317
318         s = pthread_mutex_lock(&callback_guard);
319         if (s) {
320                 return 0;
321         }
322         reap_callbacks();
323         (void)pthread_mutex_unlock(&callback_guard);
324
325         response = malloc0(BUXTON_MESSAGE_HEADER_LENGTH);
326         if (!response) {
327                 return 0;
328         }
329
330         do {
331                 l = read(client->fd, response + offset, size - offset);
332                 if (l <= 0) {
333                         return handled;
334                 }
335                 offset += (size_t)l;
336                 if (offset < BUXTON_MESSAGE_HEADER_LENGTH) {
337                         continue;
338                 }
339                 if (size == BUXTON_MESSAGE_HEADER_LENGTH) {
340                         size = buxton_get_message_size(response, offset);
341                         if (size == 0 || size > BUXTON_MESSAGE_MAX_LENGTH) {
342                                 return -1;
343                         }
344                 }
345                 if (size != BUXTON_MESSAGE_HEADER_LENGTH) {
346                         response = realloc(response, size);
347                         if (!response) {
348                                 return -1;
349                         }
350                 }
351                 if (size != offset) {
352                         continue;
353                 }
354
355                 count = buxton_deserialize_message(response, &r_msg, size, &r_msgid, &r_list);
356                 if (count < 0) {
357                         goto next;
358                 }
359
360                 if (!(r_msg == BUXTON_CONTROL_STATUS && r_list && r_list[0].type == INT32)
361                     && !(r_msg == BUXTON_CONTROL_CHANGED)) {
362                         handled++;
363                         buxton_log("Critical error: Invalid response\n");
364                         goto next;
365                 }
366
367                 s = pthread_mutex_lock(&callback_guard);
368                 if (s) {
369                         goto next;
370                 }
371
372                 handle_callback_response(r_msg, r_msgid, r_list, (size_t)count);
373
374                 (void)pthread_mutex_unlock(&callback_guard);
375                 handled++;
376
377         next:
378                 if (r_list) {
379                         for (int i = 0; i < count; i++) {
380                                 if (r_list[i].type == STRING) {
381                                         free(r_list[i].store.d_string.value);
382                                 }
383                         }
384                         free(r_list);
385                 }
386
387                 /* reset for next possible message */
388                 size = BUXTON_MESSAGE_HEADER_LENGTH;
389                 offset = 0;
390         } while (true);
391 }
392
393 int buxton_wire_get_response(_BuxtonClient *client)
394 {
395         struct pollfd pfd[1];
396         int r;
397         ssize_t processed;
398
399         pfd[0].fd = client->fd;
400         pfd[0].events = POLLIN;
401         pfd[0].revents = 0;
402         r = poll(pfd, 1, 5000);
403
404         if (r == 0) {
405                 return -ETIME;
406         } else if (r < 0) {
407                 return -errno;
408         }
409
410         processed = buxton_wire_handle_response(client);
411
412         return (int)processed;
413 }
414
415 bool buxton_wire_set_value(_BuxtonClient *client, _BuxtonKey *key, void *value,
416                            BuxtonCallback callback, void *data)
417 {
418         _cleanup_free_ uint8_t *send = NULL;
419         bool ret = false;
420         size_t send_len = 0;
421         BuxtonArray *list = NULL;
422         BuxtonData d_layer;
423         BuxtonData d_group;
424         BuxtonData d_name;
425         BuxtonData d_value;
426         uint32_t msgid = get_msgid();
427
428         buxton_string_to_data(&key->layer, &d_layer);
429         buxton_string_to_data(&key->group, &d_group);
430         buxton_string_to_data(&key->name, &d_name);
431         d_value.type = key->type;
432         switch (key->type) {
433         case STRING:
434                 d_value.store.d_string.value = (char *)value;
435                 d_value.store.d_string.length = (uint32_t)strlen((char *)value) + 1;
436                 break;
437         case INT32:
438                 d_value.store.d_int32 = *(int32_t *)value;
439                 break;
440         case INT64:
441                 d_value.store.d_int64 = *(int64_t *)value;
442                 break;
443         case UINT32:
444                 d_value.store.d_uint32 = *(uint32_t *)value;
445                 break;
446         case UINT64:
447                 d_value.store.d_uint64 = *(uint64_t *)value;
448                 break;
449         case FLOAT:
450                 d_value.store.d_float = *(float *)value;
451                 break;
452         case DOUBLE:
453                 memcpy(&d_value.store.d_double, value, sizeof(double));
454                 break;
455         case BOOLEAN:
456                 d_value.store.d_boolean = *(bool *)value;
457                 break;
458         default:
459                 break;
460         }
461
462         list = buxton_array_new();
463         if (!buxton_array_add(list, &d_layer)) {
464                 buxton_log("Failed to add layer to set_value array\n");
465                 goto end;
466         }
467         if (!buxton_array_add(list, &d_group)) {
468                 buxton_log("Failed to add group to set_value array\n");
469                 goto end;
470         }
471         if (!buxton_array_add(list, &d_name)) {
472                 buxton_log("Failed to add name to set_value array\n");
473                 goto end;
474         }
475         if (!buxton_array_add(list, &d_value)) {
476                 buxton_log("Failed to add value to set_value array\n");
477                 goto end;
478         }
479
480         send_len = buxton_serialize_message(&send, BUXTON_CONTROL_SET, msgid, list);
481
482         if (send_len == 0) {
483                 goto end;
484         }
485
486
487         if (!send_message(client, send, send_len, callback, data, msgid,
488                           BUXTON_CONTROL_SET, key)) {
489                 goto end;
490         }
491
492         ret = true;
493
494 end:
495         buxton_array_free(&list, NULL);
496         return ret;
497 }
498
499 bool buxton_wire_set_label(_BuxtonClient *client,
500                            _BuxtonKey *key, BuxtonString *value,
501                            BuxtonCallback callback, void *data)
502 {
503         assert(client);
504         assert(key);
505         assert(value);
506
507         _cleanup_free_ uint8_t *send = NULL;
508         bool ret = false;
509         size_t send_len = 0;
510         BuxtonArray *list = NULL;
511         BuxtonData d_layer;
512         BuxtonData d_group;
513         BuxtonData d_name;
514         BuxtonData d_value;
515         uint32_t msgid = get_msgid();
516
517         buxton_string_to_data(&key->layer, &d_layer);
518         buxton_string_to_data(&key->group, &d_group);
519         buxton_string_to_data(value, &d_value);
520
521         list = buxton_array_new();
522         if (!buxton_array_add(list, &d_layer)) {
523                 buxton_log("Failed to add layer to set_label array\n");
524                 goto end;
525         }
526         if (!buxton_array_add(list, &d_group)) {
527                 buxton_log("Failed to add group to set_label array\n");
528                 goto end;
529         }
530         if (key->name.value) {
531                 buxton_string_to_data(&key->name, &d_name);
532                 if (!buxton_array_add(list, &d_name)) {
533                         buxton_log("Failed to add name to set_label array\n");
534                         goto end;
535                 }
536         }
537         if (!buxton_array_add(list, &d_value)) {
538                 buxton_log("Failed to add value to set_label array\n");
539                 goto end;
540         }
541
542         send_len = buxton_serialize_message(&send, BUXTON_CONTROL_SET_LABEL, msgid, list);
543
544         if (send_len == 0) {
545                 goto end;
546         }
547
548         if (!send_message(client, send, send_len, callback, data, msgid,
549                           BUXTON_CONTROL_SET_LABEL, key)) {
550                 goto end;
551         }
552
553         ret = true;
554
555 end:
556         buxton_array_free(&list, NULL);
557         return ret;
558 }
559
560 bool buxton_wire_create_group(_BuxtonClient *client, _BuxtonKey *key,
561                               BuxtonCallback callback, void *data)
562 {
563         assert(client);
564         assert(key);
565
566         _cleanup_free_ uint8_t *send = NULL;
567         bool ret = false;
568         size_t send_len = 0;
569         BuxtonArray *list = NULL;
570         BuxtonData d_layer;
571         BuxtonData d_group;
572         uint32_t msgid = get_msgid();
573
574         buxton_string_to_data(&key->layer, &d_layer);
575         buxton_string_to_data(&key->group, &d_group);
576
577         list = buxton_array_new();
578         if (!buxton_array_add(list, &d_layer)) {
579                 buxton_log("Failed to add layer to create_group array\n");
580                 goto end;
581         }
582         if (!buxton_array_add(list, &d_group)) {
583                 buxton_log("Failed to add group to create_group array\n");
584                 goto end;
585         }
586
587         send_len = buxton_serialize_message(&send, BUXTON_CONTROL_CREATE_GROUP, msgid, list);
588
589         if (send_len == 0) {
590                 goto end;
591         }
592
593         if (!send_message(client, send, send_len, callback, data, msgid,
594                           BUXTON_CONTROL_CREATE_GROUP, key)) {
595                 goto end;
596         }
597
598         ret = true;
599
600 end:
601         buxton_array_free(&list, NULL);
602         return ret;
603 }
604
605 bool buxton_wire_remove_group(_BuxtonClient *client, _BuxtonKey *key,
606                               BuxtonCallback callback, void *data)
607 {
608         assert(client);
609         assert(key);
610
611         _cleanup_free_ uint8_t *send = NULL;
612         bool ret = false;
613         size_t send_len = 0;
614         BuxtonArray *list = NULL;
615         BuxtonData d_layer;
616         BuxtonData d_group;
617         uint32_t msgid = get_msgid();
618
619         buxton_string_to_data(&key->layer, &d_layer);
620         buxton_string_to_data(&key->group, &d_group);
621
622         list = buxton_array_new();
623         if (!buxton_array_add(list, &d_layer)) {
624                 buxton_log("Failed to add layer to remove_group array\n");
625                 goto end;
626         }
627         if (!buxton_array_add(list, &d_group)) {
628                 buxton_log("Failed to add group to remove_group array\n");
629                 goto end;
630         }
631
632         send_len = buxton_serialize_message(&send, BUXTON_CONTROL_REMOVE_GROUP, msgid, list);
633
634         if (send_len == 0) {
635                 goto end;
636         }
637
638         if (!send_message(client, send, send_len, callback, data, msgid,
639                           BUXTON_CONTROL_REMOVE_GROUP, key)) {
640                 goto end;
641         }
642
643         ret = true;
644
645 end:
646         buxton_array_free(&list, NULL);
647         return ret;
648 }
649
650 bool buxton_wire_get_value(_BuxtonClient *client, _BuxtonKey *key,
651                            BuxtonCallback callback, void *data)
652 {
653         bool ret = false;
654         size_t send_len = 0;
655         _cleanup_free_ uint8_t *send = NULL;
656         BuxtonArray *list = NULL;
657         BuxtonData d_layer;
658         BuxtonData d_group;
659         BuxtonData d_name;
660         BuxtonData d_type;
661         uint32_t msgid = get_msgid();
662
663         buxton_string_to_data(&key->group, &d_group);
664         buxton_string_to_data(&key->name, &d_name);
665         d_type.type = UINT32;
666         d_type.store.d_int32 = key->type;
667
668         list = buxton_array_new();
669         if (key->layer.value) {
670                 buxton_string_to_data(&key->layer, &d_layer);
671                 if (!buxton_array_add(list, &d_layer)) {
672                         buxton_log("Unable to prepare get_value message\n");
673                         goto end;
674                 }
675         }
676         if (!buxton_array_add(list, &d_group)) {
677                 buxton_log("Failed to add group to set_value array\n");
678                 goto end;
679         }
680         if (!buxton_array_add(list, &d_name)) {
681                 buxton_log("Failed to add name to set_value array\n");
682                 goto end;
683         }
684         if (!buxton_array_add(list, &d_type)) {
685                 buxton_log("Failed to add type to set_value array\n");
686                 goto end;
687         }
688
689         send_len = buxton_serialize_message(&send, BUXTON_CONTROL_GET, msgid, list);
690
691         if (send_len == 0) {
692                 goto end;
693         }
694
695         if (!send_message(client, send, send_len, callback, data, msgid,
696                           BUXTON_CONTROL_GET, key)) {
697                 goto end;
698         }
699
700         ret = true;
701
702 end:
703         buxton_array_free(&list, NULL);
704         return ret;
705 }
706
707 bool buxton_wire_unset_value(_BuxtonClient *client,
708                              _BuxtonKey *key,
709                              BuxtonCallback callback,
710                              void *data)
711 {
712         assert(client);
713         assert(key);
714
715         _cleanup_free_ uint8_t *send = NULL;
716         size_t send_len = 0;
717         BuxtonArray *list = NULL;
718         BuxtonData d_group;
719         BuxtonData d_name;
720         BuxtonData d_layer;
721         BuxtonData d_type;
722         bool ret = false;
723         uint32_t msgid = get_msgid();
724
725         buxton_string_to_data(&key->group, &d_group);
726         buxton_string_to_data(&key->name, &d_name);
727         buxton_string_to_data(&key->layer, &d_layer);
728         d_type.type = UINT32;
729         d_type.store.d_int32 = key->type;
730
731         list = buxton_array_new();
732         if (!buxton_array_add(list, &d_layer)) {
733                 buxton_log("Failed to add layer to set_value array\n");
734                 goto end;
735         }
736         if (!buxton_array_add(list, &d_group)) {
737                 buxton_log("Failed to add group to set_value array\n");
738                 goto end;
739         }
740         if (!buxton_array_add(list, &d_name)) {
741                 buxton_log("Failed to add name to set_value array\n");
742                 goto end;
743         }
744         if (!buxton_array_add(list, &d_type)) {
745                 buxton_log("Failed to add type to set_value array\n");
746                 goto end;
747         }
748
749         send_len = buxton_serialize_message(&send, BUXTON_CONTROL_UNSET,
750                                             msgid, list);
751
752         if (send_len == 0) {
753                 goto end;
754         }
755
756         if (!send_message(client, send, send_len, callback, data, msgid,
757                           BUXTON_CONTROL_UNSET, key)) {
758                 goto end;
759         }
760
761         ret = true;
762
763 end:
764         buxton_array_free(&list, NULL);
765         return ret;
766 }
767
768 bool buxton_wire_list_keys(_BuxtonClient *client,
769                            BuxtonString *layer,
770                            BuxtonCallback callback,
771                            void *data)
772 {
773         assert(client);
774         assert(layer);
775
776         _cleanup_free_ uint8_t *send = NULL;
777         size_t send_len = 0;
778         BuxtonArray *list = NULL;
779         BuxtonData d_layer;
780         bool ret = false;
781         uint32_t msgid = get_msgid();
782
783         buxton_string_to_data(layer, &d_layer);
784
785         list = buxton_array_new();
786         if (!buxton_array_add(list, &d_layer)) {
787                 buxton_log("Unable to add layer to list_keys array\n");
788                 goto end;
789         }
790
791         send_len = buxton_serialize_message(&send, BUXTON_CONTROL_LIST, msgid,
792                                             list);
793
794         if (send_len == 0) {
795                 goto end;
796         }
797
798         if (!send_message(client, send, send_len, callback, data, msgid,
799                           BUXTON_CONTROL_LIST, NULL)) {
800                 goto end;
801         }
802
803         ret = true;
804
805 end:
806         buxton_array_free(&list, NULL);
807
808         return ret;
809 }
810
811 bool buxton_wire_register_notification(_BuxtonClient *client,
812                                        _BuxtonKey *key,
813                                        BuxtonCallback callback,
814                                        void *data)
815 {
816         assert(client);
817         assert(key);
818
819         _cleanup_free_ uint8_t *send = NULL;
820         size_t send_len = 0;
821         BuxtonArray *list = NULL;
822         BuxtonData d_group;
823         BuxtonData d_name;
824         BuxtonData d_type;
825         bool ret = false;
826         uint32_t msgid = get_msgid();
827
828         buxton_string_to_data(&key->group, &d_group);
829         buxton_string_to_data(&key->name, &d_name);
830         d_type.type = UINT32;
831         d_type.store.d_int32 = key->type;
832
833         list = buxton_array_new();
834         if (!buxton_array_add(list, &d_group)) {
835                 buxton_log("Failed to add group to set_value array\n");
836                 goto end;
837         }
838         if (!buxton_array_add(list, &d_name)) {
839                 buxton_log("Failed to add name to set_value array\n");
840                 goto end;
841         }
842         if (!buxton_array_add(list, &d_type)) {
843                 buxton_log("Failed to add type to set_value array\n");
844                 goto end;
845         }
846
847         send_len = buxton_serialize_message(&send, BUXTON_CONTROL_NOTIFY, msgid,
848                                             list);
849
850         if (send_len == 0) {
851                 goto end;
852         }
853
854         if (!send_message(client, send, send_len, callback, data, msgid,
855                           BUXTON_CONTROL_NOTIFY, key)) {
856                 goto end;
857         }
858
859         ret = true;
860
861 end:
862         buxton_array_free(&list, NULL);
863         return ret;
864 }
865
866 bool buxton_wire_unregister_notification(_BuxtonClient *client,
867                                          _BuxtonKey *key,
868                                          BuxtonCallback callback,
869                                          void *data)
870 {
871         assert(client);
872         assert(key);
873
874         _cleanup_free_ uint8_t *send = NULL;
875         size_t send_len = 0;
876         BuxtonArray *list = NULL;
877         BuxtonData d_group;
878         BuxtonData d_name;
879         BuxtonData d_type;
880         bool ret = false;
881         uint32_t msgid = get_msgid();
882
883         buxton_string_to_data(&key->group, &d_group);
884         buxton_string_to_data(&key->name, &d_name);
885         d_type.type = UINT32;
886         d_type.store.d_int32 = key->type;
887
888         list = buxton_array_new();
889         if (!buxton_array_add(list, &d_group)) {
890                 buxton_log("Failed to add group to set_value array\n");
891                 goto end;
892         }
893         if (!buxton_array_add(list, &d_name)) {
894                 buxton_log("Failed to add name to set_value array\n");
895                 goto end;
896         }
897         if (!buxton_array_add(list, &d_type)) {
898                 buxton_log("Failed to add type to set_value array\n");
899                 goto end;
900         }
901
902         send_len = buxton_serialize_message(&send, BUXTON_CONTROL_UNNOTIFY,
903                                             msgid, list);
904
905         if (send_len == 0) {
906                 goto end;
907         }
908
909         if (!send_message(client, send, send_len, callback, data, msgid,
910                           BUXTON_CONTROL_UNNOTIFY, key)) {
911                 goto end;
912         }
913
914         ret = true;
915
916 end:
917         buxton_array_free(&list, NULL);
918         return ret;
919 }
920
921 void include_protocol(void)
922 {
923         ;
924 }
925
926 /*
927  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
928  *
929  * Local variables:
930  * c-basic-offset: 8
931  * tab-width: 8
932  * indent-tabs-mode: t
933  * End:
934  *
935  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
936  * :indentSize=8:tabSize=8:noTabs=false:
937  */