Blame src/srvc_resolve.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_common.h"
Packit Service 37472d
#include "mw_debug.h"
Packit Service 37472d
#include "mw_error.h"
Packit Service 37472d
#include "mw_service.h"
Packit Service 37472d
#include "mw_session.h"
Packit Service 37472d
#include "mw_srvc_resolve.h"
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
#define PROTOCOL_TYPE  0x00000015
Packit Service 37472d
#define PROTOCOL_VER   0x00000000
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
/** oddly, there is only one message type in this service */
Packit Service 37472d
#define RESOLVE_ACTION  0x02
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
struct mwServiceResolve {
Packit Service 37472d
  struct mwService service;
Packit Service 37472d
Packit Service 37472d
  struct mwChannel *channel;  /**< channel for this service */
Packit Service 37472d
  GHashTable *searches;       /**< guint32:struct mw_search */
Packit Service 37472d
  guint32 counter;            /**< incremented to provide searche IDs */
Packit Service 37472d
};
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
/** structure representing an active search. keeps track of the ID,
Packit Service 37472d
    the handler, and the optional user data and cleanup */
Packit Service 37472d
struct mw_search {
Packit Service 37472d
  struct mwServiceResolve *service;
Packit Service 37472d
  guint32 id;
Packit Service 37472d
  mwResolveHandler handler;
Packit Service 37472d
  gpointer data;
Packit Service 37472d
  GDestroyNotify cleanup;
Packit Service 37472d
};
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static struct mw_search *search_new(struct mwServiceResolve *srvc,
Packit Service 37472d
				    mwResolveHandler handler,
Packit Service 37472d
				    gpointer data, GDestroyNotify cleanup) {
Packit Service 37472d
Packit Service 37472d
  struct mw_search *search = g_new0(struct mw_search, 1);
Packit Service 37472d
Packit Service 37472d
  search->service = srvc;
Packit Service 37472d
  search->handler = handler;
Packit Service 37472d
Packit Service 37472d
  /* we want search IDs that aren't SEARCH_ERROR */
Packit Service 37472d
  do {
Packit Service 37472d
    search->id = srvc->counter++;
Packit Service 37472d
  } while(search->id == SEARCH_ERROR);
Packit Service 37472d
Packit Service 37472d
  search->data = data;
Packit Service 37472d
  search->cleanup = cleanup;
Packit Service 37472d
Packit Service 37472d
  return search;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
/** called whenever a mw_search is removed from the searches table of
Packit Service 37472d
    the service */
Packit Service 37472d
static void search_free(struct mw_search *search) {
Packit Service 37472d
  g_return_if_fail(search != NULL);
Packit Service 37472d
Packit Service 37472d
  if(search->cleanup)
Packit Service 37472d
    search->cleanup(search->data);
Packit Service 37472d
  
Packit Service 37472d
  g_free(search);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static const char *get_name(struct mwService *srvc) {
Packit Service 37472d
  return "Identity Resolution";
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static const char *get_desc(struct mwService *srvc) {
Packit Service 37472d
  return "Resolves short IDs to full IDs";
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static struct mwChannel *make_channel(struct mwServiceResolve *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 mwServiceResolve *srvc) {
Packit Service 37472d
  struct mwChannel *chan;
Packit Service 37472d
Packit Service 37472d
  g_return_if_fail(srvc != NULL);
Packit Service 37472d
Packit Service 37472d
  chan = make_channel(srvc);
Packit Service 37472d
  if(chan) {
Packit Service 37472d
    srvc->channel = chan;
Packit Service 37472d
  } else {
Packit Service 37472d
    mwService_stopped(MW_SERVICE(srvc));
Packit Service 37472d
    return;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  /* semi-lazily create the searches table */
Packit Service 37472d
  srvc->searches = g_hash_table_new_full(g_direct_hash, g_direct_equal,
Packit Service 37472d
					 NULL, (GDestroyNotify) search_free);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void stop(struct mwServiceResolve *srvc) {
Packit Service 37472d
  g_return_if_fail(srvc != NULL);
Packit Service 37472d
Packit Service 37472d
  if(srvc->channel) {
Packit Service 37472d
    mwChannel_destroy(srvc->channel, ERR_SUCCESS, NULL);
Packit Service 37472d
    srvc->channel = NULL;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  /* destroy all the pending requests. */
Packit Service 37472d
  g_hash_table_destroy(srvc->searches);
Packit Service 37472d
  srvc->searches = NULL;
Packit Service 37472d
  
Packit Service 37472d
  mwService_stopped(MW_SERVICE(srvc));
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void clear(struct mwServiceResolve *srvc) {
Packit Service 37472d
  if(srvc->searches) {
Packit Service 37472d
    g_hash_table_destroy(srvc->searches);
Packit Service 37472d
    srvc->searches = NULL;
Packit Service 37472d
  }
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void recv_create(struct mwServiceResolve *srvc,
Packit Service 37472d
			struct mwChannel *chan,
Packit Service 37472d
			struct mwMsgChannelCreate *msg) {
Packit Service 37472d
Packit Service 37472d
  /* you serve me, not the other way around */
Packit Service 37472d
  mwChannel_destroy(chan, ERR_FAILURE, NULL);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void recv_accept(struct mwServiceResolve *srvc,
Packit Service 37472d
			struct mwChannel *chan,
Packit Service 37472d
			struct mwMsgChannelAccept *msg) {
Packit Service 37472d
  
Packit Service 37472d
  g_return_if_fail(srvc != NULL);
Packit Service 37472d
  g_return_if_fail(chan != NULL);
Packit Service 37472d
  g_return_if_fail(chan == srvc->channel);
Packit Service 37472d
Packit Service 37472d
  mwService_started(MW_SERVICE(srvc));
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void recv_destroy(struct mwServiceResolve *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
Packit Service 37472d
  g_return_if_fail(srvc != NULL);
Packit Service 37472d
  g_return_if_fail(chan != NULL);
Packit Service 37472d
  g_return_if_fail(chan == srvc->channel);
Packit Service 37472d
Packit Service 37472d
  srvc->channel = NULL;
Packit Service 37472d
  mwService_stop(MW_SERVICE(srvc));
Packit Service 37472d
Packit Service 37472d
  session = mwService_getSession(MW_SERVICE(srvc));
Packit Service 37472d
  g_return_if_fail(session != NULL);
Packit Service 37472d
Packit Service 37472d
  mwSession_senseService(session, mwService_getType(MW_SERVICE(srvc)));
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static GList *load_matches(struct mwGetBuffer *b, guint32 count) {
Packit Service 37472d
  GList *matches = NULL;
Packit Service 37472d
Packit Service 37472d
  while(count--) {
Packit Service 37472d
    struct mwResolveMatch *m = g_new0(struct mwResolveMatch, 1);
Packit Service 37472d
Packit Service 37472d
    mwString_get(b, &m->id);
Packit Service 37472d
    mwString_get(b, &m->name);
Packit Service 37472d
    mwString_get(b, &m->desc);
Packit Service 37472d
    guint32_get(b, &m->type);
Packit Service 37472d
 
Packit Service 37472d
    matches = g_list_append(matches, m);
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  return matches;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static GList *load_results(struct mwGetBuffer *b, guint32 count) {
Packit Service 37472d
  GList *results = NULL;
Packit Service 37472d
Packit Service 37472d
  while(count--) {
Packit Service 37472d
    struct mwResolveResult *r = g_new0(struct mwResolveResult, 1);
Packit Service 37472d
    guint32 junk, matches;
Packit Service 37472d
Packit Service 37472d
    guint32_get(b, &junk);
Packit Service 37472d
    guint32_get(b, &r->code);
Packit Service 37472d
    mwString_get(b, &r->name);
Packit Service 37472d
Packit Service 37472d
    guint32_get(b, &matches);
Packit Service 37472d
    r->matches = load_matches(b, matches);
Packit Service 37472d
Packit Service 37472d
    results = g_list_append(results, r);
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  return results;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void free_matches(GList *matches) {
Packit Service 37472d
  for(; matches; matches = g_list_delete_link(matches, matches)) {
Packit Service 37472d
    struct mwResolveMatch *m = matches->data;
Packit Service 37472d
    g_free(m->id);
Packit Service 37472d
    g_free(m->name);
Packit Service 37472d
    g_free(m->desc);
Packit Service 37472d
    g_free(m);
Packit Service 37472d
  }
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void free_results(GList *results) {
Packit Service 37472d
  for(; results; results = g_list_delete_link(results, results)) {
Packit Service 37472d
    struct mwResolveResult *r = results->data;
Packit Service 37472d
    g_free(r->name);
Packit Service 37472d
    free_matches(r->matches);
Packit Service 37472d
    g_free(r);
Packit Service 37472d
  }
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void recv(struct mwServiceResolve *srvc,
Packit Service 37472d
		 struct mwChannel *chan,
Packit Service 37472d
		 guint16 type, struct mwOpaque *data) {
Packit Service 37472d
Packit Service 37472d
  struct mwGetBuffer *b;
Packit Service 37472d
  guint32 junk, id, code, count;
Packit Service 37472d
  struct mw_search *search;
Packit Service 37472d
Packit Service 37472d
  g_return_if_fail(srvc != NULL);
Packit Service 37472d
  g_return_if_fail(chan != NULL);
Packit Service 37472d
  g_return_if_fail(chan == srvc->channel);
Packit Service 37472d
  g_return_if_fail(data != NULL);
Packit Service 37472d
Packit Service 37472d
  if(type != RESOLVE_ACTION) {
Packit Service 37472d
    mw_mailme_opaque(data, "unknown message in resolve service: 0x%04x", type);
Packit Service 37472d
    return;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  b = mwGetBuffer_wrap(data);
Packit Service 37472d
  guint32_get(b, &junk);
Packit Service 37472d
  guint32_get(b, &id;;
Packit Service 37472d
  guint32_get(b, &code);
Packit Service 37472d
  guint32_get(b, &count);
Packit Service 37472d
Packit Service 37472d
  if(mwGetBuffer_error(b)) {
Packit Service 37472d
    g_warning("error parsing search result");
Packit Service 37472d
    mwGetBuffer_free(b);
Packit Service 37472d
    return;
Packit Service 37472d
  }
Packit Service 37472d
  
Packit Service 37472d
  search = g_hash_table_lookup(srvc->searches, GUINT_TO_POINTER(id));
Packit Service 37472d
Packit Service 37472d
  if(search) {
Packit Service 37472d
    GList *results = load_results(b, count);
Packit Service 37472d
    if(mwGetBuffer_error(b)) {
Packit Service 37472d
      g_warning("error parsing search results");
Packit Service 37472d
    } else {
Packit Service 37472d
      g_debug("triggering handler");
Packit Service 37472d
      search->handler(srvc, id, code, results, search->data);
Packit Service 37472d
    }
Packit Service 37472d
    free_results(results);
Packit Service 37472d
    g_hash_table_remove(srvc->searches, GUINT_TO_POINTER(id));
Packit Service 37472d
Packit Service 37472d
  } else {
Packit Service 37472d
    g_debug("no search found: 0x%x", id);
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  mwGetBuffer_free(b);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
struct mwServiceResolve *mwServiceResolve_new(struct mwSession *session) {
Packit Service 37472d
  struct mwServiceResolve *srvc_resolve;
Packit Service 37472d
  struct mwService *srvc;
Packit Service 37472d
Packit Service 37472d
  g_return_val_if_fail(session != NULL, NULL);
Packit Service 37472d
Packit Service 37472d
  srvc_resolve = g_new0(struct mwServiceResolve, 1);
Packit Service 37472d
Packit Service 37472d
  srvc = MW_SERVICE(srvc_resolve);
Packit Service 37472d
Packit Service 37472d
  mwService_init(srvc, session, mwService_RESOLVE);
Packit Service 37472d
  srvc->get_name = get_name;
Packit Service 37472d
  srvc->get_desc = get_desc;
Packit Service 37472d
  srvc->recv_create = (mwService_funcRecvCreate) recv_create;
Packit Service 37472d
  srvc->recv_accept = (mwService_funcRecvAccept) recv_accept;
Packit Service 37472d
  srvc->recv_destroy = (mwService_funcRecvDestroy) recv_destroy;
Packit Service 37472d
  srvc->recv = (mwService_funcRecv) recv;
Packit Service 37472d
  srvc->start = (mwService_funcStart) start;
Packit Service 37472d
  srvc->stop = (mwService_funcStop) stop;
Packit Service 37472d
  srvc->clear = (mwService_funcClear) clear;
Packit Service 37472d
Packit Service 37472d
  return srvc_resolve;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
guint32 mwServiceResolve_resolve(struct mwServiceResolve *srvc,
Packit Service 37472d
				 GList *queries, enum mwResolveFlag flags,
Packit Service 37472d
				 mwResolveHandler handler,
Packit Service 37472d
				 gpointer data, GDestroyNotify cleanup) {
Packit Service 37472d
Packit Service 37472d
  struct mw_search *search;
Packit Service 37472d
  struct mwPutBuffer *b;
Packit Service 37472d
  struct mwOpaque o = { 0, 0 };
Packit Service 37472d
  int ret, count = 0;
Packit Service 37472d
Packit Service 37472d
  g_return_val_if_fail(srvc != NULL, SEARCH_ERROR);
Packit Service 37472d
  g_return_val_if_fail(handler != NULL, SEARCH_ERROR);
Packit Service 37472d
Packit Service 37472d
  count = g_list_length(queries);
Packit Service 37472d
  g_return_val_if_fail(count > 0, SEARCH_ERROR);
Packit Service 37472d
Packit Service 37472d
  search = search_new(srvc, handler, data, cleanup);
Packit Service 37472d
Packit Service 37472d
  b = mwPutBuffer_new();
Packit Service 37472d
  guint32_put(b, 0x00); /* to be overwritten */
Packit Service 37472d
  guint32_put(b, search->id);
Packit Service 37472d
  guint32_put(b, count);
Packit Service 37472d
  for(; queries; queries = queries->next)
Packit Service 37472d
    mwString_put(b, queries->data);
Packit Service 37472d
  guint32_put(b, flags);
Packit Service 37472d
Packit Service 37472d
  mwPutBuffer_finalize(&o, b);
Packit Service 37472d
  
Packit Service 37472d
  ret = mwChannel_send(srvc->channel, RESOLVE_ACTION, &o);
Packit Service 37472d
  if(ret) {
Packit Service 37472d
    search_free(search);
Packit Service 37472d
    return SEARCH_ERROR;
Packit Service 37472d
Packit Service 37472d
  } else {
Packit Service 37472d
    g_hash_table_insert(srvc->searches,
Packit Service 37472d
			GUINT_TO_POINTER(search->id), search);
Packit Service 37472d
    return search->id;
Packit Service 37472d
  }
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
void mwServiceResolve_cancelResolve(struct mwServiceResolve *srvc,
Packit Service 37472d
				    guint32 id) {
Packit Service 37472d
Packit Service 37472d
  g_return_if_fail(srvc != NULL);
Packit Service 37472d
  g_return_if_fail(srvc->searches != NULL);
Packit Service 37472d
Packit Service 37472d
  g_hash_table_remove(srvc->searches, GUINT_TO_POINTER(id));
Packit Service 37472d
}
Packit Service 37472d