root/lash_compat/liblash/lash.c @ 6aa44e9ab9275f4a3cc5d34684109d1a78df39d0

Revision 6aa44e9ab9275f4a3cc5d34684109d1a78df39d0, 24.7 KB (checked in by Nedko Arnaudov <nedko@…>, 22 months ago)

dbus_ -> cdbus_ renames

  • Property mode set to 100644
Line 
1/* -*- Mode: C ; c-basic-offset: 2 -*- */
2/*
3 * LADI Session Handler (ladish)
4 *
5 * Copyright (C) 2009,2010,2011 Nedko Arnaudov <nedko@arnaudov.name>
6 *
7 **************************************************************************
8 * This file contains the liblash implementaiton
9 **************************************************************************
10 *
11 * LADI Session Handler is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * LADI Session Handler is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with LADI Session Handler. If not, see <http://www.gnu.org/licenses/>
23 * or write to the Free Software Foundation, Inc.,
24 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
25 */
26
27#include <arpa/inet.h>
28#include <sys/types.h>
29#include <sys/stat.h>
30#include <fcntl.h>
31#include <unistd.h>
32#include <errno.h>
33#include <dirent.h>
34
35#include "lash/lash.h"
36
37#define LADISH_DEBUG
38
39#include "../../common.h"
40#include "../../common/catdup.h"
41#include "../../common/dirhelpers.h"
42#include "../../common/file.h"
43#include "../../log.h"
44#include "../../dbus/helpers.h"
45#include "../../dbus/error.h"
46#include "../../dbus_constants.h"
47
48#define LASH_CONFIG_SUBDIR "/.ladish_lash_dict/"
49
50static cdbus_object_path g_object;
51extern const struct cdbus_interface_descriptor g_interface __attribute__((visibility("hidden")));
52
53struct _lash_client
54{
55  int flags;
56};
57
58static struct _lash_client g_client;
59
60struct _lash_event
61{
62  enum LASH_Event_Type type;
63  char * string;
64};
65
66static struct _lash_event g_event = {0, NULL};
67static bool g_quit = false;
68static bool g_busy = false;     /* whether the app is processing the event */
69
70struct _lash_config
71{
72  struct list_head siblings;
73  char * key;
74  size_t size;
75  void * value;
76};
77
78static LIST_HEAD(g_pending_configs);
79
80static void clean_pending_configs(void)
81{
82  struct _lash_config * config_ptr;
83
84  while (!list_empty(&g_pending_configs))
85  {
86    config_ptr = list_entry(g_pending_configs.next, struct _lash_config, siblings);
87    list_del(g_pending_configs.next);
88    lash_config_destroy(config_ptr);
89  }
90}
91
92static void save_config(const char * dir,  struct _lash_config * config_ptr)
93{
94  char * path;
95  int fd;
96        ssize_t written;
97
98  log_debug("saving dict key '%s'", config_ptr->key);
99
100  path = catdup3(dir, LASH_CONFIG_SUBDIR, config_ptr->key);
101  if (path == NULL)
102  {
103    goto exit;
104  }
105
106  fd = creat(path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
107
108        if (fd == -1)
109  {
110    log_error("error creating config file '%s' (%s)", path, strerror(errno));
111    goto free;
112        }
113
114        written = write(fd, config_ptr->value, config_ptr->size);
115        if (written == -1)
116  {
117    log_error("error writting config file '%s' (%s)", path, strerror(errno));
118    goto close;
119        }
120
121  if ((size_t)written < config_ptr->size)
122  {
123    log_error("error writting config file '%s' (%zd instead of %zu)", path, written, config_ptr->size);
124    goto close;
125  }
126
127  log_debug("saved dict key '%s'", config_ptr->key);
128
129close:
130  close(fd);
131free:
132  free(path);
133exit:
134  return;
135}
136
137static void save_pending_configs(const char * dir)
138{
139  struct _lash_config * config_ptr;
140
141  if (!ensure_dir_exist_varg(S_IRWXU | S_IRWXG | S_IRWXO, dir, LASH_CONFIG_SUBDIR, NULL))
142  {
143    log_error("ensure_dir_exist_varg() failed for %s%s", dir, LASH_CONFIG_SUBDIR);
144    clean_pending_configs();
145    return;
146  }
147
148  while (!list_empty(&g_pending_configs))
149  {
150    config_ptr = list_entry(g_pending_configs.next, struct _lash_config, siblings);
151    list_del(g_pending_configs.next);
152    save_config(dir, config_ptr);
153    lash_config_destroy(config_ptr);
154  }
155}
156
157static void load_configs(const char * appdir)
158{
159  char * dirpath;
160  char * filepath;
161  DIR * dir;
162  struct dirent * dentry;
163  struct stat st;
164  lash_config_t * config_ptr;
165
166  clean_pending_configs();
167  ASSERT(list_empty(&g_pending_configs));
168
169  log_debug("Loading configs from '%s'", appdir);
170
171  dirpath = catdup(appdir, LASH_CONFIG_SUBDIR);
172  if (dirpath == NULL)
173  {
174    goto exit;
175  }
176
177  dir = opendir(dirpath);
178  if (dir == NULL)
179  {
180    log_error("Cannot open directory '%s': %d (%s)", dirpath, errno, strerror(errno));
181    goto free;
182  }
183
184  while ((dentry = readdir(dir)) != NULL)
185  {
186    if (strcmp(dentry->d_name, ".") == 0 ||
187        strcmp(dentry->d_name, "..") == 0)
188    {
189      continue;
190    }
191
192    filepath = catdup3(dirpath, "/", dentry->d_name);
193    if (filepath == NULL)
194    {
195      log_error("catdup() failed");
196      goto close;
197    }
198
199    if (stat(filepath, &st) != 0)
200    {
201      log_error("failed to stat '%s': %d (%s)", filepath, errno, strerror(errno));
202      goto next;
203    }
204
205    if (!S_ISREG(st.st_mode))
206    {
207      log_error("not regular file '%s' with mode is %07o", filepath, st.st_mode);
208      goto next;
209    }
210
211    config_ptr = lash_config_new_with_key(dentry->d_name);
212    if (config_ptr == NULL)
213    {
214      goto next;
215    }
216
217    config_ptr->value = read_file_contents(filepath);
218    if (config_ptr->value == NULL)
219    {
220      log_error("read from '%s' failed", filepath);
221      lash_config_destroy(config_ptr);
222      goto next;
223    }
224
225    config_ptr->size = (size_t)st.st_size;
226    list_add_tail(&config_ptr->siblings, &g_pending_configs);
227
228    log_debug("loaded dict key '%s'", dentry->d_name);
229
230  next:
231    free(filepath);
232  }
233
234close:
235  closedir(dir);
236free:
237  free(dirpath);
238exit:
239  return;
240}
241
242const char * lash_protocol_string(lash_protocol_t protocol)
243{
244  return "ladish";
245}
246
247lash_args_t * lash_extract_args(int * argc, char *** argv)
248{
249  /* nothing to do, ladish does not pass any specific arguments */
250        return NULL;
251}
252
253void lash_args_destroy(lash_args_t * args)
254{
255  /* nothing to do, ladish does not pass any specific arguments */
256}
257
258lash_client_t * lash_init(const lash_args_t * args, const char * class, int client_flags, lash_protocol_t protocol)
259{
260  DBusError error;
261  DBusMessage * msg_ptr;
262  const char * dbus_unique_name;
263  bool ret;
264  dbus_uint32_t flags32;
265  dbus_uint64_t pid;
266
267  if ((client_flags & LASH_Server_Interface) != 0)
268  {
269    log_error("ladish does not implement LASH server interface.");
270    goto fail;
271  }
272
273  dbus_error_init(&error);
274  cdbus_g_dbus_connection = dbus_bus_get_private(DBUS_BUS_SESSION, &error);
275  if (cdbus_g_dbus_connection == NULL)
276  {
277    log_error("Cannot connect to D-Bus session bus: %s", error.message);
278    dbus_error_free(&error);
279    goto fail;
280  }
281
282  dbus_connection_set_exit_on_disconnect(cdbus_g_dbus_connection, FALSE);
283
284  dbus_unique_name = dbus_bus_get_unique_name(cdbus_g_dbus_connection);
285  if (dbus_unique_name == NULL)
286  {
287    log_error("Failed to read unique bus name");
288    goto close_connection;
289  }
290
291  log_info("Connected to session bus, unique name is \"%s\"", dbus_unique_name);
292
293
294  g_object = cdbus_object_path_new("/", &g_interface, NULL, NULL);
295  if (g_object == NULL)
296  {
297    goto close_connection;
298  }
299
300  if (!cdbus_object_path_register(cdbus_g_dbus_connection, g_object))
301  {
302    goto destroy_object;
303  }
304
305  flags32 = client_flags;
306  pid = getpid();
307  msg_ptr = cdbus_new_method_call_message(SERVICE_NAME, LASH_SERVER_OBJECT_PATH, IFACE_LASH_SERVER, "RegisterClient", "tsu", &pid, &class, &flags32);
308  if (msg_ptr == NULL)
309  {
310    goto close_connection;
311  }
312
313  ret = dbus_connection_send(cdbus_g_dbus_connection, msg_ptr, NULL);
314  dbus_message_unref(msg_ptr);
315  if (!ret)
316  {
317    log_error("Cannot send message over D-Bus due to lack of memory");
318    goto close_connection;
319  }
320
321  log_debug("ladish LASH support initialized (%s %s)", (client_flags & LASH_Config_File) != 0 ? "file" : "", (client_flags & LASH_Config_Data_Set) != 0 ? "dict" : "");
322  g_client.flags = client_flags;
323
324  return &g_client;
325
326destroy_object:
327  cdbus_object_path_destroy(cdbus_g_dbus_connection, g_object);
328close_connection:
329  dbus_connection_close(cdbus_g_dbus_connection);
330  dbus_connection_unref(cdbus_g_dbus_connection);
331fail:
332  return NULL;
333}
334
335unsigned int lash_get_pending_event_count(lash_client_t * client_ptr)
336{
337  ASSERT(client_ptr == &g_client);
338  return !g_busy && g_event.type != 0 ? 1 : 0;
339}
340
341static void dispatch(void)
342{
343        do
344        {
345                dbus_connection_read_write_dispatch(cdbus_g_dbus_connection, 0);
346        }
347        while (dbus_connection_get_dispatch_status(cdbus_g_dbus_connection) == DBUS_DISPATCH_DATA_REMAINS);
348}
349
350unsigned int lash_get_pending_config_count(lash_client_t * client_ptr)
351{
352  struct list_head * node_ptr;
353  unsigned int count;
354
355  ASSERT(client_ptr == &g_client);
356  dispatch();
357
358  count = 0;
359  list_for_each(node_ptr, &g_pending_configs)
360  {
361    count++;
362  }
363
364  return count;
365}
366
367lash_event_t * lash_get_event(lash_client_t * client_ptr)
368{
369  ASSERT(client_ptr == &g_client);
370  dispatch();
371
372  if (g_busy)
373  {
374    if (g_event.type == LASH_Restore_Data_Set && list_empty(&g_pending_configs))
375    {
376      /* the example lash_simple_client client does not send LASH_Restore_Data_Set event back */
377      lash_send_event(&g_client, &g_event);
378      ASSERT(!g_busy);
379    }
380    else
381    {
382      return NULL;
383    }
384  }
385
386  if (g_event.type == 0)
387  {
388    if (g_quit)
389    {
390      g_event.type = LASH_Quit;
391    }
392    else
393    {
394      return NULL;
395    }
396  }
397
398  if (g_event.type == LASH_Save_Data_Set)
399  {
400    clean_pending_configs();
401    /* TODO: change status to "saving" */
402  }
403  else if (g_event.type == LASH_Restore_Data_Set)
404  {
405    load_configs(g_event.string);
406    /* TODO: change status to "restoring (data)" */
407  }
408  else if (g_event.type == LASH_Restore_File)
409  {
410    /* TODO: change status to "restoring (file)" */
411  }
412  else if (g_event.type == LASH_Save_File)
413  {
414    /* TODO: change status to "saving" */
415  }
416  else if (g_event.type == LASH_Quit)
417  {
418    /* TODO: change status to "quitting" */
419  }
420
421  g_busy = true;
422  log_debug("App begins to process event %d (%s)", g_event.type, g_event.string);
423  return &g_event;
424}
425
426lash_config_t * lash_get_config(lash_client_t * client_ptr)
427{
428  struct _lash_config * config_ptr;
429
430  ASSERT(client_ptr == &g_client);
431
432  if (list_empty(&g_pending_configs))
433  {
434    return NULL;
435  }
436
437  config_ptr = list_entry(g_pending_configs.next, struct _lash_config, siblings);
438  list_del(g_pending_configs.next);
439
440  return config_ptr;
441}
442
443void lash_send_event(lash_client_t * client_ptr, lash_event_t * event_ptr)
444{
445  ASSERT(client_ptr == &g_client);
446
447  log_debug("lash_send_event() called. type=%d string=%s", event_ptr->type, event_ptr->string != NULL ? event_ptr->string : "(NULL)");
448
449  dispatch();
450
451  if (!g_busy)
452  {
453    return;
454  }
455
456  if (event_ptr->type == LASH_Save_File)
457  {
458    log_debug("Save to file complete (%s)", g_event.string);
459    g_busy = false;
460
461    if ((g_client.flags & LASH_Config_Data_Set) != 0)
462    {
463      log_debug("Client wants to save a dict too");
464      g_event.type = LASH_Save_Data_Set;
465      if (event_ptr == &g_event)
466      {
467        return;
468      }
469    }
470    else
471    {
472      g_event.type = 0;
473      free(g_event.string);
474      g_event.string = NULL; 
475      /* TODO: change status to "saved" */
476   }
477  }
478  else if (event_ptr->type == LASH_Save_Data_Set)
479  {
480    log_debug("Save to dict complete (%s)", g_event.string);
481
482    save_pending_configs(g_event.string);
483
484    g_busy = false;
485
486    g_event.type = 0;
487    free(g_event.string);
488    g_event.string = NULL;
489      /* TODO: change status to "saved" */
490  }
491  else if (event_ptr->type == LASH_Restore_Data_Set)
492  {
493    log_debug("Restore from dict complete (%s)", g_event.string);
494    g_busy = false;
495
496    if ((g_client.flags & LASH_Config_File) != 0)
497    {
498      log_debug("Client wants to restore from file too");
499      g_event.type = LASH_Restore_File;
500      if (event_ptr == &g_event)
501      {
502        return;
503      }
504    }
505    else
506    {
507      g_event.type = 0;
508      free(g_event.string);
509      g_event.string = NULL;
510      /* TODO: change status to "restored" */
511    }
512  }
513  else if (event_ptr->type == LASH_Restore_File)
514  {
515    log_debug("Restore from file complete (%s)", g_event.string);
516
517    g_busy = false;
518
519    g_event.type = 0;
520    free(g_event.string);
521    g_event.string = NULL;
522    /* TODO: change status to "restored" */
523  }
524
525  lash_event_destroy(event_ptr);
526}
527
528void lash_send_config(lash_client_t * client_ptr, lash_config_t * config_ptr)
529{
530  ASSERT(client_ptr == &g_client);
531
532  log_debug("lash_send_config() called. key=%s value_size=%zu", config_ptr->key, config_ptr->size);
533
534  dispatch();
535
536  if (g_event.type == LASH_Save_Data_Set)
537  {
538    list_add_tail(&config_ptr->siblings, &g_pending_configs);
539  }
540  else
541  {
542    log_error("Ignoring config with key '%s' because app is not saving data set", config_ptr->key);
543    lash_config_destroy(config_ptr);
544  }
545}
546
547int lash_server_connected(lash_client_t * client_ptr)
548{
549  ASSERT(client_ptr == &g_client);
550  return 1;                     /* yes */
551}
552
553const char * lash_get_server_name(lash_client_t * client_ptr)
554{
555  ASSERT(client_ptr == &g_client);
556        return "localhost";
557}
558
559lash_event_t * lash_event_new(void)
560{
561  struct _lash_event * event_ptr;
562
563  event_ptr = malloc(sizeof(struct _lash_event));
564  if (event_ptr == NULL)
565  {
566    log_error("malloc() failed to allocate lash event struct");
567    return NULL;
568  }
569
570  event_ptr->type = 0;
571  event_ptr->string = NULL;
572
573  return event_ptr;
574}
575
576lash_event_t * lash_event_new_with_type(enum LASH_Event_Type type)
577{
578        lash_event_t * event_ptr;
579
580        event_ptr = lash_event_new();
581  if (event_ptr == NULL)
582  {
583    return NULL;
584  }
585
586        lash_event_set_type(event_ptr, type);
587        return event_ptr;
588}
589
590lash_event_t * lash_event_new_with_all(enum LASH_Event_Type type, const char * string)
591{
592        lash_event_t * event_ptr;
593
594        event_ptr = lash_event_new_with_type(type);
595  if (event_ptr == NULL)
596  {
597    return NULL;
598  }
599
600  if (string != NULL)
601  {
602    event_ptr->string = strdup(string);
603    if (event_ptr->string == NULL)
604    {
605      log_error("strdup() failed for event string '%s'", string);
606      free(event_ptr);
607      return NULL;
608    }
609  }
610
611        return event_ptr;
612}
613
614void lash_event_destroy(lash_event_t * event_ptr)
615{
616  free(event_ptr->string);
617  if (event_ptr == &g_event)
618  {
619    event_ptr->type = 0;
620    event_ptr->string = NULL;
621  }
622  else
623  {
624    free(event_ptr);
625  }
626}
627
628enum LASH_Event_Type lash_event_get_type(const lash_event_t * event_ptr)
629{
630  return event_ptr->type;
631}
632
633const char * lash_event_get_string(const lash_event_t * event_ptr)
634{
635  return event_ptr->string;
636}
637
638void lash_event_set_type(lash_event_t * event_ptr, enum LASH_Event_Type type)
639{
640  event_ptr->type = type;
641}
642
643void lash_event_set_string(lash_event_t * event_ptr, const char * string)
644{
645  char * dup;
646
647  if (string != NULL)
648  {
649    dup = strdup(string);
650    if (dup == NULL)
651    {
652      log_error("strdup() failed for event string '%s'", string);
653      ASSERT_NO_PASS;
654      return;
655    }
656  }
657  else
658  {
659    dup = NULL;
660  }
661
662  free(event_ptr->string);
663  event_ptr->string = dup;
664}
665
666const char * lash_event_get_project(const lash_event_t * event_ptr)
667{
668  /* Server interface - not implemented */
669  ASSERT_NO_PASS;               /* lash_init() fails if LASH_Server_Interface is set */
670  return NULL;
671}
672
673void lash_event_set_project(lash_event_t * event_ptr, const char * project)
674{
675  /* Server interface - not implemented */
676  ASSERT_NO_PASS;               /* lash_init() fails if LASH_Server_Interface is set */
677}
678
679void lash_event_get_client_id(const lash_event_t * event_ptr, uuid_t id)
680{
681  /* Server interface - not implemented */
682  ASSERT_NO_PASS;               /* lash_init() fails if LASH_Server_Interface is set */
683}
684 
685void lash_event_set_client_id(lash_event_t * event_ptr, uuid_t id)
686{
687  /* Server interface - not implemented */
688  ASSERT_NO_PASS;               /* lash_init() fails if LASH_Server_Interface is set */
689}
690
691unsigned char lash_event_get_alsa_client_id(const lash_event_t * event_ptr)
692{
693  /* Server interface - not implemented */
694  ASSERT_NO_PASS;               /* lash_init() fails if LASH_Server_Interface is set */
695  return 0;
696}
697
698unsigned char lash_str_get_alsa_client_id(const char * str)
699{
700  /* Server interface - not implemented */
701  ASSERT_NO_PASS;               /* lash_init() fails if LASH_Server_Interface is set */
702  /* this is an undocumented function and probably internal one that sneaked to the public API */
703  return 0;
704}
705
706void lash_jack_client_name(lash_client_t * client_ptr, const char * name)
707{
708  /* nothing to do, ladish detects jack client name through jack server */
709}
710
711void lash_str_set_alsa_client_id(char * str, unsigned char alsa_id)
712{
713  /* nothing to do, ladish detects alsa id through alsapid.so, jack and a2jmidid */
714  /* this is an undocumented function and probably internal one that sneaked to the public API */
715}
716
717void lash_event_set_alsa_client_id(lash_event_t * event_ptr, unsigned char alsa_id)
718{
719  /* set event type, so we can silently ignore the event, when sent */
720        lash_event_set_type(event_ptr, LASH_Alsa_Client_ID);
721}
722
723void lash_alsa_client_id(lash_client_t * client, unsigned char id)
724{
725  /* nothing to do, ladish detects alsa id through alsapid.so, jack and a2jmidid */
726}
727
728lash_config_t * lash_config_new(void)
729{
730  struct _lash_config * config_ptr;
731
732  config_ptr = malloc(sizeof(struct _lash_config));
733  if (config_ptr == NULL)
734  {
735    log_error("malloc() failed to allocate lash event struct");
736    return NULL;
737  }
738
739  config_ptr->key = NULL;
740  config_ptr->value = NULL;
741  config_ptr->size = 0;
742
743  return config_ptr;
744}
745
746lash_config_t * lash_config_dup(const lash_config_t * src_ptr)
747{
748        lash_config_t * dst_ptr;
749
750        dst_ptr = lash_config_new();
751  if (dst_ptr == NULL)
752  {
753    return NULL;
754  }
755
756  ASSERT(src_ptr->key != NULL);
757  dst_ptr->key = strdup(src_ptr->key);
758  if (dst_ptr->key == NULL)
759  {
760    log_error("strdup() failed for config key '%s'", src_ptr->key);
761    free(dst_ptr);
762    return NULL;
763  }
764
765  if (dst_ptr->value != NULL)
766  {
767    dst_ptr->value = malloc(src_ptr->size);
768    if (dst_ptr->value == NULL)
769    {
770      log_error("strdup() failed for config value with size %zu", src_ptr->size);
771      free(dst_ptr->key);
772      free(dst_ptr);
773      return NULL;
774    }
775
776                memcpy(dst_ptr->value, src_ptr->value, src_ptr->size);
777    dst_ptr->size = src_ptr->size;
778  }
779
780        return dst_ptr;
781}
782
783lash_config_t * lash_config_new_with_key(const char * key)
784{
785        lash_config_t * config_ptr;
786
787        config_ptr = lash_config_new();
788  if (config_ptr == NULL)
789  {
790    return NULL;
791  }
792
793  config_ptr->key = strdup(key);
794  if (config_ptr->key == NULL)
795  {
796    log_error("strdup() failed for config key '%s'", key);
797    free(config_ptr);
798    return NULL;
799  }
800
801        return config_ptr;
802}
803
804void lash_config_destroy(lash_config_t * config_ptr)
805{
806  free(config_ptr->key);
807  free(config_ptr->value);
808  free(config_ptr);
809}
810
811const char * lash_config_get_key(const lash_config_t * config_ptr)
812{
813  return config_ptr->key;
814}
815
816const void * lash_config_get_value(const lash_config_t * config_ptr)
817{
818  return config_ptr->value;
819}
820
821size_t lash_config_get_value_size(const lash_config_t * config_ptr)
822{
823  return config_ptr->size;
824}
825
826void lash_config_set_key(lash_config_t * config_ptr, const char * key)
827{
828  char * dup;
829
830  ASSERT(key != NULL);
831
832  dup = strdup(key);
833  if (dup == NULL)
834  {
835    log_error("strdup() failed for config key '%s'", key);
836    ASSERT_NO_PASS;
837    return;
838  }
839
840  free(config_ptr->key);
841  config_ptr->key = dup;
842}
843
844void lash_config_set_value(lash_config_t * config_ptr, const void * value, size_t value_size)
845{
846  void * buf;
847
848  if (value != NULL)
849  {
850                buf = malloc(value_size);
851    if (buf == NULL)
852    {
853      log_error("malloc() failed for config value with size %zu", value_size);
854      ASSERT_NO_PASS;
855      return;
856    }
857
858                memcpy(buf, value, value_size);
859  }
860  else
861  {
862    buf = NULL;
863    value_size = 0;
864  }
865
866  free(config_ptr->value);
867  config_ptr->value = buf;
868  config_ptr->size = value_size;
869}
870
871uint32_t lash_config_get_value_int(const lash_config_t * config_ptr)
872{
873  ASSERT(lash_config_get_value_size(config_ptr) >= sizeof(uint32_t));
874        return ntohl(*(const uint32_t *)lash_config_get_value(config_ptr));
875}
876
877float lash_config_get_value_float(const lash_config_t * config_ptr)
878{
879  ASSERT(lash_config_get_value_size(config_ptr) >= sizeof(float));
880        return *(const float *)lash_config_get_value(config_ptr);
881}
882
883double lash_config_get_value_double(const lash_config_t * config_ptr)
884{
885  ASSERT(lash_config_get_value_size(config_ptr) >= sizeof(double));
886        return *(const double *)lash_config_get_value(config_ptr);
887}
888
889const char * lash_config_get_value_string(const lash_config_t * config_ptr)
890{
891  const char * string;
892  size_t len;
893  void * ptr;
894
895  string = lash_config_get_value(config_ptr);
896  len = lash_config_get_value_size(config_ptr);
897  ptr = memchr(string, 0, len);
898  ASSERT(ptr != NULL);
899  return string;
900}
901
902void lash_config_set_value_int(lash_config_t * config_ptr, uint32_t value)
903{
904        value = htonl(value);
905        lash_config_set_value(config_ptr, &value, sizeof(uint32_t));
906}
907
908void lash_config_set_value_float(lash_config_t * config_ptr, float value)
909{
910        lash_config_set_value(config_ptr, &value, sizeof(float));
911}
912
913void lash_config_set_value_double(lash_config_t * config_ptr, double value)
914{
915        lash_config_set_value(config_ptr, &value, sizeof(double));
916}
917
918void lash_config_set_value_string(lash_config_t * config_ptr, const char * value)
919{
920        lash_config_set_value(config_ptr, value, strlen(value) + 1);
921}
922
923const char * lash_get_fqn(const char * dir, const char * file)
924{
925  static char * fqn = NULL;
926
927  if (fqn != NULL)
928  {
929    free(fqn);
930  }
931
932  fqn = catdup3(dir, "/", file);
933
934  return fqn;
935}
936
937/***************************************************************************/
938/* D-Bus interface implementation */
939
940static void lash_quit(struct cdbus_method_call * call_ptr)
941{
942  log_debug("Quit command received through D-Bus");
943  g_quit = true;
944}
945
946static void lash_save(struct cdbus_method_call * call_ptr)
947{
948  const char * dir;
949  char * dup;
950  int type;
951
952  dbus_error_init(&cdbus_g_dbus_error);
953  if (!dbus_message_get_args(call_ptr->message, &cdbus_g_dbus_error, DBUS_TYPE_STRING, &dir, DBUS_TYPE_INVALID))
954  {
955    lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Invalid arguments to method \"%s\": %s",  call_ptr->method_name, cdbus_g_dbus_error.message);
956    dbus_error_free(&cdbus_g_dbus_error);
957    return;
958  }
959
960  log_debug("Save command received through D-Bus (%s)", dir);
961
962  if (g_event.type != 0)
963  {
964    lash_dbus_error(call_ptr, LASH_DBUS_ERROR_UNFINISHED_TASK, "App is busy processing event if type %d", g_event.type);
965    return;
966  }
967
968  if (g_quit != 0)
969  {
970    lash_dbus_error(call_ptr, LASH_DBUS_ERROR_UNFINISHED_TASK, "App is quitting", g_event.type);
971    return;
972  }
973
974  if ((g_client.flags & LASH_Config_File) != 0)
975  {
976    type = LASH_Save_File;
977  }
978  else if ((g_client.flags & LASH_Config_Data_Set) != 0)
979  {
980    type = LASH_Save_Data_Set;
981  }
982  else
983  {
984    log_debug("App does not have internal state");
985    /* TODO: change status to "saved" */
986    return;
987  }
988
989  dup = strdup(dir);
990  if (dup == NULL)
991  {
992    lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "strdup() failed for event string (dir) '%s'", dup);
993    return;
994  }
995
996  ASSERT(g_event.string == NULL);
997  g_event.string = dup;
998  g_event.type = type;
999}
1000
1001static void lash_restore(struct cdbus_method_call * call_ptr)
1002{
1003  const char * dir;
1004  char * dup;
1005  int type;
1006
1007  dbus_error_init(&cdbus_g_dbus_error);
1008  if (!dbus_message_get_args(call_ptr->message, &cdbus_g_dbus_error, DBUS_TYPE_STRING, &dir, DBUS_TYPE_INVALID))
1009  {
1010    lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Invalid arguments to method \"%s\": %s",  call_ptr->method_name, cdbus_g_dbus_error.message);
1011    dbus_error_free(&cdbus_g_dbus_error);
1012    return;
1013  }
1014
1015  log_debug("Restore command received through D-Bus (%s)", dir);
1016
1017  if (g_event.type != 0)
1018  {
1019    lash_dbus_error(call_ptr, LASH_DBUS_ERROR_UNFINISHED_TASK, "App is busy processing event if type %d", g_event.type);
1020    return;
1021  }
1022
1023  if (g_quit != 0)
1024  {
1025    lash_dbus_error(call_ptr, LASH_DBUS_ERROR_UNFINISHED_TASK, "App is quitting", g_event.type);
1026    return;
1027  }
1028
1029  if ((g_client.flags & LASH_Config_File) != 0)
1030  {
1031    type = LASH_Restore_File;
1032  }
1033  else if ((g_client.flags & LASH_Config_Data_Set) != 0)
1034  {
1035    type = LASH_Restore_Data_Set;
1036  }
1037  else
1038  {
1039    log_debug("App does not have internal state");
1040    /* TODO: change status to "restored" */
1041    return;
1042  }
1043
1044  dup = strdup(dir);
1045  if (dup == NULL)
1046  {
1047    lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "strdup() failed for event string (dir) '%s'", dup);
1048    return;
1049  }
1050
1051  ASSERT(g_event.string == NULL);
1052  g_event.string = dup;
1053  g_event.type = type;
1054}
1055
1056METHOD_ARGS_BEGIN(Save, "Tell lash client to save")
1057  METHOD_ARG_DESCRIBE_IN("app_dir", "s", "Directory where app must save its internal state")
1058METHOD_ARGS_END
1059
1060METHOD_ARGS_BEGIN(Restore, "Tell lash client to restore")
1061  METHOD_ARG_DESCRIBE_IN("app_dir", "s", "Directory from where app must load its internal state")
1062METHOD_ARGS_END
1063
1064METHOD_ARGS_BEGIN(Quit, "Tell lash client to quit")
1065METHOD_ARGS_END
1066
1067METHODS_BEGIN
1068  METHOD_DESCRIBE(Save, lash_save)
1069  METHOD_DESCRIBE(Restore, lash_restore)
1070  METHOD_DESCRIBE(Quit, lash_quit)
1071METHODS_END
1072
1073INTERFACE_BEGIN(g_interface, IFACE_LASH_CLIENT)
1074  INTERFACE_DEFAULT_HANDLER
1075  INTERFACE_EXPOSE_METHODS
1076INTERFACE_END
Note: See TracBrowser for help on using the browser.