Merge branch 'master' of git://valera-ext.nynaeve.net/silc into silc.1.1.branch
authorPekka Riikonen <priikone@silcnet.org>
Sat, 22 Nov 2008 16:14:35 +0000 (18:14 +0200)
committerPekka Riikonen <priikone@silcnet.org>
Sat, 22 Nov 2008 16:14:35 +0000 (18:14 +0200)
Code cleanup during merge.

Reverted External IP commit

Reverted changes to silcsocketstream API.  The user context can be now
set to SilcClientConnectionParams.  Increased shared library revision to
avoid backwards incompatiblity.

Signed-off-by: Pekka Riikonen <priikone@silcnet.org>
15 files changed:
1  2 
apps/irssi/src/silc/core/client_ops.c
apps/irssi/src/silc/core/clientutil.c
apps/irssi/src/silc/core/clientutil.h
apps/irssi/src/silc/core/silc-queries.c
apps/irssi/src/silc/core/silc-servers.c
apps/silcd/packet_receive.c
apps/silcd/server.c
apps/silcd/server_util.c
lib/configure.ad
lib/silcclient/client.c
lib/silcclient/client.h
lib/silcclient/client_entry.c
lib/silcclient/silcclient.h
lib/silcske/silcske.c
lib/silcske/silcske_i.h

index 38e90d0844553855d9cc38cc2497756754e37975,2de86781ee02c2339e3728f42678ac95e0e36e01..16feddc7583a8b2c18dd200f736473b2a8ba6d92
@@@ -4,7 -4,7 +4,7 @@@
  
    Author: Pekka Riikonen <priikone@silcnet.org>
  
--  Copyright (C) 2001 - 2007 Pekka Riikonen
++  Copyright (C) 2001 - 2008 Pekka Riikonen
  
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@@ -1438,6 -1439,20 +1439,21 @@@ void silc_getkey_cb(bool success, void 
                       entity, name);
    }
  
 -      * Drop our references as need be.
 -      */
 -  switch (getkey->id_type)
 -  {
 -    case SILC_ID_CLIENT:
 -         silc_client_unref_client(getkey->client, getkey->conn, (SilcClientEntry)getkey->entry);
 -         break;
 -
 -    case SILC_ID_SERVER:
 -         silc_client_unref_server(getkey->client, getkey->conn, (SilcServerEntry)getkey->entry);
 -              break;
+   /*
++   * Drop our references as need be.
++   */
++  switch (getkey->id_type) {
++  case SILC_ID_CLIENT:
++    silc_client_unref_client(getkey->client, getkey->conn,
++                           (SilcClientEntry)getkey->entry);
++    break;
++
++  case SILC_ID_SERVER:
++    silc_client_unref_server(getkey->client, getkey->conn,
++                           (SilcServerEntry)getkey->entry);
++    break;
+   }
    silc_free(getkey);
  }
  
@@@ -2097,6 -2112,19 +2113,18 @@@ void silc_command_reply(SilcClient clie
                ((SilcClientEntry)entry)->nickname :
                ((SilcServerEntry)entry)->server_name);
  
 -      switch (id_type)
 -      {
 -              case SILC_ID_CLIENT:
 -                      name = ((SilcClientEntry)entry)->nickname;
 -                      silc_client_ref_client(client, conn, (SilcClientEntry)entry);
 -                      break;
 -
 -              case SILC_ID_SERVER:
 -                      name = ((SilcServerEntry)entry)->server_name;
 -                      silc_client_ref_server(client, conn, (SilcServerEntry)entry);
 -                      break;
++      switch (id_type) {
++      case SILC_ID_CLIENT:
++        name = ((SilcClientEntry)entry)->nickname;
++        silc_client_ref_client(client, conn, (SilcClientEntry)entry);
++        break;
++
++      case SILC_ID_SERVER:
++        name = ((SilcServerEntry)entry)->server_name;
++        silc_client_ref_server(client, conn, (SilcServerEntry)entry);
++        break;
+       }
        silc_verify_public_key_internal(client, conn, name,
                                        (id_type == SILC_ID_CLIENT ?
                                         SILC_CONN_CLIENT :
@@@ -2366,11 -2394,13 +2394,13 @@@ typedef struct 
    void *context;
  } *PublicKeyVerify;
  
- static void verify_public_key_completion(const char *line, void *context)
+ static void verify_public_key_completion(const char *line, void *context,
 -              SilcKeyboardPromptStatus reason)
++                                       SilcKeyboardPromptStatus reason)
  {
    PublicKeyVerify verify = (PublicKeyVerify)context;
 -  bool success = (reason == KeyboardCompletionSuccess);
++  SilcBool success = (reason == KeyboardCompletionSuccess);
  
-   if (line[0] == 'Y' || line[0] == 'y') {
+   if (success && (line[0] == 'Y' || line[0] == 'y')) {
      /* Call the completion */
      if (verify->completion)
        verify->completion(TRUE, verify->context);
                       verify->entity);
    }
  
 -
 -  if (reason != KeyboardCompletionFailed)
 -  {
+   /*
+    * If we were not called due to a failure to begin the callback, then we
+    * shall zero the async context block in the server record.  If we were
+    * called due to a failure to begin the callback, then it is possible that
+    * we failed due to an overlapping callback, in which case we shouldn't
+    * overwrite the async context block pointer.
+    */
 -        * Null out the completion context in the server record as this operation
 -        * is done as far as we are concerned.  The underlying keyboard library
 -        * routine will take care of freeing the async context memory when the
 -        * actual callback is called by irssi in the abort case.  In the success
 -        * case, it will free the async context memory after we return from this
 -        * routine.
 -        */
 -
 -     SILC_SERVER_REC *server = (SILC_SERVER_REC*)(verify->conn->context);
 -
 -        server->prompt_op = NULL;
++  if (reason != KeyboardCompletionFailed) {
+     /*
++     * Null out the completion context in the server record as this operation
++     * is done as far as we are concerned.  The underlying keyboard library
++     * routine will take care of freeing the async context memory when the
++     * actual callback is called by irssi in the abort case.  In the success
++     * case, it will free the async context memory after we return from this
++     * routine.
++     */
++    SILC_SERVER_REC *server = (SILC_SERVER_REC*)(verify->conn->context);
++    server->prompt_op = NULL;
+   }
    silc_free(verify->filename);
    silc_free(verify->entity);
    silc_free(verify->entity_name);
@@@ -2423,6 -2478,51 +2474,14 @@@ silc_verify_public_key_internal(SilcCli
                  "server" : "client");
    int i;
  
 -
 -  /*
 -      * If we don't have a context yet, then we'll set it up based on the
 -      * stream context associated with the SilcPacketStream that is attached
 -      * to the SilcClientConnection.  This is a bit ugly, but we need to have a
 -      * per-connection context value to perform the public key verify operation,
 -      * and the public API was not designed to let us have this in a particularly
 -      * straightforward fashion.
 -      */
 -
+   server = (SILC_SERVER_REC*)conn->context;
 -    SilcPacketStream packet_stream;
 -       SilcStream       stream;
 -
 -    packet_stream = conn->stream;
 -
 -       if (!packet_stream)
 -    {
 -      if (completion)
 -        completion(FALSE, context);
 -      return;
 -    }
 -
 -    stream        = silc_packet_stream_get_stream(packet_stream);
 -
 -    if (!stream)
 -    {
 -      if (completion)
 -        completion(FALSE, context);
 -      return;
 -    }
 -
 -    server        = (SILC_SERVER_REC*)(silc_socket_stream_get_context(stream));
 -
 -    if (!server)
 -    {
 -      if (completion)
 -        completion(FALSE, context);
 -      return;
 -    }
 -
 -    conn->context = (void *)server;
++  SILC_VERIFY(server);
+   if (!server) {
++    if (completion)
++      completion(FALSE, context);
++    return;
+   }
    if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC) {
      printformat_module("fe-common/silc", NULL, NULL,
                       MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
@@@ -2676,25 -2777,37 +2736,43 @@@ typedef struct 
    void *context;
  } *AskPassphrase;
  
- void ask_passphrase_completion(const char *passphrase, void *context)
+ void ask_passphrase_completion(const char *passphrase, void *context,
 -              SilcKeyboardPromptStatus reason)
++                             SilcKeyboardPromptStatus reason)
  {
    AskPassphrase p = (AskPassphrase)context;
    if (passphrase && passphrase[0] == '\0')
      passphrase = NULL;
    p->completion((unsigned char *)passphrase,
                passphrase ? strlen(passphrase) : 0, p->context);
 -  if (reason != KeyboardCompletionFailed)
 -  {
 -
 -       server->prompt_op = NULL;
++  if (reason != KeyboardCompletionFailed) {
+     SILC_SERVER_REC *server = (SILC_SERVER_REC *)(p->conn->context);
++    server->prompt_op = NULL;
+   }
    silc_free(p);
  }
  
  void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
                         SilcAskPassphrase completion, void *context)
  {
-   AskPassphrase p = silc_calloc(1, sizeof(*p));
+   SILC_SERVER_REC *server = (SILC_SERVER_REC*)(conn->context);
 -  AskPassphrase p = silc_calloc(1, sizeof(*p));
 - 
++  AskPassphrase p;
++
++  p = silc_calloc(1, sizeof(*p));
++  if (!p) {
++    if (completion)
++      completion(NULL, 0, context);
++    return;
++  }
++
    p->completion = completion;
-   p->context = context;
+   p->conn       = conn;
+   p->context    = context;
  
-   keyboard_entry_redirect((SIGNAL_FUNC)ask_passphrase_completion,
-                         "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
+   silc_keyboard_entry_redirect(ask_passphrase_completion,
 -                        "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p, &server->prompt_op);
++                             "Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN,
++                             p, &server->prompt_op);
  }
  
  typedef struct {
index 836347338a3457deaa8af281f5d37ef4d6775dc1,9a04df914c79175e29f8a773baf52db31340d202..66c8eb9a987e9c617ac9eef0d0836f1ff9dee1c2
@@@ -4,7 -4,7 +4,7 @@@
  
    Author: Pekka Riikonen <priikone@silcnet.org>
  
--  Copyright (C) 1997 - 2006 Pekka Riikonen
++  Copyright (C) 1997 - 2006, 2008 Pekka Riikonen
  
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@@ -341,7 -341,7 +341,7 @@@ int silc_client_load_keys(SilcClient cl
  {
    char pub[256], prv[256];
    struct passwd *pw;
--  bool ret;
++  SilcBool ret;
  
    SILC_LOG_DEBUG(("Loading public and private keys"));
  
    return ret;
  }
  
 -static bool silc_keyboard_prompt_pending;
++static SilcBool silc_keyboard_prompt_pending;
 -typedef struct
 -{
 -      SilcAsyncOperation async_context;
 -      SILC_KEYBOARD_PROMPT_PROC user_prompt_proc;
 -      void *user_context;
 -      bool aborted;
 -      bool *immediate_completion;
 -} * SilcKeyboardEntryRedirectContext;
 -
 -static void silc_keyboard_entry_redirect_abort(
 -      SilcAsyncOperation op,
 -      void *context)
 -{
 -      SilcKeyboardEntryRedirectContext ctx = (SilcKeyboardEntryRedirectContext)context;
 -
 -      /*
 -       * Flag ourselves as aborted so the irssi callback doesn't do any real
 -       * work here.
 -       */
 -
 -      ctx->aborted = TRUE;
 -
 -      /*
 -       * Call the user routine to notify it that we are aborting, so that it may
 -       * clean up anything that needs cleaning up, e.g. references.  The user
 -       * may not reference the SilcAsyncOperation beyond this abort call.  The
 -       * recommended procedure is for the user prompt routine to null out its
 -       * reference to the SilcAsyncOperation context.  The underlying context
 -       * structure will be released when the actual wrappered callback fires,
 -       * though the wrappered callback will not call into user code now that
 -       * the operation has been aborted.
 -       */
 -
 -      ctx->user_prompt_proc(NULL, ctx->user_context, KeyboardCompletionAborted);
 -}
++typedef struct {
++  SilcAsyncOperation async_context;
++  SILC_KEYBOARD_PROMPT_PROC user_prompt_proc;
++  void *user_context;
++  SilcBool aborted;
++  SilcBool *immediate_completion;
++} *SilcKeyboardEntryRedirectContext;
 -static void silc_keyboard_entry_redirect_completion(
 -      const char *line,
 -      void *context)
++static void silc_keyboard_entry_redirect_abort(SilcAsyncOperation op,
++                                             void *context)
+ {
 -      SilcKeyboardEntryRedirectContext ctx = (SilcKeyboardEntryRedirectContext)context;
 -
 -      /*
 -       * If we are aborted, then don't call the user routine.  Note that we
 -       * already notified the user that they were aborted when the abort
 -       * call was made in the first place, so the user should not have any
 -       * dangling references at this point.
 -       *
 -       * Otherwise, call the user routine.
 -       */
 -
 -      if (!ctx->aborted)
 -      {
 -              ctx->user_prompt_proc(line, ctx->user_context,
 -                              KeyboardCompletionSuccess);
 -      }
++  SilcKeyboardEntryRedirectContext ctx = context;
 -      /*
 -       * If there's a flag to set on completion, such that we can detect when the
 -       * operation finished immediately instead of being processed as a callback,
 -       * then set that now.
 -       */
++  /*
++   * Flag ourselves as aborted so the irssi callback doesn't do any real
++   * work here.
++   */
++  ctx->aborted = TRUE;
 -      if (ctx->immediate_completion)
 -              *ctx->immediate_completion = TRUE;
++  /*
++   * Call the user routine to notify it that we are aborting, so that it may
++   * clean up anything that needs cleaning up, e.g. references.  The user
++   * may not reference the SilcAsyncOperation beyond this abort call.  The
++   * recommended procedure is for the user prompt routine to null out its
++   * reference to the SilcAsyncOperation context.  The underlying context
++   * structure will be released when the actual wrappered callback fires,
++   * though the wrappered callback will not call into user code now that
++   * the operation has been aborted.
++   */
++  ctx->user_prompt_proc(NULL, ctx->user_context, KeyboardCompletionAborted);
++}
 -      /*
 -       * Clean up our internal context structures.  Note that we are considered
 -       * responsible for handling the SilcAsyncOperation release in this model,
 -       * unless we were aborted, in which case the abort request has released it.
 -       */
++static void silc_keyboard_entry_redirect_completion(const char *line,
++                                                  void *context)
++{
++  SilcKeyboardEntryRedirectContext ctx = context;
 -      if (!ctx->aborted)
 -              silc_async_free(ctx->async_context);
++  /*
++   * If we are aborted, then don't call the user routine.  Note that we
++   * already notified the user that they were aborted when the abort
++   * call was made in the first place, so the user should not have any
++   * dangling references at this point.
++   *
++   * Otherwise, call the user routine.
++   */
++  if (!ctx->aborted) {
++    ctx->user_prompt_proc(line, ctx->user_context,
++                        KeyboardCompletionSuccess);
++  }
 -      silc_free(ctx);
++  /*
++   * If there's a flag to set on completion, such that we can detect when the
++   * operation finished immediately instead of being processed as a callback,
++   * then set that now.
++   */
++  if (ctx->immediate_completion)
++    *ctx->immediate_completion = TRUE;
++
++  /*
++   * Clean up our internal context structures.  Note that we are considered
++   * responsible for handling the SilcAsyncOperation release in this model,
++   * unless we were aborted, in which case the abort request has released it.
++   */
++  if (!ctx->aborted)
++    silc_async_free(ctx->async_context);
 -      /*
 -       * Mark us as not having a keyboard prompt pending.
 -       */
++  silc_free(ctx);
 -      silc_keyboard_prompt_pending = FALSE;
++  /*
++   * Mark us as not having a keyboard prompt pending.
++   */
++  silc_keyboard_prompt_pending = FALSE;
+ }
+ /* Prompt for user input. */
 -bool silc_keyboard_entry_redirect(
 -      SILC_KEYBOARD_PROMPT_PROC prompt_func,
 -      const char *entry,
 -      int flags,
 -      void *data,
 -      SilcAsyncOperation *async)
++SilcBool silc_keyboard_entry_redirect(SILC_KEYBOARD_PROMPT_PROC prompt_func,
++                                    const char *entry,
++                                    int flags,
++                                    void *data,
++                                    SilcAsyncOperation *async)
+ {
 -      SilcKeyboardEntryRedirectContext ctx;
 -      bool                             completed_now;
 -
 -      /*
 -       * Check if we already have a keyboard prompt pending.  This sucks, but
 -       * irssi stores the keyboard prompt data in a global, and if we request
 -       * a prompt while there is already a prompt in progress, the old prompt
 -       * data is leaked.  If irssi gets its act together, this can (and should)
 -       * go away.
 -       */
 -
 -      if (silc_keyboard_prompt_pending)
 -      {
 -              prompt_func(NULL, data, KeyboardCompletionFailed);
 -              return FALSE;
 -      }
++  SilcKeyboardEntryRedirectContext ctx;
++  SilcBool completed_now;
++
++  /*
++   * Check if we already have a keyboard prompt pending.  This sucks, but
++   * irssi stores the keyboard prompt data in a global, and if we request
++   * a prompt while there is already a prompt in progress, the old prompt
++   * data is leaked.  If irssi gets its act together, this can (and should)
++   * go away.
++   */
++  if (silc_keyboard_prompt_pending) {
++    prompt_func(NULL, data, KeyboardCompletionFailed);
++    return FALSE;
++  }
 -      /*
 -       * Allocate our context blocks.
 -       */
++  /*
++   * Allocate our context blocks.
++   */
++  ctx = (SilcKeyboardEntryRedirectContext)silc_calloc(1, sizeof(*ctx));
++  if (!ctx) {
++    prompt_func(NULL, data, KeyboardCompletionFailed);
++    return FALSE;
++  }
 -      ctx = (SilcKeyboardEntryRedirectContext)silc_calloc(1, sizeof(*ctx));
++  ctx->async_context = silc_async_alloc(silc_keyboard_entry_redirect_abort,
++                                      NULL, ctx);
++  if (!ctx->async_context) {
++    silc_free(ctx);
++    prompt_func(NULL, data, KeyboardCompletionFailed);
++    return FALSE;
++  }
 -      if (!ctx)
 -      {
 -              prompt_func(NULL, data, KeyboardCompletionFailed);
 -              return FALSE;
 -      }
++  /*
++   * Initially, we don't consider ourselves as having finished.
++   */
++  completed_now = FALSE;
 -      ctx->async_context = silc_async_alloc(silc_keyboard_entry_redirect_abort,
 -                      NULL, ctx);
++  /*
++   * Since irssi can't handle overlapping keyboard prompt requests, block
++   * future requests until we are finished.  N.B. This should really be
++   * handled inside of irssi, but this requires a breaking change to how
++   * keyboard callbacks are processed from an API perspective.  A problem
++   * exists where another user could call a keyboard redirect request
++   * external to silc while we have one pending, and cause ours to get
++   * lost, in which case we will get stuck denying future prompt requests.
++   *
++   * Fortunately, nobody else seems to use keyboard prompt requests, at least
++   * not that I can tell.
++   */
++  silc_keyboard_prompt_pending = TRUE;
 -      if (!ctx->async_context)
 -      {
 -              silc_free(ctx);
 -              prompt_func(NULL, data, KeyboardCompletionFailed);
 -              return FALSE;
 -      }
++  /*
++   * Set up the call to the irssi keyboard entry redirection facility.
++   */
 -      /*
 -       * Initially, we don't consider ourselves as having finished.
 -       */
 -
 -      completed_now = FALSE;
 -
 -      /*
 -       * Since irssi can't handle overlapping keyboard prompt requests, block
 -       * future requests until we are finished.  N.B. This should really be
 -       * handled inside of irssi, but this requires a breaking change to how
 -       * keyboard callbacks are processed from an API perspective.  A problem
 -       * exists where another user could call a keyboard redirect request
 -       * external to silc while we have one pending, and cause ours to get
 -       * lost, in which case we will get stuck denying future prompt requests.
 -       *
 -       * Fortunately, nobody else seems to use keyboard prompt requests, at least
 -       * not that I can tell.
 -       */
 -
 -      silc_keyboard_prompt_pending = TRUE;
 -
 -      /*
 -       * Set up the call to the irssi keyboard entry redirection facility.
 -       */
 -
 -      ctx->user_prompt_proc     = prompt_func;
 -      ctx->user_context         = data;
 -      ctx->aborted              = FALSE;
 -      ctx->immediate_completion = &completed_now;
 -
 -      keyboard_entry_redirect((SIGNAL_FUNC)silc_keyboard_entry_redirect_completion,
 -                      entry, 0, ctx);
 -
 -      ctx->immediate_completion = NULL;
 -
 -      /* 
 -       * If we completed immediately, then there is nothing to return as the async
 -       * context has already been released.  In this case we have completed with a
 -       * success status, but there is no SilcAsyncOperation context to return.
 -       */
 -
 -      if (completed_now)
 -      {
 -              *async = NULL;
 -              return TRUE;
 -      }
++  ctx->user_prompt_proc     = prompt_func;
++  ctx->user_context         = data;
++  ctx->aborted              = FALSE;
++  ctx->immediate_completion = &completed_now;
 -      /*
 -       * Otherwise, we must return an async operation context to the caller, and
 -       * we must unset the immediate_completion flag as we don't want to be
 -       * notified anymore since we're returning out.  Note that this is not safe
 -       * if keyboard_entry_redirect can call from a different thread, but we are
 -       * assuming that it doesn't as there's already many other things that seem
 -       * to make this assumption.
 -       */
++  keyboard_entry_redirect((SIGNAL_FUNC)silc_keyboard_entry_redirect_completion,
++                        entry, 0, ctx);
 -      *async = ctx->async_context;
++  ctx->immediate_completion = NULL;
++
++  /*
++   * If we completed immediately, then there is nothing to return as the async
++   * context has already been released.  In this case we have completed with a
++   * success status, but there is no SilcAsyncOperation context to return.
++   */
++  if (completed_now) {
++    *async = NULL;
++    return TRUE;
++  }
 -      /*
 -       * All done.  Irssi will invoke the callback on this thread at a later point
 -       * in time.
 -       */
++  /*
++   * Otherwise, we must return an async operation context to the caller, and
++   * we must unset the immediate_completion flag as we don't want to be
++   * notified anymore since we're returning out.  Note that this is not safe
++   * if keyboard_entry_redirect can call from a different thread, but we are
++   * assuming that it doesn't as there's already many other things that seem
++   * to make this assumption.
++   */
++  *async = ctx->async_context;
 -      return TRUE;
++  /*
++   * All done.  Irssi will invoke the callback on this thread at a later point
++   * in time.
++   */
++  return TRUE;
+ }
  #ifdef SILC_PLUGIN
  void create_key_passphrase(const char *answer, CREATE_KEY_REC *rec)
  {
index 240100a600ed6d9b3c4dfedc82d66d82e7ba4af6,dc60a0499b299363599bb39636d04f4a2e72e2b9..4b925f2f6ea2af84d29c0adfa417686dbe1f16a3
@@@ -4,13 -4,13 +4,13 @@@
  
    Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
  
--  Copyright (C) 1997 - 2000 Pekka Riikonen
++  Copyright (C) 1997 - 2000, 2008 Pekka Riikonen
  
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.
--  
++
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
@@@ -31,6 -31,64 +31,61 @@@ void silc_client_list_pkcs()
  int silc_client_check_silc_dir();
  int silc_client_load_keys(SilcClient client);
  
 -typedef enum
 -{
 -      KeyboardCompletionSuccess, /* Success; keyboard data returned to callback. */
 -      KeyboardCompletionAborted, /* Operation was aborted after starting successfully. */
 -      KeyboardCompletionFailed /* Operation was not started successfully. */
++typedef enum {
++  KeyboardCompletionSuccess, /* Success; keyboard data returned to callback. */
++  KeyboardCompletionAborted, /* Operation was aborted after starting successfully. */
++  KeyboardCompletionFailed /* Operation was not started successfully. */
+ } SilcKeyboardPromptStatus;
 -typedef void (*SILC_KEYBOARD_PROMPT_PROC)(
 -      const char *line,
 -      void *context,
 -      SilcKeyboardPromptStatus reason);
++typedef void (*SILC_KEYBOARD_PROMPT_PROC)(const char *line,
++                                        void *context,
++                                        SilcKeyboardPromptStatus reason);
+ /*
+  * Prompt for keyboard input.
+  *
+  * If the function returns FALSE, then the prompt operation could not be
+  * initiated and the user supplied callback is called to indicate that the
+  * operation was not started (reason KeyboardCompletionFailed).  This can be
+  * used to centralize all cleanup work in the callback function.
+  *
+  * If the function returns TRUE, then the operation was initiated successfully
+  * and the prompt callback is guaranteed to be called sometime in the future.
+  * Note that it is posssible for the completion callback to have been already
+  * called by the time the function returns TRUE.  In this instance, the
+  * callback will eventually be called with KeyboardCompletionSuccess, unless
+  * the operation is aborted before then.
+  *
+  * If the function returns TRUE, then a SilcAsyncOperation context may be
+  * returned.  If an async operation context is returned, then the operation has
+  * not been completed immediately, and may be canceled with a call to
+  * silc_async_abort(*async).
+  *
+  * Note that the SilcAsyncOperation object's lifetime is managed internally.  A
+  * user may call silc_async_abort exactly once, after which it can never touch
+  * the async context again.  Additionally, the async context may not be
+  * referenced after the user callback returns.  The recommended way to handle
+  * the async operation context is to remove the reference to it when the user
+  * callback is called, either for an abort or regular completion.  If the
+  * callback is called with a KeyboardCompletionFailed reason, then no async
+  * context object was allocated.
+  *
+  * If an abort is requested, then the user callback is called with reason code
+  * KeyboardCompletionAborted.  In this case, the user should clean up all
+  * associated callback data and perform the handling expected in the abort case,
+  * such as the associated server connection going away while the operation was
+  * in progress.
+  *
+  * There can only be one keyboard redirect operation in progress.  If a
+  * keyboard redirect operation is aborted while we are still waiting for data,
+  * then we abort all callbacks until that callback returns.
+  */
 -bool silc_keyboard_entry_redirect(
 -      SILC_KEYBOARD_PROMPT_PROC prompt_func,
 -      const char *entry,
 -      int flags,
 -      void *data,
 -      SilcAsyncOperation *async);
++SilcBool silc_keyboard_entry_redirect(SILC_KEYBOARD_PROMPT_PROC prompt_func,
++                                    const char *entry,
++                                    int flags,
++                                    void *data,
++                                    SilcAsyncOperation *async);
  #ifdef SILC_PLUGIN
  typedef struct {
    char *old, *passphrase, *file, *pkcs;
index 1e7f75132230b18e746d7825f4ed9b32c89f8883,0da01d6b6918a9c6eec30a4a08c5ab4d395dbc82..ec29a2f32df8ffb85509834b69c010520d23139e
@@@ -4,7 -4,7 +4,7 @@@
  
    Author: Pekka Riikonen <priikone@silcnet.org>
  
--  Copyright (C) 2002 - 2007 Pekka Riikonen
++  Copyright (C) 2002 - 2008 Pekka Riikonen
  
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@@ -32,8 -33,9 +33,9 @@@
  #include "fe-common/core/keyboard.h"
  #include "fe-common/silc/module-formats.h"
  
--static void silc_query_attributes_print_final(bool success, void *context);
- static void silc_query_attributes_accept(const char *line, void *context);
++static void silc_query_attributes_print_final(SilcBool success, void *context);
+ static void silc_query_attributes_accept(const char *line, void *context,
+               SilcKeyboardPromptStatus reason);
  
  QUERY_REC *silc_query_create(const char *server_tag,
                             const char *nick, int automatic)
@@@ -68,7 -70,7 +70,7 @@@ void command_attr(const char *data, SIL
    SilcUInt32 argc;
    SilcUInt32 *argv_lens, *argv_types;
    const char *sv;
--  bool allowed;
++  SilcBool allowed;
  
    /* Now parse all arguments */
    tmp = g_strconcat("ATTR", " ", data, NULL);
@@@ -252,7 -254,7 +254,7 @@@ void silc_query_attributes_default(Silc
    SilcAttributeObjDevice dev;
    SilcAttributeObjPk pk;
    SilcVCardStruct vcard;
--  bool allowed;
++  SilcBool allowed;
  
    memset(&service, 0, sizeof(service));
    memset(&geo, 0, sizeof(geo));
@@@ -557,7 -559,8 +559,8 @@@ typedef struct 
    SilcVCardStruct vcard;
    SilcMime message;
    SilcMime extension;
--  bool nopk;
 -  bool autoaccept;
++  SilcBool nopk;
++  SilcBool autoaccept;
  } *AttrVerify;
  
  void silc_query_attributes_print(SILC_SERVER_REC *server,
    }
  }
  
--static void silc_query_attributes_print_final(bool success, void *context)
++static void silc_query_attributes_print_final(SilcBool success, void *context)
  {
    AttrVerify verify = context;
    SILC_SERVER_REC *server = verify->server;
      /* Ask to accept save requested attributes */
      format = format_get_text("fe-common/silc", NULL, NULL, NULL,
                             SILCTXT_ATTR_SAVE);
-     keyboard_entry_redirect((SIGNAL_FUNC)silc_query_attributes_accept,
-                           format, 0, verify);
+     silc_keyboard_entry_redirect(silc_query_attributes_accept,
+                           format, 0, verify, &server->prompt_op);
    } else {
      /* Save new data to existing directory */
-     silc_query_attributes_accept("Y", verify);
 -       verify->autoaccept = TRUE; /* Ensure we don't twiddle the async context */
++    verify->autoaccept = TRUE; /* Ensure we don't twiddle the async context */
+     silc_query_attributes_accept("Y", verify, KeyboardCompletionSuccess);
    }
  
    g_free(format);
@@@ -978,8 -987,9 +987,9 @@@ static void silc_query_attributes_accep
    unsigned char filename[256], filename2[256], *fingerprint = NULL, *tmp;
    SilcUInt32 len;
    int i;
 -  bool success = (reason == KeyboardCompletionSuccess);
++  SilcBool success = (reason == KeyboardCompletionSuccess);
  
-   if (line[0] == 'Y' || line[0] == 'y') {
+   if (success && (line[0] == 'Y' || line[0] == 'y')) {
      /* Save the attributes */
      memset(filename, 0, sizeof(filename));
      memset(filename2, 0, sizeof(filename2));
index e16fb02cdc056fef1116a982f49259c3bf0d7483,e763b8eef2f9c6792738b275458709ab38de4224..9dd1c8e25030a81b18c99fcef6c70540e3c327fd
@@@ -1,7 -1,7 +1,7 @@@
  /*
    silc-server.c : irssi
  
--  Copyright (C) 2000 - 2007 Timo Sirainen
++  Copyright (C) 2000 - 2008 Timo Sirainen
                              Pekka Riikonen <priikone@silcnet.org>
  
    This program is free software; you can redistribute it and/or modify
@@@ -415,6 -415,6 +415,7 @@@ static void sig_connected_stream_create
    params.timeout_secs = settings_get_int("key_exchange_timeout_secs");
    params.rekey_secs = settings_get_int("key_exchange_rekey_secs");
    params.pfs = settings_get_bool("key_exchange_rekey_pfs");
++  params.context = server;
  
    /* Try to read detached session data and use it if found. */
    file = silc_get_session_filename(server);
@@@ -466,6 -482,12 +467,12 @@@ static void sig_disconnected(SILC_SERVE
    if (!IS_SILC_SERVER(server))
      return;
  
 -       server->prompt_op = NULL;
+   /* If we have a prompt in progress, then abort it. */
+   if (server->prompt_op) {
+     silc_async_abort(server->prompt_op, NULL, NULL);
++    server->prompt_op = NULL;
+   }
    if (server->conn) {
      /* Close connection */
      silc_client_close_connection(silc_client, server->conn);
index 73424a68988fe7b2016030d9c8de39bb8f33b7a9,06e5bcd9161431a807f2b264523c292a9198875a..ab174e4f5d000140e18aac2b179e83316b0c2675
@@@ -326,6 -327,7 +326,7 @@@ static void silc_server_notify_process(
        tmp_len = 128;
  
      /* Update statistics */
 -      assert(server->stat.clients > 0);
++    SILC_VERIFY(server->stat.clients > 0);
      server->stat.clients--;
      if (server->stat.cell_clients)
        server->stat.cell_clients--;
            }
  
            /* Update statistics */
 -              assert(server->stat.clients > 0);
++          SILC_VERIFY(server->stat.clients > 0);
            server->stat.clients--;
            if (server->stat.cell_clients)
              server->stat.cell_clients--;
        }
  
        /* Update statistics */
 -        assert(server->stat.clients > 0);
++      SILC_VERIFY(server->stat.clients > 0);
        server->stat.clients--;
        if (server->stat.cell_clients)
        server->stat.cell_clients--;
@@@ -3733,6 -3737,7 +3736,7 @@@ void silc_server_resume_client(SilcServ
  
      /* Delete this current client entry since we're resuming to old one. */
      server->stat.my_clients--;
 -      assert(server->stat.clients > 0);
++    SILC_VERIFY(server->stat.clients > 0);
      server->stat.clients--;
      if (server->stat.cell_clients)
        server->stat.cell_clients--;
index 0e1cffb084ddac0918c65e38d35bcd17a0e4c0ef,0da85e541dd5f68025715da27cc3bb821bbfd00b..c9825e008959d76a531aa30356dc2e8ddd830551
@@@ -3129,6 -3136,7 +3131,7 @@@ void silc_server_free_client_data(SilcS
  
    /* Update statistics */
    server->stat.my_clients--;
 -  assert(server->stat.clients > 0);
++  SILC_VERIFY(server->stat.clients > 0);
    server->stat.clients--;
    if (server->stat.cell_clients)
      server->stat.cell_clients--;
index 74ce18ba2902866107148517f3f961fe645dd714,28e33ed15d73d0d93d567853d4378ab8f2cbf1a4..9bcc47b20377b5c8c5acd8a0152dce1ca08d1656
@@@ -119,7 -120,7 +119,7 @@@ silc_server_remove_clients_channels(Sil
        silc_hash_table_add(channels, channel, channel);
    }
    silc_hash_table_list_reset(&htl);
--  assert(!silc_hash_table_count(client->channels));
++  SILC_VERIFY(!silc_hash_table_count(client->channels));
  }
  
  /* This function removes all client entries that are originated from
@@@ -205,6 -206,7 +205,7 @@@ SilcBool silc_server_remove_clients_by_
        }
  
        /* Update statistics */
 -        assert(server->stat.clients > 0);
++      SILC_VERIFY(server->stat.clients > 0);
        server->stat.clients--;
        if (server->stat.cell_clients)
        server->stat.cell_clients--;
        }
  
        /* Update statistics */
 -        assert(server->stat.clients > 0);
++      SILC_VERIFY(server->stat.clients > 0);
        server->stat.clients--;
        if (server->stat.cell_clients)
        server->stat.cell_clients--;
@@@ -1560,6 -1563,7 +1562,7 @@@ void silc_server_kill_client(SilcServe
      }
    } else {
      /* Update statistics */
 -      assert(server->stat.clients > 0);
++    SILC_VERIFY(server->stat.clients > 0);
      server->stat.clients--;
      if (server->stat.cell_clients)
        server->stat.cell_clients--;
index 6f381c7b2729719b478a88f2848b0f474669f281,6f381c7b2729719b478a88f2848b0f474669f281..7badb52e48c1ec07d9452435b5f7a075d3a02e81
@@@ -88,8 -88,8 +88,8 @@@ LIBSILC_REVISION=0            # prev = 
  LIBSILC_AGE=1                 # prev = 1
  
  # libsilcclient versions
--LIBSILCCLIENT_CURRENT=2               # prev = 1
--LIBSILCCLIENT_REVISION=1      # prev = 1
++LIBSILCCLIENT_CURRENT=3               # prev = 2
++LIBSILCCLIENT_REVISION=0      # prev = 1
  LIBSILCCLIENT_AGE=0           # prev = 0
  
  # libsilcserver versions
index 3ab7ba17b4aa96fc872496dce38c17ae078227d7,3ab7ba17b4aa96fc872496dce38c17ae078227d7..2c731ebd78bdccb4add462821898156b7d798e6b
@@@ -4,7 -4,7 +4,7 @@@
  
    Author: Pekka Riikonen <priikone@silcnet.org>
  
--  Copyright (C) 1997 - 2007 Pekka Riikonen
++  Copyright (C) 1997 - 2008 Pekka Riikonen
  
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@@ -621,8 -621,8 +621,10 @@@ silc_client_add_connection(SilcClient c
    }
  
    /* Set parameters */
--  if (params)
++  if (params) {
      conn->internal->params = *params;
++    conn->context = params->context;
++  }
    if (!conn->internal->params.rekey_secs)
      conn->internal->params.rekey_secs = 3600;
  #ifndef SILC_DIST_INPLACE
index d66808dcef168e06473e7168104b18f97430ce43,542b6329fc1ef4bd6d9dce9a777bf93155d565c9..8c9895531c107ba906a4af6c2cd4e20adba61550
@@@ -101,6 -101,8 +101,9 @@@ typedef struct SilcServerEntryInternalS
    SilcRwLock lock;                         /* Read/write lock */
    SilcUInt16 resolve_cmd_ident;                    /* Resolving identifier */
    SilcAtomic32 refcnt;                             /* Reference counter */
 -  SilcAtomic32 deleted;     /* Flag indicating whether the server object is
 -                                                                         already scheduled for deletion.*/
++  SilcAtomic32 deleted;                            /* Flag indicating whether the
++                                              server object is already
++                                              scheduled for deletion. */
  } SilcServerEntryInternal;
  
  #endif /* CLIENT_H */
index 4664dbaa75f770446b457b8b7d830b67cab2d524,64810b75d4fe640e12654280e8d697b74e6f0209..a7ec24ee2701801ad02b235fe6c773a54bc37149
@@@ -4,7 -4,7 +4,7 @@@
  
    Author: Pekka Riikonen <priikone@silcnet.org>
  
--  Copyright (C) 2001 - 2007 Pekka Riikonen
++  Copyright (C) 2001 - 2008 Pekka Riikonen
  
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@@ -815,6 -815,9 +815,9 @@@ SilcClientEntry silc_client_add_client(
                                                 NULL, NULL, NULL, TRUE);
    if (!client_entry->channels) {
      silc_free(client_entry->realname);
 -       silc_atomic_uninit32(&client_entry->internal.deleted);
 -       silc_atomic_uninit32(&client_entry->internal.refcnt);
 -       silc_rwlock_free(client_entry->internal.lock);
++    silc_atomic_uninit32(&client_entry->internal.deleted);
++    silc_atomic_uninit32(&client_entry->internal.refcnt);
++    silc_rwlock_free(client_entry->internal.lock);
      silc_free(client_entry);
      return NULL;
    }
      nick = silc_identifier_check(parsed, strlen(parsed),
                                 SILC_STRING_UTF8, 128, NULL);
      if (!nick) {
-       silc_free(client_entry->realname);
        silc_hash_table_free(client_entry->channels);
 -         silc_atomic_uninit32(&client_entry->internal.deleted);
 -         silc_atomic_uninit32(&client_entry->internal.refcnt);
 -         silc_rwlock_free(client_entry->internal.lock);
+       silc_free(client_entry->realname);
++      silc_atomic_uninit32(&client_entry->internal.deleted);
++      silc_atomic_uninit32(&client_entry->internal.refcnt);
++      silc_rwlock_free(client_entry->internal.lock);
        silc_free(client_entry);
        return NULL;
      }
    if (!silc_idcache_add(conn->internal->client_cache, nick,
                        &client_entry->id, client_entry)) {
      silc_free(nick);
-     silc_free(client_entry->realname);
      silc_hash_table_free(client_entry->channels);
 -       silc_atomic_uninit32(&client_entry->internal.deleted);
 -       silc_atomic_uninit32(&client_entry->internal.refcnt);
 -       silc_rwlock_free(client_entry->internal.lock);
+     silc_free(client_entry->realname);
++    silc_atomic_uninit32(&client_entry->internal.deleted);
++    silc_atomic_uninit32(&client_entry->internal.refcnt);
++    silc_rwlock_free(client_entry->internal.lock);
      silc_free(client_entry);
      silc_mutex_unlock(conn->internal->lock);
      return NULL;
@@@ -1652,6 -1661,7 +1661,7 @@@ SilcChannelEntry silc_client_add_channe
    if (!channel->channel_name) {
      silc_rwlock_free(channel->internal.lock);
      silc_atomic_uninit32(&channel->internal.refcnt);
 -       silc_atomic_uninit32(&channel->internal.deleted);
++    silc_atomic_uninit32(&channel->internal.deleted);
      silc_free(channel);
      return NULL;
    }
    if (!channel->user_list) {
      silc_rwlock_free(channel->internal.lock);
      silc_atomic_uninit32(&channel->internal.refcnt);
 -       silc_atomic_uninit32(&channel->internal.deleted);
++    silc_atomic_uninit32(&channel->internal.deleted);
      silc_free(channel->channel_name);
      silc_free(channel);
      return NULL;
    if (!channel_namec) {
      silc_rwlock_free(channel->internal.lock);
      silc_atomic_uninit32(&channel->internal.refcnt);
 -       silc_atomic_uninit32(&channel->internal.deleted);
++    silc_atomic_uninit32(&channel->internal.deleted);
      silc_free(channel->channel_name);
      silc_hash_table_free(channel->user_list);
      silc_free(channel);
                        &channel->id, channel)) {
      silc_rwlock_free(channel->internal.lock);
      silc_atomic_uninit32(&channel->internal.refcnt);
 -       silc_atomic_uninit32(&channel->internal.deleted);
++    silc_atomic_uninit32(&channel->internal.deleted);
      silc_free(channel_namec);
      silc_free(channel->channel_name);
      silc_hash_table_free(channel->user_list);
@@@ -2128,34 -2148,15 +2148,11 @@@ SilcBool silc_client_del_server(SilcCli
    if (!server)
      return FALSE;
  
-   if (silc_atomic_sub_int32(&server->internal.refcnt, 1) > 0)
+   if (silc_atomic_sub_int32(&server->internal.deleted, 1) != 0)
 -  {
 -        SILC_LOG_DEBUG(("** WARNING ** Deleting a server twice %p", server));
 -//      asm("int3");
 -        return FALSE;
 -  }
 +    return FALSE;
  
-   SILC_LOG_DEBUG(("Deleting server %p", server));
-   silc_mutex_lock(conn->internal->lock);
-   if (silc_idcache_find_by_context(conn->internal->server_cache, server,
-                                  &id_cache)) {
-     namec = id_cache->name;
-     ret = silc_idcache_del_by_context(conn->internal->server_cache,
-                                     server, NULL);
-     silc_free(namec);
-   }
-   silc_mutex_unlock(conn->internal->lock);
-   silc_free(server->server_name);
-   silc_free(server->server_info);
-   if (server->public_key)
-     silc_pkcs_public_key_free(server->public_key);
-   silc_atomic_uninit32(&server->internal.refcnt);
-   silc_rwlock_free(server->internal.lock);
-   silc_free(server);
-   return ret;
+   silc_client_unref_server(client, conn, server);
+   return TRUE;
  }
  
  /* Updates the `server_entry' with the new information sent as argument. */
index 898204a18f46663a571c0c38202d924fb9d3f089,898204a18f46663a571c0c38202d924fb9d3f089..00d0b5e58fbca0458059a82ae3f8db50a2271615
@@@ -4,7 -4,7 +4,7 @@@
  
    Author: Pekka Riikonen <priikone@silcnet.org>
  
--  Copyright (C) 2000 - 2007 Pekka Riikonen
++  Copyright (C) 2000 - 2008 Pekka Riikonen
  
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@@ -943,6 -943,6 +943,10 @@@ typedef struct SilcClientConnectionPara
       silc_client_attribute_add for more information on attributes. */
    SilcBool ignore_requested_attributes;
  
++  /* User context for SilcClientConnection.  If non-NULL this context is
++     set to the 'context' field in SilcClientConnection when the connection
++     context is created. */
++  void *context;
  } SilcClientConnectionParams;
  /***/
  
index bac8a5c4fac9b8feb642da88c272092fa4a1ccb3,1987ffc279f737dcb91d2ee65f1ff4df4941dec2..a4822e95a505a8cb709d6d63bfb0f4eabf9e8f0f
@@@ -73,6 -73,7 +73,41 @@@ static SilcBool silc_ske_packet_send(Si
                                     const unsigned char *data,
                                     SilcUInt32 data_len);
  
 -static void silc_ske_notify_failure(SilcSKE ske);
++/*
++ * Notify the owner of the ske that we failed.  Ensures that we don't make the
++ * same callout twice, as the notification callback routines are not designed
++ * to handle that case.
++ */
++static void silc_ske_notify_failure(SilcSKE ske)
++{
++  SILC_LOG_DEBUG(("Notifying SKE %p owner of failure (failure_notified = %lu)",
++                ske, ske->failure_notified));
++
++  /*
++   * First, check if we have already made a failure callout.  If so, then we
++   * will stop here.
++   */
++  if (ske->failure_notified)
++    return;
++
++  /*
++   * Mark ourselves as having already sent the failure notification here and
++   * now.
++   */
++  ske->failure_notified = TRUE;
++
++  SILC_LOG_DEBUG(("Deliver failure notification for SKE %p (%s)",
++                ske, ske->responder ? "responder" : "initiator"));
++
++  /*
++   * Finally, make the call to the owner's registered failure callback.
++   */
++  if (ske->responder)
++    silc_fsm_next(&ske->fsm, silc_ske_st_responder_failure);
++  else
++    silc_fsm_next(&ske->fsm, silc_ske_st_initiator_failure);
++}
++
  /* Packet callback */
  
  static SilcBool silc_ske_packet_receive(SilcPacketEngine engine,
    }
  
    /* See if received failure from remote */
--  if (packet->type == SILC_PACKET_FAILURE) {
-     if (ske->responder)
-       silc_fsm_next(&ske->fsm, silc_ske_st_responder_failure);
-     else
-       silc_fsm_next(&ske->fsm, silc_ske_st_initiator_failure);
-   }
++  if (packet->type == SILC_PACKET_FAILURE)
+     silc_ske_notify_failure(ske);
 -  }
  
    /* Handle rekey and SUCCESS packets synchronously.  After SUCCESS packets
       they keys are taken into use immediately, hence the synchronous
@@@ -973,9 -968,8 +1001,7 @@@ static void silc_ske_finished(SilcFSM f
                              void *destructor_context)
  {
    SilcSKE ske = fsm_context;
-   ske->running = FALSE;
-   if (ske->freed)
 -  ske->fsm_finished = TRUE;
--    silc_ske_free(ske);
++  silc_ske_free(ske);
  }
  
  /* Key exchange timeout task callback */
@@@ -1039,23 -1030,28 +1062,28 @@@ void silc_ske_free(SilcSKE ske
    if (!ske)
      return;
  
-   if (ske->running) {
-     ske->freed = TRUE;
 -  SILC_LOG_DEBUG(("Freeing Key Exchange object %p: aborted=%u refcount=%hu", ske, ske->aborted, ske->refcnt));
 -
 -    if (ske->aborted) {
 -      /*
 -       * If already aborted, destroy the session immediately.  Only do the
 -       * notification work if we have not already though, as doing so twice
 -       * results in memory corruption.  We may have silc_ske_free called
 -       * twice, once when the abort is requested, and then again when the
 -       * FSM finish routine is called.  We have to be prepared to handle
 -       * that case.
 -       */
++  SILC_LOG_DEBUG(("Freeing Key Exchange object %p: aborted=%u refcount=%hu",
++                ske, ske->aborted, ske->refcnt));
  
-     if (ske->aborted) {
-       /* If already aborted, destroy the session immediately */
-       ske->packet = NULL;
-       ske->status = SILC_SKE_STATUS_ERROR;
-       if (ske->responder)
-       silc_fsm_next(&ske->fsm, silc_ske_st_responder_failure);
-       else
-       silc_fsm_next(&ske->fsm, silc_ske_st_initiator_failure);
 -      ske->packet         = NULL;
 -      ske->status         = SILC_SKE_STATUS_ERROR;
++  if (ske->aborted) {
++    /*
++     * If already aborted, destroy the session immediately.  Only do the
++     * notification work if we have not already though, as doing so twice
++     * results in memory corruption.  We may have silc_ske_free called
++     * twice, once when the abort is requested, and then again when the
++     * FSM finish routine is called.  We have to be prepared to handle
++     * that case.
++     */
++    ske->packet         = NULL;
++    ske->status         = SILC_SKE_STATUS_ERROR;
 -      silc_ske_notify_failure(ske);
++    silc_ske_notify_failure(ske);
 -      if (!ske->fsm_finished)
 -         silc_fsm_continue_sync(&ske->fsm);
 -      else
 -         SILC_LOG_DEBUG(("Not continuing FSM as it's finished for SKE %p", ske));
 -    }
++    if (silc_fsm_is_started(&ske->fsm))
 +      silc_fsm_continue_sync(&ske->fsm);
-     }
-     return;
++    else
++      SILC_LOG_DEBUG(("Not continuing FSM as it's finished for SKE %p", ske));
 +  }
  
    ske->refcnt--;
    if (ske->refcnt > 0)
@@@ -1805,7 -1801,7 +1833,8 @@@ SilcAsyncOperation silc_ske_initiator(S
                                      SilcSKEParams params,
                                      SilcSKEStartPayload start_payload)
  {
-   SILC_LOG_DEBUG(("Start SKE as initiator"));
 -  SILC_LOG_DEBUG(("Start SKE %p as initiator; stream=%p; params=%p; start_payload=%p", ske, stream, params, start_payload));
++  SILC_LOG_DEBUG(("Start SKE %p as initiator; stream=%p; params=%p; "
++                "start_payload=%p", ske, stream, params, start_payload));
  
    if (!ske || !stream || !params || !params->version)
      return NULL;
index 051324550b66727f0f413281fae1b8466df22b40,572b0837fbc368f0aa3f1f8162546b7fef627de0..b7b6e2e76157315174ed1e609b838f1728efbd17
@@@ -4,7 -4,7 +4,7 @@@
  
    Author: Pekka Riikonen <priikone@silcnet.org>
  
--  Copyright (C) 2005 - 2007 Pekka Riikonen
++  Copyright (C) 2005 - 2008 Pekka Riikonen
  
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@@ -90,11 -90,11 +90,11 @@@ struct SilcSKEStruct 
    SilcUInt16 timeout;               /* SKE timeout */
    SilcUInt16 refcnt;                /* Reference counter */
  
-   unsigned int aborted    : 1;        /* Set when SKE aborted */
-   unsigned int freed      : 1;              /* Set when freed during session */
-   unsigned int responder  : 1;              /* Set when we are responder side */
-   unsigned int running    : 1;              /* Set when SKE is running */
-   unsigned int rekeying   : 1;              /* Set when rekeying */
 -  unsigned int aborted          : 1;         /* Set when SKE aborted */
 -  unsigned int responder        : 1;        /* Set when we are responder side */
 -  unsigned int rekeying         : 1;        /* Set when rekeying */
 -  unsigned int failure_notified : 1;        /* Set to indicate that we already called the failure notify routine */
 -  unsigned int fsm_finished     : 1;         /* Set when we're in FSM teardown */
++  unsigned int aborted          : 1;  /* Set when SKE aborted */
++  unsigned int responder        : 1;  /* Set when we are responder side */
++  unsigned int rekeying         : 1;  /* Set when rekeying */
++  unsigned int failure_notified : 1;  /* Set to indicate that we already called
++                                       the failure notify routine */
  };
  
  #endif /* SILCSKE_I_H */