Blame src/srvc_resolve.c.fix-glib-headers

Packit ee6627
Packit ee6627
/*
Packit ee6627
  Meanwhile - Unofficial Lotus Sametime Community Client Library
Packit ee6627
  Copyright (C) 2004  Christopher (siege) O'Brien
Packit ee6627
  
Packit ee6627
  This library is free software; you can redistribute it and/or
Packit ee6627
  modify it under the terms of the GNU Library General Public
Packit ee6627
  License as published by the Free Software Foundation; either
Packit ee6627
  version 2 of the License, or (at your option) any later version.
Packit ee6627
  
Packit ee6627
  This library is distributed in the hope that it will be useful,
Packit ee6627
  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit ee6627
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit ee6627
  Library General Public License for more details.
Packit ee6627
  
Packit ee6627
  You should have received a copy of the GNU Library General Public
Packit ee6627
  License along with this library; if not, write to the Free
Packit ee6627
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Packit ee6627
*/
Packit ee6627
Packit ee6627
#include <glib/ghash.h>
Packit ee6627
Packit ee6627
#include "mw_channel.h"
Packit ee6627
#include "mw_common.h"
Packit ee6627
#include "mw_debug.h"
Packit ee6627
#include "mw_error.h"
Packit ee6627
#include "mw_service.h"
Packit ee6627
#include "mw_session.h"
Packit ee6627
#include "mw_srvc_resolve.h"
Packit ee6627
Packit ee6627
Packit ee6627
#define PROTOCOL_TYPE  0x00000015
Packit ee6627
#define PROTOCOL_VER   0x00000000
Packit ee6627
Packit ee6627
Packit ee6627
/** oddly, there is only one message type in this service */
Packit ee6627
#define RESOLVE_ACTION  0x02
Packit ee6627
Packit ee6627
Packit ee6627
struct mwServiceResolve {
Packit ee6627
  struct mwService service;
Packit ee6627
Packit ee6627
  struct mwChannel *channel;  /**< channel for this service */
Packit ee6627
  GHashTable *searches;       /**< guint32:struct mw_search */
Packit ee6627
  guint32 counter;            /**< incremented to provide searche IDs */
Packit ee6627
};
Packit ee6627
Packit ee6627
Packit ee6627
/** structure representing an active search. keeps track of the ID,
Packit ee6627
    the handler, and the optional user data and cleanup */
Packit ee6627
struct mw_search {
Packit ee6627
  struct mwServiceResolve *service;
Packit ee6627
  guint32 id;
Packit ee6627
  mwResolveHandler handler;
Packit ee6627
  gpointer data;
Packit ee6627
  GDestroyNotify cleanup;
Packit ee6627
};
Packit ee6627
Packit ee6627
Packit ee6627
static struct mw_search *search_new(struct mwServiceResolve *srvc,
Packit ee6627
				    mwResolveHandler handler,
Packit ee6627
				    gpointer data, GDestroyNotify cleanup) {
Packit ee6627
Packit ee6627
  struct mw_search *search = g_new0(struct mw_search, 1);
Packit ee6627
Packit ee6627
  search->service = srvc;
Packit ee6627
  search->handler = handler;
Packit ee6627
Packit ee6627
  /* we want search IDs that aren't SEARCH_ERROR */
Packit ee6627
  do {
Packit ee6627
    search->id = srvc->counter++;
Packit ee6627
  } while(search->id == SEARCH_ERROR);
Packit ee6627
Packit ee6627
  search->data = data;
Packit ee6627
  search->cleanup = cleanup;
Packit ee6627
Packit ee6627
  return search;
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
/** called whenever a mw_search is removed from the searches table of
Packit ee6627
    the service */
Packit ee6627
static void search_free(struct mw_search *search) {
Packit ee6627
  g_return_if_fail(search != NULL);
Packit ee6627
Packit ee6627
  if(search->cleanup)
Packit ee6627
    search->cleanup(search->data);
Packit ee6627
  
Packit ee6627
  g_free(search);
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
static const char *get_name(struct mwService *srvc) {
Packit ee6627
  return "Identity Resolution";
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
static const char *get_desc(struct mwService *srvc) {
Packit ee6627
  return "Resolves short IDs to full IDs";
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
static struct mwChannel *make_channel(struct mwServiceResolve *srvc) {
Packit ee6627
  struct mwSession *session;
Packit ee6627
  struct mwChannelSet *cs;
Packit ee6627
  struct mwChannel *chan;
Packit ee6627
Packit ee6627
  session = mwService_getSession(MW_SERVICE(srvc));
Packit ee6627
  cs = mwSession_getChannels(session);
Packit ee6627
  chan = mwChannel_newOutgoing(cs);
Packit ee6627
 
Packit ee6627
  mwChannel_setService(chan, MW_SERVICE(srvc));
Packit ee6627
  mwChannel_setProtoType(chan, PROTOCOL_TYPE);
Packit ee6627
  mwChannel_setProtoVer(chan, PROTOCOL_VER);
Packit ee6627
Packit ee6627
  return mwChannel_create(chan)? NULL: chan;
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
static void start(struct mwServiceResolve *srvc) {
Packit ee6627
  struct mwChannel *chan;
Packit ee6627
Packit ee6627
  g_return_if_fail(srvc != NULL);
Packit ee6627
Packit ee6627
  chan = make_channel(srvc);
Packit ee6627
  if(chan) {
Packit ee6627
    srvc->channel = chan;
Packit ee6627
  } else {
Packit ee6627
    mwService_stopped(MW_SERVICE(srvc));
Packit ee6627
    return;
Packit ee6627
  }
Packit ee6627
Packit ee6627
  /* semi-lazily create the searches table */
Packit ee6627
  srvc->searches = g_hash_table_new_full(g_direct_hash, g_direct_equal,
Packit ee6627
					 NULL, (GDestroyNotify) search_free);
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
static void stop(struct mwServiceResolve *srvc) {
Packit ee6627
  g_return_if_fail(srvc != NULL);
Packit ee6627
Packit ee6627
  if(srvc->channel) {
Packit ee6627
    mwChannel_destroy(srvc->channel, ERR_SUCCESS, NULL);
Packit ee6627
    srvc->channel = NULL;
Packit ee6627
  }
Packit ee6627
Packit ee6627
  /* destroy all the pending requests. */
Packit ee6627
  g_hash_table_destroy(srvc->searches);
Packit ee6627
  srvc->searches = NULL;
Packit ee6627
  
Packit ee6627
  mwService_stopped(MW_SERVICE(srvc));
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
static void clear(struct mwServiceResolve *srvc) {
Packit ee6627
  if(srvc->searches) {
Packit ee6627
    g_hash_table_destroy(srvc->searches);
Packit ee6627
    srvc->searches = NULL;
Packit ee6627
  }
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
static void recv_create(struct mwServiceResolve *srvc,
Packit ee6627
			struct mwChannel *chan,
Packit ee6627
			struct mwMsgChannelCreate *msg) {
Packit ee6627
Packit ee6627
  /* you serve me, not the other way around */
Packit ee6627
  mwChannel_destroy(chan, ERR_FAILURE, NULL);
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
static void recv_accept(struct mwServiceResolve *srvc,
Packit ee6627
			struct mwChannel *chan,
Packit ee6627
			struct mwMsgChannelAccept *msg) {
Packit ee6627
  
Packit ee6627
  g_return_if_fail(srvc != NULL);
Packit ee6627
  g_return_if_fail(chan != NULL);
Packit ee6627
  g_return_if_fail(chan == srvc->channel);
Packit ee6627
Packit ee6627
  mwService_started(MW_SERVICE(srvc));
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
static void recv_destroy(struct mwServiceResolve *srvc,
Packit ee6627
			 struct mwChannel *chan,
Packit ee6627
			 struct mwMsgChannelDestroy *msg) {
Packit ee6627
Packit ee6627
  struct mwSession *session;
Packit ee6627
Packit ee6627
  g_return_if_fail(srvc != NULL);
Packit ee6627
  g_return_if_fail(chan != NULL);
Packit ee6627
  g_return_if_fail(chan == srvc->channel);
Packit ee6627
Packit ee6627
  srvc->channel = NULL;
Packit ee6627
  mwService_stop(MW_SERVICE(srvc));
Packit ee6627
Packit ee6627
  session = mwService_getSession(MW_SERVICE(srvc));
Packit ee6627
  g_return_if_fail(session != NULL);
Packit ee6627
Packit ee6627
  mwSession_senseService(session, mwService_getType(MW_SERVICE(srvc)));
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
static GList *load_matches(struct mwGetBuffer *b, guint32 count) {
Packit ee6627
  GList *matches = NULL;
Packit ee6627
Packit ee6627
  while(count--) {
Packit ee6627
    struct mwResolveMatch *m = g_new0(struct mwResolveMatch, 1);
Packit ee6627
Packit ee6627
    mwString_get(b, &m->id);
Packit ee6627
    mwString_get(b, &m->name);
Packit ee6627
    mwString_get(b, &m->desc);
Packit ee6627
    guint32_get(b, &m->type);
Packit ee6627
 
Packit ee6627
    matches = g_list_append(matches, m);
Packit ee6627
  }
Packit ee6627
Packit ee6627
  return matches;
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
static GList *load_results(struct mwGetBuffer *b, guint32 count) {
Packit ee6627
  GList *results = NULL;
Packit ee6627
Packit ee6627
  while(count--) {
Packit ee6627
    struct mwResolveResult *r = g_new0(struct mwResolveResult, 1);
Packit ee6627
    guint32 junk, matches;
Packit ee6627
Packit ee6627
    guint32_get(b, &junk);
Packit ee6627
    guint32_get(b, &r->code);
Packit ee6627
    mwString_get(b, &r->name);
Packit ee6627
Packit ee6627
    guint32_get(b, &matches);
Packit ee6627
    r->matches = load_matches(b, matches);
Packit ee6627
Packit ee6627
    results = g_list_append(results, r);
Packit ee6627
  }
Packit ee6627
Packit ee6627
  return results;
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
static void free_matches(GList *matches) {
Packit ee6627
  for(; matches; matches = g_list_delete_link(matches, matches)) {
Packit ee6627
    struct mwResolveMatch *m = matches->data;
Packit ee6627
    g_free(m->id);
Packit ee6627
    g_free(m->name);
Packit ee6627
    g_free(m->desc);
Packit ee6627
    g_free(m);
Packit ee6627
  }
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
static void free_results(GList *results) {
Packit ee6627
  for(; results; results = g_list_delete_link(results, results)) {
Packit ee6627
    struct mwResolveResult *r = results->data;
Packit ee6627
    g_free(r->name);
Packit ee6627
    free_matches(r->matches);
Packit ee6627
    g_free(r);
Packit ee6627
  }
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
static void recv(struct mwServiceResolve *srvc,
Packit ee6627
		 struct mwChannel *chan,
Packit ee6627
		 guint16 type, struct mwOpaque *data) {
Packit ee6627
Packit ee6627
  struct mwGetBuffer *b;
Packit ee6627
  guint32 junk, id, code, count;
Packit ee6627
  struct mw_search *search;
Packit ee6627
Packit ee6627
  g_return_if_fail(srvc != NULL);
Packit ee6627
  g_return_if_fail(chan != NULL);
Packit ee6627
  g_return_if_fail(chan == srvc->channel);
Packit ee6627
  g_return_if_fail(data != NULL);
Packit ee6627
Packit ee6627
  if(type != RESOLVE_ACTION) {
Packit ee6627
    mw_mailme_opaque(data, "unknown message in resolve service: 0x%04x", type);
Packit ee6627
    return;
Packit ee6627
  }
Packit ee6627
Packit ee6627
  b = mwGetBuffer_wrap(data);
Packit ee6627
  guint32_get(b, &junk);
Packit ee6627
  guint32_get(b, &id;;
Packit ee6627
  guint32_get(b, &code);
Packit ee6627
  guint32_get(b, &count);
Packit ee6627
Packit ee6627
  if(mwGetBuffer_error(b)) {
Packit ee6627
    g_warning("error parsing search result");
Packit ee6627
    mwGetBuffer_free(b);
Packit ee6627
    return;
Packit ee6627
  }
Packit ee6627
  
Packit ee6627
  search = g_hash_table_lookup(srvc->searches, GUINT_TO_POINTER(id));
Packit ee6627
Packit ee6627
  if(search) {
Packit ee6627
    GList *results = load_results(b, count);
Packit ee6627
    if(mwGetBuffer_error(b)) {
Packit ee6627
      g_warning("error parsing search results");
Packit ee6627
    } else {
Packit ee6627
      g_debug("triggering handler");
Packit ee6627
      search->handler(srvc, id, code, results, search->data);
Packit ee6627
    }
Packit ee6627
    free_results(results);
Packit ee6627
    g_hash_table_remove(srvc->searches, GUINT_TO_POINTER(id));
Packit ee6627
Packit ee6627
  } else {
Packit ee6627
    g_debug("no search found: 0x%x", id);
Packit ee6627
  }
Packit ee6627
Packit ee6627
  mwGetBuffer_free(b);
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
struct mwServiceResolve *mwServiceResolve_new(struct mwSession *session) {
Packit ee6627
  struct mwServiceResolve *srvc_resolve;
Packit ee6627
  struct mwService *srvc;
Packit ee6627
Packit ee6627
  g_return_val_if_fail(session != NULL, NULL);
Packit ee6627
Packit ee6627
  srvc_resolve = g_new0(struct mwServiceResolve, 1);
Packit ee6627
Packit ee6627
  srvc = MW_SERVICE(srvc_resolve);
Packit ee6627
Packit ee6627
  mwService_init(srvc, session, mwService_RESOLVE);
Packit ee6627
  srvc->get_name = get_name;
Packit ee6627
  srvc->get_desc = get_desc;
Packit ee6627
  srvc->recv_create = (mwService_funcRecvCreate) recv_create;
Packit ee6627
  srvc->recv_accept = (mwService_funcRecvAccept) recv_accept;
Packit ee6627
  srvc->recv_destroy = (mwService_funcRecvDestroy) recv_destroy;
Packit ee6627
  srvc->recv = (mwService_funcRecv) recv;
Packit ee6627
  srvc->start = (mwService_funcStart) start;
Packit ee6627
  srvc->stop = (mwService_funcStop) stop;
Packit ee6627
  srvc->clear = (mwService_funcClear) clear;
Packit ee6627
Packit ee6627
  return srvc_resolve;
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
guint32 mwServiceResolve_resolve(struct mwServiceResolve *srvc,
Packit ee6627
				 GList *queries, enum mwResolveFlag flags,
Packit ee6627
				 mwResolveHandler handler,
Packit ee6627
				 gpointer data, GDestroyNotify cleanup) {
Packit ee6627
Packit ee6627
  struct mw_search *search;
Packit ee6627
  struct mwPutBuffer *b;
Packit ee6627
  struct mwOpaque o = { 0, 0 };
Packit ee6627
  int ret, count = 0;
Packit ee6627
Packit ee6627
  g_return_val_if_fail(srvc != NULL, SEARCH_ERROR);
Packit ee6627
  g_return_val_if_fail(handler != NULL, SEARCH_ERROR);
Packit ee6627
Packit ee6627
  count = g_list_length(queries);
Packit ee6627
  g_return_val_if_fail(count > 0, SEARCH_ERROR);
Packit ee6627
Packit ee6627
  search = search_new(srvc, handler, data, cleanup);
Packit ee6627
Packit ee6627
  b = mwPutBuffer_new();
Packit ee6627
  guint32_put(b, 0x00); /* to be overwritten */
Packit ee6627
  guint32_put(b, search->id);
Packit ee6627
  guint32_put(b, count);
Packit ee6627
  for(; queries; queries = queries->next)
Packit ee6627
    mwString_put(b, queries->data);
Packit ee6627
  guint32_put(b, flags);
Packit ee6627
Packit ee6627
  mwPutBuffer_finalize(&o, b);
Packit ee6627
  
Packit ee6627
  ret = mwChannel_send(srvc->channel, RESOLVE_ACTION, &o);
Packit ee6627
  if(ret) {
Packit ee6627
    search_free(search);
Packit ee6627
    return SEARCH_ERROR;
Packit ee6627
Packit ee6627
  } else {
Packit ee6627
    g_hash_table_insert(srvc->searches,
Packit ee6627
			GUINT_TO_POINTER(search->id), search);
Packit ee6627
    return search->id;
Packit ee6627
  }
Packit ee6627
}
Packit ee6627
Packit ee6627
Packit ee6627
void mwServiceResolve_cancelResolve(struct mwServiceResolve *srvc,
Packit ee6627
				    guint32 id) {
Packit ee6627
Packit ee6627
  g_return_if_fail(srvc != NULL);
Packit ee6627
  g_return_if_fail(srvc->searches != NULL);
Packit ee6627
Packit ee6627
  g_hash_table_remove(srvc->searches, GUINT_TO_POINTER(id));
Packit ee6627
}
Packit ee6627