Blame src/srvc_store.c

Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  Meanwhile - Unofficial Lotus Sametime Community Client Library
Packit Service 37472d
  Copyright (C) 2004  Christopher (siege) O'Brien
Packit Service 37472d
  
Packit Service 37472d
  This library is free software; you can redistribute it and/or
Packit Service 37472d
  modify it under the terms of the GNU Library General Public
Packit Service 37472d
  License as published by the Free Software Foundation; either
Packit Service 37472d
  version 2 of the License, or (at your option) any later version.
Packit Service 37472d
  
Packit Service 37472d
  This library is distributed in the hope that it will be useful,
Packit Service 37472d
  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 37472d
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 37472d
  Library General Public License for more details.
Packit Service 37472d
  
Packit Service 37472d
  You should have received a copy of the GNU Library General Public
Packit Service 37472d
  License along with this library; if not, write to the Free
Packit Service 37472d
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Packit Service 37472d
*/
Packit Service 37472d
Packit Service 1bfe49
#include <glib.h>
Packit Service 37472d
Packit Service 37472d
#include "mw_channel.h"
Packit Service 37472d
#include "mw_debug.h"
Packit Service 37472d
#include "mw_error.h"
Packit Service 37472d
#include "mw_message.h"
Packit Service 37472d
#include "mw_service.h"
Packit Service 37472d
#include "mw_session.h"
Packit Service 37472d
#include "mw_srvc_store.h"
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
#define PROTOCOL_TYPE  0x00000025
Packit Service 37472d
#define PROTOCOL_VER   0x00000001
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
enum storage_action {
Packit Service 37472d
  action_load    = 0x0004,
Packit Service 37472d
  action_loaded  = 0x0005,
Packit Service 37472d
  action_save    = 0x0006,
Packit Service 37472d
  action_saved   = 0x0007,
Packit Service 37472d
};
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
struct mwStorageUnit {
Packit Service 37472d
  /** key by which data is referenced in service
Packit Service 37472d
      @see mwStorageKey */
Packit Service 37472d
  guint32 key;
Packit Service 37472d
Packit Service 37472d
  /** Data associated with key in service */
Packit Service 37472d
  struct mwOpaque data;
Packit Service 37472d
};
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
struct mwStorageReq {
Packit Service 37472d
  guint32 id;                  /**< unique id for this request */
Packit Service 37472d
  guint32 result_code;         /**< result code for completed request */
Packit Service 37472d
  enum storage_action action;  /**< load or save */
Packit Service 37472d
  struct mwStorageUnit *item;  /**< the key/data pair */ 
Packit Service 37472d
  mwStorageCallback cb;        /**< callback to notify upon completion */
Packit Service 37472d
  gpointer data;               /**< user data to pass with callback */
Packit Service 37472d
  GDestroyNotify data_free;    /**< optionally frees user data */
Packit Service 37472d
};
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
struct mwServiceStorage {
Packit Service 37472d
  struct mwService service;
Packit Service 37472d
Packit Service 37472d
  /** collection of mwStorageReq */
Packit Service 37472d
  GList *pending;
Packit Service 37472d
Packit Service 37472d
  /** current service channel */
Packit Service 37472d
  struct mwChannel *channel;
Packit Service 37472d
Packit Service 37472d
  /** keep track of the counter */
Packit Service 37472d
  guint32 id_counter;
Packit Service 37472d
};
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void request_get(struct mwGetBuffer *b, struct mwStorageReq *req) {
Packit Service 37472d
  guint32 id, count, junk;
Packit Service 37472d
Packit Service 37472d
  if(mwGetBuffer_error(b)) return;
Packit Service 37472d
Packit Service 37472d
  guint32_get(b, &id;;
Packit Service 37472d
  guint32_get(b, &req->result_code);
Packit Service 37472d
Packit Service 37472d
  if(req->action == action_loaded) {
Packit Service 37472d
    guint32_get(b, &count);
Packit Service 37472d
Packit Service 37472d
    if(count > 0) {
Packit Service 37472d
      guint32_get(b, &junk);
Packit Service 37472d
      guint32_get(b, &req->item->key);
Packit Service 37472d
Packit Service 37472d
      mwOpaque_clear(&req->item->data);
Packit Service 37472d
      mwOpaque_get(b, &req->item->data);
Packit Service 37472d
    }
Packit Service 37472d
  }
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void request_put(struct mwPutBuffer *b, struct mwStorageReq *req) {
Packit Service 37472d
Packit Service 37472d
  guint32_put(b, req->id);
Packit Service 37472d
  guint32_put(b, 1);
Packit Service 37472d
Packit Service 37472d
  if(req->action == action_save) {
Packit Service 37472d
    guint32_put(b, 20 + req->item->data.len); /* ugh, offset garbage */
Packit Service 37472d
    guint32_put(b, req->item->key);
Packit Service 37472d
    mwOpaque_put(b, &req->item->data);
Packit Service 37472d
Packit Service 37472d
  } else {
Packit Service 37472d
    guint32_put(b, req->item->key);
Packit Service 37472d
  }
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static int request_send(struct mwChannel *chan, struct mwStorageReq *req) {
Packit Service 37472d
  struct mwPutBuffer *b;
Packit Service 37472d
  struct mwOpaque o = { 0, 0 };
Packit Service 37472d
  int ret;
Packit Service 37472d
Packit Service 37472d
  b = mwPutBuffer_new();
Packit Service 37472d
  request_put(b, req);
Packit Service 37472d
Packit Service 37472d
  mwPutBuffer_finalize(&o, b);
Packit Service 37472d
  ret = mwChannel_send(chan, req->action, &o);
Packit Service 37472d
  mwOpaque_clear(&o);
Packit Service 37472d
Packit Service 37472d
  if(! ret) {
Packit Service 37472d
    if(req->action == action_save) {
Packit Service 37472d
      req->action = action_saved;
Packit Service 37472d
    } else if(req->action == action_load) {
Packit Service 37472d
      req->action = action_loaded;
Packit Service 37472d
    }
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  return ret;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static struct mwStorageReq *request_find(struct mwServiceStorage *srvc,
Packit Service 37472d
					 guint32 id) {
Packit Service 37472d
  GList *l;
Packit Service 37472d
Packit Service 37472d
  for(l = srvc->pending; l; l = l->next) {
Packit Service 37472d
    struct mwStorageReq *r = l->data;
Packit Service 37472d
    if(r->id == id) return r;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  return NULL;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static const char *action_str(enum storage_action act) {
Packit Service 37472d
  switch(act) {
Packit Service 37472d
  case action_load:    return "load";
Packit Service 37472d
  case action_loaded:  return "loaded";
Packit Service 37472d
  case action_save:    return "save";
Packit Service 37472d
  case action_saved:   return "saved";
Packit Service 37472d
  default:             return "UNKNOWN";
Packit Service 37472d
  }
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void request_trigger(struct mwServiceStorage *srvc,
Packit Service 37472d
			    struct mwStorageReq *req) {
Packit Service 37472d
Packit Service 37472d
  struct mwStorageUnit *item = req->item;
Packit Service 37472d
Packit Service 37472d
  g_message("storage request %s: key = 0x%x, result = 0x%x, length = %u",
Packit Service 37472d
	    action_str(req->action),
Packit Service 37472d
	    item->key, req->result_code, (guint) item->data.len);
Packit Service 37472d
  
Packit Service 37472d
  if(req->cb)
Packit Service 37472d
    req->cb(srvc, req->result_code, item, req->data);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void request_free(struct mwStorageReq *req) {
Packit Service 37472d
  if(req->data_free) {
Packit Service 37472d
    req->data_free(req->data);
Packit Service 37472d
    req->data = NULL;
Packit Service 37472d
    req->data_free = NULL;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  mwStorageUnit_free(req->item);
Packit Service 37472d
  g_free(req);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void request_remove(struct mwServiceStorage *srvc,
Packit Service 37472d
			   struct mwStorageReq *req) {
Packit Service 37472d
Packit Service 37472d
  srvc->pending = g_list_remove_all(srvc->pending, req);
Packit Service 37472d
  request_free(req);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static const char *get_name(struct mwService *srvc) {
Packit Service 37472d
  return "User Storage";
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static const char *get_desc(struct mwService *srvc) {
Packit Service 37472d
  return "Stores user data and settings on the server";
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static struct mwChannel *make_channel(struct mwServiceStorage *srvc) {
Packit Service 37472d
  struct mwSession *session;
Packit Service 37472d
  struct mwChannelSet *cs;
Packit Service 37472d
  struct mwChannel *chan;
Packit Service 37472d
Packit Service 37472d
  session = mwService_getSession(MW_SERVICE(srvc));
Packit Service 37472d
  cs = mwSession_getChannels(session);
Packit Service 37472d
  chan = mwChannel_newOutgoing(cs);
Packit Service 37472d
 
Packit Service 37472d
  mwChannel_setService(chan, MW_SERVICE(srvc));
Packit Service 37472d
  mwChannel_setProtoType(chan, PROTOCOL_TYPE);
Packit Service 37472d
  mwChannel_setProtoVer(chan, PROTOCOL_VER);
Packit Service 37472d
Packit Service 37472d
  return mwChannel_create(chan)? NULL: chan;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void start(struct mwService *srvc) {
Packit Service 37472d
  struct mwServiceStorage *srvc_store;
Packit Service 37472d
  struct mwChannel *chan;
Packit Service 37472d
Packit Service 37472d
  g_return_if_fail(srvc != NULL);
Packit Service 37472d
  srvc_store = (struct mwServiceStorage *) srvc;
Packit Service 37472d
Packit Service 37472d
  chan = make_channel(srvc_store);
Packit Service 37472d
  if(chan) {
Packit Service 37472d
    srvc_store->channel = chan;
Packit Service 37472d
  } else {
Packit Service 37472d
    mwService_stopped(srvc);
Packit Service 37472d
  }
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void stop(struct mwService *srvc) {
Packit Service 37472d
Packit Service 37472d
  struct mwServiceStorage *srvc_store;
Packit Service 37472d
  GList *l;
Packit Service 37472d
Packit Service 37472d
  g_return_if_fail(srvc != NULL);
Packit Service 37472d
  srvc_store = (struct mwServiceStorage *) srvc;
Packit Service 37472d
Packit Service 37472d
  if(srvc_store->channel) {
Packit Service 37472d
    mwChannel_destroy(srvc_store->channel, ERR_SUCCESS, NULL);
Packit Service 37472d
    srvc_store->channel = NULL;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
#if 1
Packit Service 37472d
  /* the new way */
Packit Service 37472d
  /* remove pending requests. Sometimes we can crash the storage
Packit Service 37472d
     service, and when that happens, we end up resending the killer
Packit Service 37472d
     request over and over again, and the service never stays up */
Packit Service 37472d
  for(l = srvc_store->pending; l; l = l->next)
Packit Service 37472d
    request_free(l->data);
Packit Service 37472d
Packit Service 37472d
  g_list_free(srvc_store->pending);
Packit Service 37472d
  srvc_store->pending = NULL;
Packit Service 37472d
Packit Service 37472d
  srvc_store->id_counter = 0;
Packit Service 37472d
Packit Service 37472d
#else
Packit Service 37472d
  /* the old way */
Packit Service 37472d
  /* reset all of the started requests to their unstarted states */
Packit Service 37472d
  for(l = srvc_store->pending; l; l = l->next) {
Packit Service 37472d
    struct mwStorageReq *req = l->data;
Packit Service 37472d
Packit Service 37472d
    if(req->action == action_loaded) {
Packit Service 37472d
      req->action = action_load;
Packit Service 37472d
    } else if(req->action == action_saved) {
Packit Service 37472d
      req->action = action_save;
Packit Service 37472d
    }
Packit Service 37472d
  }
Packit Service 37472d
#endif
Packit Service 37472d
Packit Service 37472d
  mwService_stopped(srvc);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void recv_channelAccept(struct mwService *srvc,
Packit Service 37472d
			       struct mwChannel *chan,
Packit Service 37472d
			       struct mwMsgChannelAccept *msg) {
Packit Service 37472d
 
Packit Service 37472d
  struct mwServiceStorage *srvc_stor;
Packit Service 37472d
  GList *l;
Packit Service 37472d
Packit Service 37472d
  g_return_if_fail(srvc != NULL);
Packit Service 37472d
  srvc_stor = (struct mwServiceStorage *) srvc;
Packit Service 37472d
Packit Service 37472d
  g_return_if_fail(chan != NULL);
Packit Service 37472d
  g_return_if_fail(chan == srvc_stor->channel);
Packit Service 37472d
Packit Service 37472d
  /* send all pending requests */
Packit Service 37472d
  for(l = srvc_stor->pending; l; l = l->next) {
Packit Service 37472d
    struct mwStorageReq *req = l->data;
Packit Service 37472d
Packit Service 37472d
    if(req->action == action_save || req->action == action_load) {
Packit Service 37472d
      request_send(chan, req);
Packit Service 37472d
    }
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  mwService_started(srvc);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void recv_channelDestroy(struct mwService *srvc,
Packit Service 37472d
				struct mwChannel *chan,
Packit Service 37472d
				struct mwMsgChannelDestroy *msg) {
Packit Service 37472d
Packit Service 37472d
  struct mwSession *session;
Packit Service 37472d
  struct mwServiceStorage *srvc_stor;
Packit Service 37472d
Packit Service 37472d
  g_return_if_fail(srvc != NULL);
Packit Service 37472d
  g_return_if_fail(chan != NULL);
Packit Service 37472d
Packit Service 37472d
  session = mwService_getSession(srvc);
Packit Service 37472d
  g_return_if_fail(session != NULL);
Packit Service 37472d
Packit Service 37472d
  srvc_stor = (struct mwServiceStorage *) srvc;
Packit Service 37472d
  srvc_stor->channel = NULL;
Packit Service 37472d
Packit Service 37472d
  mwService_stop(srvc);
Packit Service 37472d
  mwSession_senseService(session, mwService_getType(srvc));
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void recv(struct mwService *srvc, struct mwChannel *chan,
Packit Service 37472d
		 guint16 type, struct mwOpaque *data) {
Packit Service 37472d
Packit Service 37472d
  /* process into results, trigger callbacks */
Packit Service 37472d
Packit Service 37472d
  struct mwGetBuffer *b;
Packit Service 37472d
  struct mwServiceStorage *srvc_stor;
Packit Service 37472d
  struct mwStorageReq *req;
Packit Service 37472d
  guint32 id;
Packit Service 37472d
Packit Service 37472d
  g_return_if_fail(srvc != NULL);
Packit Service 37472d
  srvc_stor = (struct mwServiceStorage *) srvc;
Packit Service 37472d
Packit Service 37472d
  g_return_if_fail(chan != NULL);
Packit Service 37472d
  g_return_if_fail(chan == srvc_stor->channel);
Packit Service 37472d
  g_return_if_fail(data != NULL);
Packit Service 37472d
Packit Service 37472d
  b = mwGetBuffer_wrap(data);
Packit Service 37472d
Packit Service 37472d
  id = guint32_peek(b);
Packit Service 37472d
  req = request_find(srvc_stor, id);
Packit Service 37472d
Packit Service 37472d
  if(! req) {
Packit Service 37472d
    g_warning("couldn't find request 0x%x in storage service", id);
Packit Service 37472d
    mwGetBuffer_free(b);
Packit Service 37472d
    return;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  g_return_if_fail(req->action == type);
Packit Service 37472d
  request_get(b, req);
Packit Service 37472d
Packit Service 37472d
  if(mwGetBuffer_error(b)) {
Packit Service 37472d
    mw_mailme_opaque(data, "storage request 0x%x, type: 0x%x", id, type);
Packit Service 37472d
Packit Service 37472d
  } else {
Packit Service 37472d
    request_trigger(srvc_stor, req);
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  mwGetBuffer_free(b);
Packit Service 37472d
  request_remove(srvc_stor, req);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void clear(struct mwService *srvc) {
Packit Service 37472d
  struct mwServiceStorage *srvc_stor;
Packit Service 37472d
  GList *l;
Packit Service 37472d
Packit Service 37472d
  srvc_stor = (struct mwServiceStorage *) srvc;
Packit Service 37472d
Packit Service 37472d
  for(l = srvc_stor->pending; l; l = l->next)
Packit Service 37472d
    request_free(l->data);
Packit Service 37472d
Packit Service 37472d
  g_list_free(srvc_stor->pending);
Packit Service 37472d
  srvc_stor->pending = NULL;
Packit Service 37472d
Packit Service 37472d
  srvc_stor->id_counter = 0;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
struct mwServiceStorage *mwServiceStorage_new(struct mwSession *session) {
Packit Service 37472d
  struct mwServiceStorage *srvc_store;
Packit Service 37472d
  struct mwService *srvc;
Packit Service 37472d
Packit Service 37472d
  srvc_store = g_new0(struct mwServiceStorage, 1);
Packit Service 37472d
  srvc = MW_SERVICE(srvc_store);
Packit Service 37472d
Packit Service 37472d
  mwService_init(srvc, session, mwService_STORAGE);
Packit Service 37472d
  srvc->get_name = get_name;
Packit Service 37472d
  srvc->get_desc = get_desc;
Packit Service 37472d
  srvc->recv_accept = recv_channelAccept;
Packit Service 37472d
  srvc->recv_destroy = recv_channelDestroy;
Packit Service 37472d
  srvc->recv = recv;
Packit Service 37472d
  srvc->start = start;
Packit Service 37472d
  srvc->stop = stop;
Packit Service 37472d
  srvc->clear = clear;
Packit Service 37472d
Packit Service 37472d
  return srvc_store;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
struct mwStorageUnit *mwStorageUnit_new(guint32 key) {
Packit Service 37472d
  struct mwStorageUnit *u;
Packit Service 37472d
Packit Service 37472d
  u = g_new0(struct mwStorageUnit, 1);
Packit Service 37472d
  u->key = key;
Packit Service 37472d
Packit Service 37472d
  return u;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
struct mwStorageUnit *mwStorageUnit_newOpaque(guint32 key,
Packit Service 37472d
					      struct mwOpaque *data) {
Packit Service 37472d
  struct mwStorageUnit *u;
Packit Service 37472d
Packit Service 37472d
  u = g_new0(struct mwStorageUnit, 1);
Packit Service 37472d
  u->key = key;
Packit Service 37472d
Packit Service 37472d
  if(data)
Packit Service 37472d
    mwOpaque_clone(&u->data, data);
Packit Service 37472d
Packit Service 37472d
  return u;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
struct mwStorageUnit *mwStorageUnit_newBoolean(guint32 key,
Packit Service 37472d
					       gboolean val) {
Packit Service 37472d
Packit Service 37472d
  return mwStorageUnit_newInteger(key, (guint32) val);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
struct mwStorageUnit *mwStorageUnit_newInteger(guint32 key,
Packit Service 37472d
					       guint32 val) {
Packit Service 37472d
  struct mwStorageUnit *u;
Packit Service 37472d
  struct mwPutBuffer *b;
Packit Service 37472d
Packit Service 37472d
  u = g_new0(struct mwStorageUnit, 1);
Packit Service 37472d
  u->key = key;
Packit Service 37472d
  
Packit Service 37472d
  b = mwPutBuffer_new();
Packit Service 37472d
  guint32_put(b, val);
Packit Service 37472d
  mwPutBuffer_finalize(&u->data, b);
Packit Service 37472d
Packit Service 37472d
  return u;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
struct mwStorageUnit *mwStorageUnit_newString(guint32 key,
Packit Service 37472d
					      const char *str) {
Packit Service 37472d
  struct mwStorageUnit *u;
Packit Service 37472d
  struct mwPutBuffer *b;
Packit Service 37472d
Packit Service 37472d
  u = g_new0(struct mwStorageUnit, 1);
Packit Service 37472d
  u->key = key;
Packit Service 37472d
Packit Service 37472d
  b = mwPutBuffer_new();
Packit Service 37472d
  mwString_put(b, str);
Packit Service 37472d
  mwPutBuffer_finalize(&u->data, b);
Packit Service 37472d
Packit Service 37472d
  return u;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
guint32 mwStorageUnit_getKey(struct mwStorageUnit *item) {
Packit Service 37472d
  g_return_val_if_fail(item != NULL, 0x00); /* feh, unsafe */
Packit Service 37472d
  return item->key;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
gboolean mwStorageUnit_asBoolean(struct mwStorageUnit *item,
Packit Service 37472d
				 gboolean val) {
Packit Service 37472d
Packit Service 37472d
  return !! mwStorageUnit_asInteger(item, (guint32) val);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
guint32 mwStorageUnit_asInteger(struct mwStorageUnit *item,
Packit Service 37472d
				guint32 val) {
Packit Service 37472d
  struct mwGetBuffer *b;
Packit Service 37472d
  guint32 v;
Packit Service 37472d
Packit Service 37472d
  g_return_val_if_fail(item != NULL, val);
Packit Service 37472d
Packit Service 37472d
  b = mwGetBuffer_wrap(&item->data);
Packit Service 37472d
Packit Service 37472d
  guint32_get(b, &v);
Packit Service 37472d
  if(! mwGetBuffer_error(b)) val = v;
Packit Service 37472d
  mwGetBuffer_free(b);
Packit Service 37472d
Packit Service 37472d
  return val;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
char *mwStorageUnit_asString(struct mwStorageUnit *item) {
Packit Service 37472d
  struct mwGetBuffer *b;
Packit Service 37472d
  char *c = NULL;
Packit Service 37472d
Packit Service 37472d
  g_return_val_if_fail(item != NULL, NULL);
Packit Service 37472d
Packit Service 37472d
  b = mwGetBuffer_wrap(&item->data);
Packit Service 37472d
Packit Service 37472d
  mwString_get(b, &c);
Packit Service 37472d
Packit Service 37472d
  if(mwGetBuffer_error(b))
Packit Service 37472d
    g_debug("error obtaining string value from opaque");
Packit Service 37472d
Packit Service 37472d
  mwGetBuffer_free(b);
Packit Service 37472d
Packit Service 37472d
  return c;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
struct mwOpaque *mwStorageUnit_asOpaque(struct mwStorageUnit *item) {
Packit Service 37472d
  g_return_val_if_fail(item != NULL, NULL);
Packit Service 37472d
  return &item->data;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
void mwStorageUnit_free(struct mwStorageUnit *item) {
Packit Service 37472d
  if(! item) return;
Packit Service 37472d
Packit Service 37472d
  mwOpaque_clear(&item->data);
Packit Service 37472d
  g_free(item);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static struct mwStorageReq *request_new(struct mwServiceStorage *srvc,
Packit Service 37472d
					struct mwStorageUnit *item,
Packit Service 37472d
					mwStorageCallback cb,
Packit Service 37472d
					gpointer data, GDestroyNotify df) {
Packit Service 37472d
Packit Service 37472d
  struct mwStorageReq *req = g_new0(struct mwStorageReq, 1);
Packit Service 37472d
Packit Service 37472d
  req->id = ++srvc->id_counter;
Packit Service 37472d
  req->item = item;
Packit Service 37472d
  req->cb = cb;
Packit Service 37472d
  req->data = data;
Packit Service 37472d
  req->data_free = df;
Packit Service 37472d
Packit Service 37472d
  return req;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
void mwServiceStorage_load(struct mwServiceStorage *srvc,
Packit Service 37472d
			   struct mwStorageUnit *item,
Packit Service 37472d
			   mwStorageCallback cb,
Packit Service 37472d
			   gpointer data, GDestroyNotify d_free) {
Packit Service 37472d
Packit Service 37472d
  /* - construct a request
Packit Service 37472d
     - put request at end of pending
Packit Service 37472d
     - if channel is open and connected
Packit Service 37472d
       - compose the load message
Packit Service 37472d
       - send message
Packit Service 37472d
       - set request to sent
Packit Service 37472d
     - else
Packit Service 37472d
       - start service
Packit Service 37472d
  */ 
Packit Service 37472d
Packit Service 37472d
  struct mwStorageReq *req;
Packit Service 37472d
Packit Service 37472d
  req = request_new(srvc, item, cb, data, d_free);
Packit Service 37472d
  req->action = action_load;
Packit Service 37472d
Packit Service 37472d
  srvc->pending = g_list_append(srvc->pending, req);
Packit Service 37472d
Packit Service 37472d
  if(MW_SERVICE_IS_STARTED(MW_SERVICE(srvc)))
Packit Service 37472d
    request_send(srvc->channel, req);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
void mwServiceStorage_save(struct mwServiceStorage *srvc,
Packit Service 37472d
			   struct mwStorageUnit *item,
Packit Service 37472d
			   mwStorageCallback cb,
Packit Service 37472d
			   gpointer data, GDestroyNotify d_free) {
Packit Service 37472d
Packit Service 37472d
  /* - construct a request
Packit Service 37472d
     - put request at end of pending
Packit Service 37472d
     - if channel is open and connected
Packit Service 37472d
       - compose the save message
Packit Service 37472d
       - send message
Packit Service 37472d
       - set request to sent
Packit Service 37472d
     - else
Packit Service 37472d
       - start service
Packit Service 37472d
  */
Packit Service 37472d
Packit Service 37472d
  struct mwStorageReq *req;
Packit Service 37472d
Packit Service 37472d
  req = request_new(srvc, item, cb, data, d_free);
Packit Service 37472d
  req->action = action_save;
Packit Service 37472d
Packit Service 37472d
  srvc->pending = g_list_append(srvc->pending, req);
Packit Service 37472d
Packit Service 37472d
  if(MW_SERVICE_IS_STARTED(MW_SERVICE(srvc)))
Packit Service 37472d
    request_send(srvc->channel, req);
Packit Service 37472d
}
Packit Service 37472d