Blame src/srvc_resolve.c

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