Hi Stefan,

> It appears the attachment is missing.
Yeah, motoric memory took over and I sent the mail, while I intended to
actually test the patches again before resending.

So, here's the updated _and_ tested patches, attached this time.

Gr.

Matthijs
[[[
Fix the python bindings for svn_auth_get_platform_specific_client_providers.

The bindings were present, but due to a missing argout typemap for
apr_array_header_t **providers, they threw a not implemented error. This
was fixed for perl in r1035745, but was still broken for python and
ruby.

[in subversion/bindings/swig]

* include/svn_containers.swg
  Add an argout typemap for apr_array_header_t **providers, using the
  new svn_swig_py_pointerlist_to_list.

* python/libsvn_swig_py/swigutil_py.c
  Generalize convert_rangelist and svn_swig_py_ranglist_to_list to work
  with any apr_array containing pointers and rename them to
  convert_pointerlist and svn_swig_py_pointerlist_to_list respectively.

* python/libsvn_swig_py/swigutil_py.h
  Rename svn_swig_py_ranglist_to_list to svn_swig_py_pointerlist_to_list.

* python/test/client.py
  (test_platform_providers): Add testcase.

[in /tools/examples]

* get-location-segments.py
  Let this example use svn_auth_get_platform_specific_client_providers.

Patch by: Matthijs Kooijman <matth...@stdin.nl>

]]]
Index: subversion-trunk/subversion/bindings/swig/include/svn_containers.swg
===================================================================
--- subversion-trunk.orig/subversion/bindings/swig/include/svn_containers.swg	2012-01-06 10:10:47.872180699 +0100
+++ subversion-trunk/subversion/bindings/swig/include/svn_containers.swg	2012-02-07 16:20:36.906353455 +0100
@@ -825,8 +825,8 @@
 #ifdef SWIGPYTHON
 %typemap(argout) apr_array_header_t **RANGELIST {
   %append_output
-    (svn_swig_py_rangelist_to_list(*$1, $descriptor(svn_merge_range_t *),
-                                   _global_py_pool));
+    (svn_swig_py_pointerlist_to_list(*$1, $descriptor(svn_merge_range_t *),
+                                     _global_py_pool));
   if (PyErr_Occurred()) {
     SWIG_fail;
   }
@@ -873,3 +873,14 @@
                     $descriptor(svn_auth_provider_object_t *)));
 }
 #endif
+
+#ifdef SWIGPYTHON
+%typemap(argout) apr_array_header_t **providers {
+  %append_output
+    (svn_swig_py_pointerlist_to_list(*$1, $descriptor(svn_auth_provider_object_t *),
+                                     _global_py_pool));
+  if (PyErr_Occurred()) {
+    SWIG_fail;
+  }
+}
+#endif
Index: subversion-trunk/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c
===================================================================
--- subversion-trunk.orig/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c	2012-02-07 16:16:30.304976327 +0100
+++ subversion-trunk/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c	2012-02-07 16:24:48.087755431 +0100
@@ -650,7 +650,7 @@
   return convert_hash(hash, convert_string, NULL, NULL);
 }
 
-static PyObject *convert_rangelist(void *value, void *ctx, PyObject *py_pool)
+static PyObject *convert_pointerlist(void *value, void *ctx, PyObject *py_pool)
 {
   int i;
   PyObject *list;
@@ -662,11 +662,11 @@
 
   for (i = 0; i < array->nelts; i++)
     {
-      svn_merge_range_t *range = APR_ARRAY_IDX(array, i, svn_merge_range_t *);
+      void *ptr = APR_ARRAY_IDX(array, i, void *);
       PyObject *obj;
       int result;
 
-      obj = convert_to_swigtype(range, ctx, py_pool);
+      obj = convert_to_swigtype(ptr, ctx, py_pool);
       if (obj == NULL)
         goto error;
 
@@ -681,18 +681,18 @@
   return NULL;
 }
 
-PyObject *svn_swig_py_rangelist_to_list(apr_array_header_t *rangelist,
-                                        swig_type_info *type,
-                                        PyObject *py_pool)
+PyObject *svn_swig_py_pointerlist_to_list(apr_array_header_t *list,
+                                          swig_type_info *type,
+                                          PyObject *py_pool)
 {
-  return convert_rangelist(rangelist, type, py_pool);
+  return convert_pointerlist(list, type, py_pool);
 }
 
 PyObject *svn_swig_py_mergeinfo_to_dict(apr_hash_t *hash,
                                         swig_type_info *type,
                                         PyObject *py_pool)
 {
-  return convert_hash(hash, convert_rangelist, type, py_pool);
+  return convert_hash(hash, convert_pointerlist, type, py_pool);
 }
 
 static PyObject *convert_mergeinfo_hash(void *value, void *ctx,
Index: subversion-trunk/tools/examples/get-location-segments.py
===================================================================
--- subversion-trunk.orig/tools/examples/get-location-segments.py	2012-02-07 16:19:07.413853775 +0100
+++ subversion-trunk/tools/examples/get-location-segments.py	2012-02-07 16:20:36.914353499 +0100
@@ -125,7 +125,13 @@
 
   core.svn_config_ensure(None)
   ctx = client.svn_client_create_context()
-  providers = [
+
+  # Make sure that these are at the start of the list, so passwords from
+  # gnome-keyring / kwallet are checked before asking for new passwords.
+  # Note that we don't pass our config here, since we can't seem to access
+  # ctx.config.config (ctx.config is opaque).
+  providers = core.svn_auth_get_platform_specific_client_providers(None, None)
+  providers.extend([
     client.get_simple_provider(),
     core.svn_auth_get_ssl_server_trust_file_provider(),
     core.svn_auth_get_simple_prompt_provider(prompt_func_simple_prompt, 2),
@@ -134,7 +140,8 @@
     client.get_ssl_server_trust_file_provider(),
     client.get_ssl_client_cert_file_provider(),
     client.get_ssl_client_cert_pw_file_provider(),
-    ]
+  ])
+
   ctx.auth_baton = core.svn_auth_open(providers)
   ctx.config = core.svn_config_get_config(None)
 
Index: subversion-trunk/subversion/bindings/swig/python/tests/client.py
===================================================================
--- subversion-trunk.orig/subversion/bindings/swig/python/tests/client.py	2012-01-06 10:10:47.856180623 +0100
+++ subversion-trunk/subversion/bindings/swig/python/tests/client.py	2012-02-07 16:20:36.914353499 +0100
@@ -374,6 +374,11 @@
 
     self.assertEqual(readme_text, 'This is a test.\n')
 
+  def test_platform_providers(self):
+    providers = core.svn_auth_get_platform_specific_client_providers(None, None)
+    # Not much more we can test in this minimal environment.
+    self.assert_(isinstance(providers, list))
+
 def suite():
     return unittest.defaultTestLoader.loadTestsFromTestCase(
       SubversionClientTestCase)
Index: subversion-trunk/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.h
===================================================================
--- subversion-trunk.orig/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.h	2012-01-06 10:10:47.840180547 +0100
+++ subversion-trunk/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.h	2012-02-07 16:20:36.914353499 +0100
@@ -135,9 +135,9 @@
 /* helper function to convert an apr_array_header_t* (of
    svn_merge_range_t *) to a Python list */
 SVN_SWIG_SWIGUTIL_EXPORT
-PyObject *svn_swig_py_rangelist_to_list(apr_array_header_t *rangelist,
-                                        swig_type_info *type,
-                                        PyObject *py_pool);
+PyObject *svn_swig_py_pointerlist_to_list(apr_array_header_t *list,
+                                          swig_type_info *type,
+                                          PyObject *py_pool);
 
 /* helper function to convert an apr_hash_t* (const char *->array of
    svn_merge_range_t *) to a Python dict */
[[[
Fix the ruby bindings for svn_auth_get_platform_specific_client_providers.

The bindings were present, but due to a missing argout typemap for
apr_array_header_t **providers, they threw a not implemented error. This
was fixed for perl in r1035745 and for python in the previous commit,
but was still broken for ruby.

[in subversion/bindings/swig]

* include/svn_containers.swg
  Add an argout typemap for apr_array_header_t **providers, using the
  new svn_swig_rb_apr_array_to_array_auth_provider_object.

* ruby/libsvn_swig_ruby/swigutil_rb.c,
  ruby/libsvn_swig_ruby/swigutil_rb.h
  (svn_swig_rb_apr_array_to_array_auth_provider_object): Add function.

* ruby/svn/core.rb
  (add_platform_specific_client_providers, add_providers): Add
  functions.

[in tools/examples]

* info.rb
  Add a new example that shows how to do remote access instead of
  working on an existing working copy (like the existing examples do).
  This example also shows how to call
  svn_auth_get_platform_specific_client_providers.

Patch by: Matthijs Kooijman <matth...@stdin.nl>

]]]
Index: subversion-trunk/subversion/bindings/swig/include/svn_containers.swg
===================================================================
--- subversion-trunk.orig/subversion/bindings/swig/include/svn_containers.swg	2012-02-07 16:20:36.906353455 +0100
+++ subversion-trunk/subversion/bindings/swig/include/svn_containers.swg	2012-02-07 16:25:20.339935397 +0100
@@ -884,3 +884,9 @@
   }
 }
 #endif
+
+#ifdef SWIGRUBY
+%typemap(argout) apr_array_header_t **providers {
+  %append_output(svn_swig_rb_apr_array_to_array_auth_provider_object(*$1));
+}
+#endif
Index: subversion-trunk/subversion/bindings/swig/ruby/libsvn_swig_ruby/swigutil_rb.c
===================================================================
--- subversion-trunk.orig/subversion/bindings/swig/ruby/libsvn_swig_ruby/swigutil_rb.c	2012-01-06 10:10:47.652179654 +0100
+++ subversion-trunk/subversion/bindings/swig/ruby/libsvn_swig_ruby/swigutil_rb.c	2012-02-07 16:25:37.444030832 +0100
@@ -1313,6 +1313,9 @@
 DEFINE_APR_ARRAY_TO_ARRAY(VALUE, svn_swig_rb_apr_array_to_array_merge_range,
                           c2r_merge_range_dup, EMPTY_CPP_ARGUMENT,
                           svn_merge_range_t *, NULL)
+DEFINE_APR_ARRAY_TO_ARRAY(VALUE, svn_swig_rb_apr_array_to_array_auth_provider_object,
+                          c2r_swig_type, EMPTY_CPP_ARGUMENT,
+                          svn_auth_provider_object_t *, "svn_auth_provider_object_t*")
 
 static VALUE
 c2r_merge_range_array(void *value, void *ctx)
Index: subversion-trunk/subversion/bindings/swig/ruby/libsvn_swig_ruby/swigutil_rb.h
===================================================================
--- subversion-trunk.orig/subversion/bindings/swig/ruby/libsvn_swig_ruby/swigutil_rb.h	2012-01-06 10:10:47.636179576 +0100
+++ subversion-trunk/subversion/bindings/swig/ruby/libsvn_swig_ruby/swigutil_rb.h	2012-02-07 16:25:37.428030743 +0100
@@ -154,6 +154,8 @@
 VALUE svn_swig_rb_apr_array_to_array_external_item2(const apr_array_header_t *ary);
 SVN_RB_SWIG_SWIGUTIL_EXPORT
 VALUE svn_swig_rb_apr_array_to_array_merge_range(const apr_array_header_t *ary);
+SVN_RB_SWIG_SWIGUTIL_EXPORT
+VALUE svn_swig_rb_apr_array_to_array_auth_provider_object(const apr_array_header_t *ary);
 
 SVN_RB_SWIG_SWIGUTIL_EXPORT
 VALUE svn_swig_rb_prop_apr_array_to_hash_prop(const apr_array_header_t *ary);
Index: subversion-trunk/tools/examples/info.rb
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ subversion-trunk/tools/examples/info.rb	2012-02-07 16:25:37.544031390 +0100
@@ -0,0 +1,54 @@
+# Example based on a blogpost by Mark Deepwell
+# http://www.markdeepwell.com/2010/06/ruby-subversion-bindings/
+
+require "svn/core"
+require "svn/client"
+require "svn/wc"
+require "svn/repos"
+
+# Prompt function mimicking svn's own prompt
+simple_prompt = Proc.new do
+  |result, realm, username, default, may_save, pool|
+
+  puts "Authentication realm: #{realm}"
+  if username != nil
+    result.username = username
+  else
+    print "Username: "
+    result.username = STDIN.gets.strip
+  end
+  print "Password for '#{result.username}': "
+  result.password = STDIN.gets.strip
+end
+
+
+if ARGV.length != 1
+	puts "Usage: info.rb URL[@REV]"
+else
+  ctx = Svn::Client::Context.new()
+  ctx.add_platform_specific_client_providers
+  ctx.add_simple_provider
+  ctx.add_simple_prompt_provider(2, simple_prompt)
+  ctx.add_username_provider
+  ctx.add_ssl_server_trust_file_provider
+  ctx.add_ssl_client_cert_file_provider
+  ctx.add_ssl_client_cert_pw_file_provider
+
+  repos_uri, revision = ARGV[0].split("@", 2)
+  if revision
+    revision = Integer(revision)
+  end
+
+  begin
+    ctx.info(repos_uri, revision) do |path, info|
+      puts("Url: #{info.url}")
+      puts("Last changed rev: #{info.last_changed_rev}")
+      puts("Last changed author: #{info.last_changed_author}")
+      puts("Last changed date: #{info.last_changed_date}")
+      puts("Kind: #{info.kind}")
+    end
+  rescue Svn::Error => e
+    # catch a generic svn error
+    raise "Failed to retrieve SVN info at revision " + revision.to_s
+  end
+end
Index: subversion-trunk/subversion/bindings/swig/ruby/svn/core.rb
===================================================================
--- subversion-trunk.orig/subversion/bindings/swig/ruby/svn/core.rb	2012-01-06 10:10:47.624179521 +0100
+++ subversion-trunk/subversion/bindings/swig/ruby/svn/core.rb	2012-02-07 16:25:20.343935419 +0100
@@ -279,6 +279,10 @@
         add_prompt_provider("ssl_client_cert_pw", args, prompt, klass)
       end
 
+      def add_platform_specific_client_providers(config=nil)
+        add_providers(Core.auth_get_platform_specific_client_providers(config))
+      end
+
       private
       def add_prompt_provider(name, args, prompt, credential_class)
         real_prompt = Proc.new do |*prompt_args|
@@ -294,6 +298,10 @@
       end
 
       def add_provider(provider)
+        add_providers([provider])
+      end
+
+      def add_providers(new_providers)
         if auth_baton
           providers = auth_baton.providers
           parameters = auth_baton.parameters
@@ -301,7 +309,7 @@
           providers = []
           parameters = {}
         end
-        self.auth_baton = AuthBaton.new(providers + [provider], parameters)
+        self.auth_baton = AuthBaton.new(providers + new_providers, parameters)
       end
     end
 
[[[
Allow setting the SVN_AUTH_PARAM_GNOME_KEYRING_UNLOCK_PROMPT_FUNC
authentication parameter from the perl, python and ruby bindings.

This parameter cannot be set using the regular svn_auth_set_parameter
function, since the function from perl/python/ruby space must be wrapped
in a C function to allow it to be called. For this reason, a new
function, svn_auth_set_gnome_keyring_unlock_prompt_func, is introduced
(in the bindings only).

[in subversion/bindings/swig]

* core.i
  (svn_auth_set_gnome_keyring_unlock_prompt_func): Add function and
  setup corresponding authprompt_callback_typemap.

* perl/libsvn_swig_perl/swigutil_pl.c,
  perl/libsvn_swig_perl/swigutil_pl.h
  (svn_swig_pl_thunk_gnome_keyring_unlock_prompt): Add function (called
  by authprompt_callback_typemap)

* python/libsvn_swig_py/swigutil_py.c
  python/libsvn_swig_py/swigutil_py.h
  (svn_swig_py_auth_gnome_keyring_unlock_prompt_func): Add function
  (called by authprompt_callback_typemap)

* ruby/libsvn_swig_ruby/swigutil_rb.c,
  ruby/libsvn_swig_ruby/swigutil_rb.h
  (svn_swig_rb_auth_gnome_keyring_unlock_prompt_func): Add function
  (called by authprompt_callback_typemap)

* perl/native/t/3client.t,
  python/tests/client.py
  Add test for svn_auth_set_gnome_keyring_unlock_prompt_func.

[in tools/examples]

* get-location-segments.py,
  info.rb
  Use the new svn_auth_set_gnome_keyring_unlock_prompt_func function.

Patch by: Matthijs Kooijman <matth...@stdin.nl>

]]]

Index: subversion-trunk/subversion/bindings/swig/core.i
===================================================================
--- subversion-trunk.orig/subversion/bindings/swig/core.i	2012-01-06 10:10:47.452178703 +0100
+++ subversion-trunk/subversion/bindings/swig/core.i	2012-02-07 16:25:21.547942137 +0100
@@ -699,6 +699,34 @@
 %authprompt_callback_typemap(ssl_client_cert)
 %authprompt_callback_typemap(ssl_client_cert_pw)
 
+%{
+#ifdef SVN_AUTH_PARAM_GNOME_KEYRING_UNLOCK_PROMPT_FUNC
+/* Helper function to set the gnome-keyring unlock prompt function. This
+ * C function accepts an auth baton, a function and a prompt baton, but
+ * the below callback_typemap uses both the function and the prompt
+ * baton, so the resulting binding has just two arguments: The auth
+ * baton and the prompt function.
+ * The prompt function should again have two arguments: The keyring name
+ * (string) and a pool (except for the ruby version, which doesn't have
+ * the pool argument). It should return the entered password (string).
+ * This binding generated for this function generates a reference to the
+ * prompt function that was passed into this. The caller should store
+ * that reference somewhere, to prevent the function from being garbage
+ * collected...
+ */
+static void svn_auth_set_gnome_keyring_unlock_prompt_func(svn_auth_baton_t *ab,
+                                                          svn_auth_gnome_keyring_unlock_prompt_func_t prompt_func,
+                                                          void *prompt_baton) {
+    svn_auth_set_parameter(ab, SVN_AUTH_PARAM_GNOME_KEYRING_UNLOCK_PROMPT_FUNC,
+                           prompt_func);
+    svn_auth_set_parameter(ab, SVN_AUTH_PARAM_GNOME_KEYRING_UNLOCK_PROMPT_BATON,
+                           prompt_baton);
+}
+#endif
+%}
+
+%authprompt_callback_typemap(gnome_keyring_unlock)
+
 /* -----------------------------------------------------------------------
  * For all the various functions that set a callback baton create a reference
  * for the baton (which in this case is an SV pointing to the callback)
@@ -764,6 +792,12 @@
 %include svn_pools_h.swg
 %include svn_version_h.swg
 
+/* This is the function defined above */
+void svn_auth_set_gnome_keyring_unlock_prompt_func(svn_auth_baton_t *ab,
+                                                   svn_auth_gnome_keyring_unlock_prompt_func_t prompt_func,
+                                                   void *prompt_baton);
+
+
 /* The constant SVN_PROP_REVISION_ALL_PROPS is a C fragment, not a single
    data value, so the SWIG parser will raise a 305 warning if we don't
    suppress it. */
Index: subversion-trunk/subversion/bindings/swig/perl/libsvn_swig_perl/swigutil_pl.c
===================================================================
--- subversion-trunk.orig/subversion/bindings/swig/perl/libsvn_swig_perl/swigutil_pl.c	2012-01-06 10:10:47.348178211 +0100
+++ subversion-trunk/subversion/bindings/swig/perl/libsvn_swig_perl/swigutil_pl.c	2012-02-07 16:25:21.547942137 +0100
@@ -984,6 +984,34 @@
     return SVN_NO_ERROR;
 }
 
+svn_error_t *svn_swig_pl_thunk_gnome_keyring_unlock_prompt(char **keyring_password,
+                                                           const char *keyring_name,
+                                                           void *baton,
+                                                           apr_pool_t *pool)
+{
+    SV *result;
+    STRLEN len;
+    /* The baton is the actual prompt function passed from perl, so we
+     * call that one and process the result. */
+    svn_swig_pl_callback_thunk(CALL_SV,
+                               baton, &result,
+                               "sS", keyring_name,
+                               pool, POOLINFO);
+    if (!SvOK(result) || result == &PL_sv_undef) {
+        *keyring_password = NULL;
+    }
+    else if (SvPOK(result)) {
+        *keyring_password = apr_pstrdup(pool, SvPV(result, len));
+    }
+    else {
+        SvREFCNT_dec(result);
+        croak("not a string");
+    }
+
+    SvREFCNT_dec(result);
+    return SVN_NO_ERROR;
+}
+
 svn_error_t *svn_swig_pl_thunk_simple_prompt(svn_auth_cred_simple_t **cred,
                                              void *baton,
                                              const char *realm,
Index: subversion-trunk/subversion/bindings/swig/perl/libsvn_swig_perl/swigutil_pl.h
===================================================================
--- subversion-trunk.orig/subversion/bindings/swig/perl/libsvn_swig_perl/swigutil_pl.h	2012-01-06 10:10:47.364178285 +0100
+++ subversion-trunk/subversion/bindings/swig/perl/libsvn_swig_perl/swigutil_pl.h	2012-02-07 16:25:21.551942160 +0100
@@ -144,6 +144,11 @@
 				   SV *perl_callbacks,
 				   apr_pool_t *pool);
 
+/* thunked gnome_keyring_unlock_prompt callback function */
+svn_error_t *svn_swig_pl_thunk_gnome_keyring_unlock_prompt(char **keyring_password,
+                                                           const char *keyring_name,
+                                                           void *baton,
+                                                           apr_pool_t *pool);
 /* thunked simple_prompt callback function */
 svn_error_t *svn_swig_pl_thunk_simple_prompt(svn_auth_cred_simple_t **cred,
                                              void *baton,
Index: subversion-trunk/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c
===================================================================
--- subversion-trunk.orig/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c	2012-02-07 16:24:48.087755431 +0100
+++ subversion-trunk/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c	2012-02-07 16:25:21.551942160 +0100
@@ -2804,6 +2804,41 @@
 }
 
 svn_error_t *
+svn_swig_py_auth_gnome_keyring_unlock_prompt_func(char **keyring_passwd,
+                                                  const char *keyring_name,
+                                                  void *baton,
+                                                  apr_pool_t *pool)
+{
+  /* The baton is the actual prompt function passed from python */
+  PyObject *function = baton;
+  PyObject *result;
+  svn_error_t *err = SVN_NO_ERROR;
+  *keyring_passwd = NULL;
+
+  if ((function == NULL) || (function == Py_None))
+    return SVN_NO_ERROR;
+
+  svn_swig_py_acquire_py_lock();
+
+  if ((result = PyObject_CallFunction(function,
+                                      (char *)"sO&",
+                                      keyring_name,
+                                      make_ob_pool, pool)) == NULL)
+    {
+      err = callback_exception_error();
+    }
+  else
+    {
+      *keyring_passwd = make_string_from_ob(result, pool);
+      Py_DECREF(result);
+    }
+
+  svn_swig_py_release_py_lock();
+  return err;
+}
+
+
+svn_error_t *
 svn_swig_py_auth_simple_prompt_func(svn_auth_cred_simple_t **cred,
                                     void *baton,
                                     const char *realm,
Index: subversion-trunk/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.h
===================================================================
--- subversion-trunk.orig/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.h	2012-02-07 16:20:36.914353499 +0100
+++ subversion-trunk/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.h	2012-02-07 16:25:21.551942160 +0100
@@ -423,6 +423,13 @@
 
 /* auth provider callbacks */
 SVN_SWIG_SWIGUTIL_EXPORT
+svn_error_t * svn_swig_py_auth_gnome_keyring_unlock_prompt_func(
+        char **keyring_passwd,
+        const char *keyring_name,
+        void *baton,
+        apr_pool_t *pool);
+
+SVN_SWIG_SWIGUTIL_EXPORT
 svn_error_t *svn_swig_py_auth_simple_prompt_func(
     svn_auth_cred_simple_t **cred,
     void *baton,
Index: subversion-trunk/subversion/bindings/swig/ruby/libsvn_swig_ruby/swigutil_rb.c
===================================================================
--- subversion-trunk.orig/subversion/bindings/swig/ruby/libsvn_swig_ruby/swigutil_rb.c	2012-02-07 16:25:20.339935397 +0100
+++ subversion-trunk/subversion/bindings/swig/ruby/libsvn_swig_ruby/swigutil_rb.c	2012-02-07 16:25:21.555942182 +0100
@@ -2963,6 +2963,41 @@
 }
 
 svn_error_t *
+svn_swig_rb_auth_gnome_keyring_unlock_prompt_func(char **keyring_passwd,
+                                                  const char *keyring_name,
+                                                  void *baton,
+                                                  apr_pool_t *pool)
+{
+  svn_error_t *err = SVN_NO_ERROR;
+  VALUE proc, rb_pool;
+  *keyring_passwd = NULL;
+
+  svn_swig_rb_from_baton((VALUE)baton, &proc, &rb_pool);
+
+  if (!NIL_P(proc)) {
+    char error_message[] =
+      "svn_auth_gnome_keyring_unlock_prompt_func_t should"
+      "return a string, not '%s'.";
+
+    callback_baton_t cbb;
+    VALUE result;
+
+    cbb.receiver = proc;
+    cbb.message = id_call;
+    cbb.args = rb_ary_new3(1, c2r_string2(keyring_name));
+    result = invoke_callback_handle_error((VALUE)(&cbb), rb_pool, &err);
+
+    if (!NIL_P(result)) {
+      if (!RTEST(rb_obj_is_kind_of(result, rb_cString)))
+        rb_raise(rb_eTypeError, error_message, r2c_inspect(result));
+      *keyring_passwd = (char *)r2c_string(result, NULL, pool);
+    }
+  }
+
+  return err;
+}
+
+svn_error_t *
 svn_swig_rb_auth_username_prompt_func(svn_auth_cred_username_t **cred,
                                       void *baton,
                                       const char *realm,
Index: subversion-trunk/subversion/bindings/swig/ruby/libsvn_swig_ruby/swigutil_rb.h
===================================================================
--- subversion-trunk.orig/subversion/bindings/swig/ruby/libsvn_swig_ruby/swigutil_rb.h	2012-02-07 16:25:20.343935419 +0100
+++ subversion-trunk/subversion/bindings/swig/ruby/libsvn_swig_ruby/swigutil_rb.h	2012-02-07 16:25:21.555942182 +0100
@@ -380,6 +380,13 @@
 
 /* auth provider callbacks */
 SVN_RB_SWIG_SWIGUTIL_EXPORT
+svn_error_t * svn_swig_rb_auth_gnome_keyring_unlock_prompt_func(
+    char **keyring_passwd,
+    const char *keyring_name,
+    void *baton,
+    apr_pool_t *pool);
+
+SVN_RB_SWIG_SWIGUTIL_EXPORT
 svn_error_t *svn_swig_rb_auth_simple_prompt_func(
     svn_auth_cred_simple_t **cred,
     void *baton,
Index: subversion-trunk/subversion/bindings/swig/perl/native/t/3client.t
===================================================================
--- subversion-trunk.orig/subversion/bindings/swig/perl/native/t/3client.t	2012-01-06 10:10:47.332178134 +0100
+++ subversion-trunk/subversion/bindings/swig/perl/native/t/3client.t	2012-02-07 16:25:21.555942182 +0100
@@ -20,7 +20,7 @@
 #
 #
 
-use Test::More tests => 119;
+use Test::More tests => 120;
 use strict;
 
 # shut up about variables that are only used once.
@@ -477,6 +477,23 @@
 }
 ok($ok, 'svn_auth_get_platform_specific_client_providers returns _p_svn_auth_provider_object_t\'s');
 
+# Test setting gnome_keyring prompt function. This just sets the proper
+# attributes in the auth baton and checks the return value (which should
+# be a reference to the passed function reference). This does not
+# actually try the prompt, since that would require setting up a
+# gnome-keyring-daemon...
+sub gnome_keyring_unlock_prompt {
+    my $keyring_name = shift;
+    my $pool = shift;
+
+    'test';
+}
+
+my $callback = \&gnome_keyring_unlock_prompt;
+my $result = SVN::Core::auth_set_gnome_keyring_unlock_prompt_func(
+              $ctx->auth(), $callback);
+is(${$result}, $callback, 'auth_set_gnome_keyring_unlock_prompt_func result equals paramter');
+
 END {
 diag('cleanup');
 rmtree($testpath);
Index: subversion-trunk/subversion/bindings/swig/python/tests/client.py
===================================================================
--- subversion-trunk.orig/subversion/bindings/swig/python/tests/client.py	2012-02-07 16:20:36.914353499 +0100
+++ subversion-trunk/subversion/bindings/swig/python/tests/client.py	2012-02-07 16:25:21.555942182 +0100
@@ -379,6 +379,17 @@
     # Not much more we can test in this minimal environment.
     self.assert_(isinstance(providers, list))
 
+  def testGnomeKeyring(self):
+    # This tests setting the gnome-keyring unlock prompt function as an
+    # auth baton parameter. It doesn't actually call gnome-keyring
+    # stuff, since that would require having a gnome-keyring running. We
+    # just test if this doesn't error out, there's not even a return
+    # value to test.
+    def prompt_func(realm_string, pool):
+      return "Foo"
+
+    core.svn_auth_set_gnome_keyring_unlock_prompt_func(self.client_ctx.auth_baton, prompt_func)
+
 def suite():
     return unittest.defaultTestLoader.loadTestsFromTestCase(
       SubversionClientTestCase)
Index: subversion-trunk/tools/examples/get-location-segments.py
===================================================================
--- subversion-trunk.orig/tools/examples/get-location-segments.py	2012-02-07 16:20:36.914353499 +0100
+++ subversion-trunk/tools/examples/get-location-segments.py	2012-02-07 16:25:21.555942182 +0100
@@ -105,6 +105,9 @@
   simple_cred.may_save = False
   return simple_cred
 
+def prompt_func_gnome_keyring_prompt(keyring, pool):
+  return getpass.getpass(prompt="Password for '%s' GNOME keyring: " % keyring)
+
 def main():
   try:
     url, peg_revision, start_revision, end_revision = parse_args(sys.argv[1:])
@@ -145,6 +148,9 @@
   ctx.auth_baton = core.svn_auth_open(providers)
   ctx.config = core.svn_config_get_config(None)
 
+  if hasattr(core, 'svn_auth_set_gnome_keyring_unlock_prompt_func'):
+    core.svn_auth_set_gnome_keyring_unlock_prompt_func(ctx.auth_baton, prompt_func_gnome_keyring_prompt)
+
   ra_callbacks = ra.callbacks_t()
   ra_callbacks.auth_baton = ctx.auth_baton
   ra_session = ra.open(url, ra_callbacks, None, ctx.config)
Index: subversion-trunk/tools/examples/info.rb
===================================================================
--- subversion-trunk.orig/tools/examples/info.rb	2012-02-07 16:25:20.343935419 +0100
+++ subversion-trunk/tools/examples/info.rb	2012-02-07 16:25:21.559942204 +0100
@@ -1,7 +1,9 @@
+#!/usr/bin/ruby
 # Example based on a blogpost by Mark Deepwell
 # http://www.markdeepwell.com/2010/06/ruby-subversion-bindings/
 
 require "svn/core"
+require "svn/ext/core"
 require "svn/client"
 require "svn/wc"
 require "svn/repos"
@@ -21,6 +23,12 @@
   result.password = STDIN.gets.strip
 end
 
+gnome_keyring_prompt = Proc.new do
+  |keyring_name|
+
+  print "Password for '#{keyring_name}' GNOME keyring: "
+  STDIN.gets.strip
+end
 
 if ARGV.length != 1
 	puts "Usage: info.rb URL[@REV]"
@@ -34,6 +42,12 @@
   ctx.add_ssl_client_cert_file_provider
   ctx.add_ssl_client_cert_pw_file_provider
 
+  # Allow asking for the gnome keyring password, in case the keyring is
+  # locked.
+  if Svn::Ext::Core.respond_to?(:svn_auth_set_gnome_keyring_unlock_prompt_func)
+    Svn::Ext::Core::svn_auth_set_gnome_keyring_unlock_prompt_func(ctx.auth_baton, gnome_keyring_prompt)
+  end
+
   repos_uri, revision = ARGV[0].split("@", 2)
   if revision
     revision = Integer(revision)

Attachment: signature.asc
Description: Digital signature

Reply via email to