Removed C99 struct initializers for compatibility with 'legacy' compilers (like MSVC...
[jelmer/subvertpy.git] / ra.c
1 /* Copyright © 2008 Jelmer Vernooij <jelmer@samba.org>
2  * -*- coding: utf-8 -*-
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18 #include <stdbool.h>
19 #include <Python.h>
20 #include <apr_general.h>
21 #include <svn_types.h>
22 #include <svn_ra.h>
23 #include <svn_path.h>
24 #include <apr_file_io.h>
25 #include <apr_portable.h>
26
27 #include <structmember.h>
28
29 #include "editor.h"
30 #include "util.h"
31 #include "ra.h"
32
33 static PyObject *busy_exc;
34
35 PyAPI_DATA(PyTypeObject) Reporter_Type;
36 PyAPI_DATA(PyTypeObject) RemoteAccess_Type;
37 PyAPI_DATA(PyTypeObject) AuthProvider_Type;
38 PyAPI_DATA(PyTypeObject) CredentialsIter_Type;
39 PyAPI_DATA(PyTypeObject) TxDeltaWindowHandler_Type;
40
41 static svn_error_t *py_commit_callback(const svn_commit_info_t *commit_info, void *baton, apr_pool_t *pool)
42 {
43         PyObject *fn = (PyObject *)baton, *ret;
44
45         if (fn == Py_None)
46                 return NULL;
47
48         ret = PyObject_CallFunction(fn, "izz", 
49                                                                 commit_info->revision, commit_info->date, 
50                                                                 commit_info->author);
51         if (ret == NULL)
52                 return py_svn_error();
53         Py_DECREF(ret);
54         return NULL;
55 }
56
57 static PyObject *pyify_lock(const svn_lock_t *lock)
58 {
59         return Py_BuildValue("(ssszbLL)", 
60                                                  lock->path, lock->token, 
61                                                  lock->owner, lock->comment,
62                                                  lock->is_dav_comment,
63                                                  lock->creation_date,
64                                                  lock->expiration_date);
65 }
66
67 static svn_error_t *py_lock_func (void *baton, const char *path, int do_lock, 
68                                                    const svn_lock_t *lock, svn_error_t *ra_err, 
69                                                    apr_pool_t *pool)
70 {
71         PyObject *py_ra_err = Py_None, *ret, *py_lock;
72         if (ra_err != NULL) {
73                 py_ra_err = PyErr_NewSubversionException(ra_err);
74         }
75         py_lock = pyify_lock(lock);
76         ret = PyObject_CallFunction((PyObject *)baton, "zbOO", path, do_lock, 
77                                                   py_lock, py_ra_err);
78         Py_DECREF(py_lock);
79         Py_DECREF(py_ra_err);
80         if (ret == NULL)
81                 return py_svn_error();
82         Py_DECREF(ret);
83         return NULL;
84 }
85
86 /** Connection to a remote Subversion repository. */
87 typedef struct {
88         PyObject_HEAD
89         svn_ra_session_t *ra;
90         apr_pool_t *pool;
91         const char *url;
92         PyObject *progress_func;
93         AuthObject *auth;
94         bool busy;
95         PyObject *client_string_func;
96         PyObject *open_tmp_file_func;
97         char *root;
98 } RemoteAccessObject;
99
100 typedef struct {
101         PyObject_HEAD
102         const svn_ra_reporter2_t *reporter;
103         void *report_baton;
104         apr_pool_t *pool;
105         RemoteAccessObject *ra;
106 } ReporterObject;
107
108 static PyObject *reporter_set_path(PyObject *self, PyObject *args)
109 {
110         char *path; 
111         svn_revnum_t revision; 
112         bool start_empty; 
113         char *lock_token = NULL;
114         ReporterObject *reporter = (ReporterObject *)self;
115
116         if (!PyArg_ParseTuple(args, "slb|z", &path, &revision, &start_empty, 
117                                                   &lock_token))
118                 return NULL;
119
120         if (!check_error(reporter->reporter->set_path(reporter->report_baton, 
121                                                                                                   path, revision, start_empty, 
122                                          lock_token, reporter->pool)))
123                 return NULL;
124
125         Py_RETURN_NONE;
126 }
127
128 static PyObject *reporter_delete_path(PyObject *self, PyObject *args)
129 {
130         ReporterObject *reporter = (ReporterObject *)self;
131         char *path;
132         if (!PyArg_ParseTuple(args, "s", &path))
133                 return NULL;
134
135         if (!check_error(reporter->reporter->delete_path(reporter->report_baton, 
136                                                                                                         path, reporter->pool)))
137                 return NULL;
138
139         Py_RETURN_NONE;
140 }
141
142 static PyObject *reporter_link_path(PyObject *self, PyObject *args)
143 {
144         char *path, *url;
145         svn_revnum_t revision;
146         bool start_empty;
147         char *lock_token = NULL;
148         ReporterObject *reporter = (ReporterObject *)self;
149
150         if (!PyArg_ParseTuple(args, "sslb|z", &path, &url, &revision, &start_empty, &lock_token))
151                 return NULL;
152
153         if (!check_error(reporter->reporter->link_path(reporter->report_baton, path, url, 
154                                 revision, start_empty, lock_token, reporter->pool)))
155                 return NULL;
156
157         Py_RETURN_NONE;
158 }
159
160 static PyObject *reporter_finish(PyObject *self)
161 {
162         ReporterObject *reporter = (ReporterObject *)self;
163
164         reporter->ra->busy = false;
165
166         if (!check_error(reporter->reporter->finish_report(reporter->report_baton, 
167                                                                                                           reporter->pool)))
168                 return NULL;
169
170         Py_XDECREF(reporter->ra);
171
172         Py_RETURN_NONE;
173 }
174
175 static PyObject *reporter_abort(PyObject *self)
176 {
177         ReporterObject *reporter = (ReporterObject *)self;
178         
179         reporter->ra->busy = false;
180
181         if (!check_error(reporter->reporter->abort_report(reporter->report_baton, 
182                                                                                                          reporter->pool)))
183                 return NULL;
184
185         Py_XDECREF(reporter->ra);
186
187         Py_RETURN_NONE;
188 }
189
190 static PyMethodDef reporter_methods[] = {
191         { "abort", (PyCFunction)reporter_abort, METH_NOARGS, NULL },
192         { "finish", (PyCFunction)reporter_finish, METH_NOARGS, NULL },
193         { "link_path", (PyCFunction)reporter_link_path, METH_VARARGS, NULL },
194         { "set_path", (PyCFunction)reporter_set_path, METH_VARARGS, NULL },
195         { "delete_path", (PyCFunction)reporter_delete_path, METH_VARARGS, NULL },
196         { NULL, }
197 };
198
199 static void reporter_dealloc(PyObject *self)
200 {
201         ReporterObject *reporter = (ReporterObject *)self;
202         /* FIXME: Warn the user if abort_report/finish_report wasn't called? */
203         apr_pool_destroy(reporter->pool);
204         PyObject_Del(self);
205 }
206
207 PyTypeObject Reporter_Type = {
208         PyObject_HEAD_INIT(NULL) 0,
209         "ra.Reporter", /*       const char *tp_name;  For printing, in format "<module>.<name>" */
210         sizeof(ReporterObject), 
211         0,/*    Py_ssize_t tp_basicsize, tp_itemsize;  For allocation */
212         
213         /* Methods to implement standard operations */
214         
215         reporter_dealloc, /*    destructor tp_dealloc;  */
216         NULL, /*        printfunc tp_print;     */
217         NULL, /*        getattrfunc tp_getattr; */
218         NULL, /*        setattrfunc tp_setattr; */
219         NULL, /*        cmpfunc tp_compare;     */
220         NULL, /*        reprfunc tp_repr;       */
221         
222         /* Method suites for standard classes */
223         
224         NULL, /*        PyNumberMethods *tp_as_number;  */
225         NULL, /*        PySequenceMethods *tp_as_sequence;      */
226         NULL, /*        PyMappingMethods *tp_as_mapping;        */
227         
228         /* More standard operations (here for binary compatibility) */
229         
230         NULL, /*        hashfunc tp_hash;       */
231         NULL, /*        ternaryfunc tp_call;    */
232         NULL, /*        reprfunc tp_str;        */
233         NULL, /*        getattrofunc tp_getattro;       */
234         NULL, /*        setattrofunc tp_setattro;       */
235         
236         /* Functions to access object as input/output buffer */
237         NULL, /*        PyBufferProcs *tp_as_buffer;    */
238         
239         /* Flags to define presence of optional/expanded features */
240         0, /*   long tp_flags;  */
241         
242         NULL, /*        const char *tp_doc;  Documentation string */
243         
244         /* Assigned meaning in release 2.0 */
245         /* call function for all accessible objects */
246         NULL, /*        traverseproc tp_traverse;       */
247         
248         /* delete references to contained objects */
249         NULL, /*        inquiry tp_clear;       */
250         
251         /* Assigned meaning in release 2.1 */
252         /* rich comparisons */
253         NULL, /*        richcmpfunc tp_richcompare;     */
254         
255         /* weak reference enabler */
256         0, /*   Py_ssize_t tp_weaklistoffset;   */
257         
258         /* Added in release 2.2 */
259         /* Iterators */
260         NULL, /*        getiterfunc tp_iter;    */
261         NULL, /*        iternextfunc tp_iternext;       */
262         
263         /* Attribute descriptor and subclassing stuff */
264         reporter_methods, /*    struct PyMethodDef *tp_methods; */
265
266 };
267
268 /**
269  * Get libsvn_ra version information.
270  *
271  * :return: tuple with major, minor, patch version number and tag.
272  */
273 static PyObject *version(PyObject *self)
274 {
275         const svn_version_t *ver = svn_ra_version();
276         return Py_BuildValue("(iiis)", ver->major, ver->minor, 
277                                                  ver->patch, ver->tag);
278 }
279
280 static svn_error_t *py_cb_editor_set_target_revision(void *edit_baton, svn_revnum_t target_revision, apr_pool_t *pool)
281 {
282         PyObject *self = (PyObject *)edit_baton, *ret;
283
284         ret = PyObject_CallMethod(self, "set_target_revision", "l", target_revision);
285         if (ret == NULL)
286                 return py_svn_error();
287         Py_DECREF(ret);
288         return NULL;
289 }
290
291 static svn_error_t *py_cb_editor_open_root(void *edit_baton, svn_revnum_t base_revision, apr_pool_t *pool, void **root_baton)
292 {
293         PyObject *self = (PyObject *)edit_baton, *ret;
294         *root_baton = NULL;
295         ret = PyObject_CallMethod(self, "open_root", "l", base_revision);
296         if (ret == NULL)
297                 return py_svn_error();
298         *root_baton = (void *)ret;
299         return NULL;
300 }
301
302 static svn_error_t *py_cb_editor_delete_entry(const char *path, long revision, void *parent_baton, apr_pool_t *pool)
303 {
304         PyObject *self = (PyObject *)parent_baton, *ret;
305         ret = PyObject_CallMethod(self, "delete_entry", "sl", path, revision);
306         if (ret == NULL)
307                 return py_svn_error();
308         Py_DECREF(ret);
309         return NULL;
310 }
311
312 static svn_error_t *py_cb_editor_add_directory(const char *path, void *parent_baton, const char *copyfrom_path, long copyfrom_revision, apr_pool_t *pool, void **child_baton)
313 {
314         PyObject *self = (PyObject *)parent_baton, *ret;
315         *child_baton = NULL;
316         if (copyfrom_path == NULL) {
317                 ret = PyObject_CallMethod(self, "add_directory", "s", path);
318         } else {
319                 ret = PyObject_CallMethod(self, "add_directory", "ssl", path, copyfrom_path, copyfrom_revision);
320         }
321         if (ret == NULL)
322                 return py_svn_error();
323         *child_baton = (void *)ret;
324         return NULL;
325 }
326
327 static svn_error_t *py_cb_editor_open_directory(const char *path, void *parent_baton, long base_revision, apr_pool_t *pool, void **child_baton)
328 {
329         PyObject *self = (PyObject *)parent_baton, *ret;
330         *child_baton = NULL;
331         ret = PyObject_CallMethod(self, "open_directory", "sl", path, base_revision);
332         if (ret == NULL)
333                 return py_svn_error();
334         *child_baton = (void *)ret;
335         return NULL;
336 }
337
338 static svn_error_t *py_cb_editor_change_prop(void *dir_baton, const char *name, const svn_string_t *value, apr_pool_t *pool)
339 {
340         PyObject *self = (PyObject *)dir_baton, *ret;
341
342         if (value != NULL) {
343                 ret = PyObject_CallMethod(self, "change_prop", "sz#", name, value->data, value->len);
344         } else {
345                 ret = PyObject_CallMethod(self, "change_prop", "sO", name, Py_None);
346         }
347         if (ret == NULL)
348                 return py_svn_error();
349         Py_DECREF(ret);
350         return NULL;
351 }
352
353 static svn_error_t *py_cb_editor_close_directory(void *dir_baton, apr_pool_t *pool)
354 {
355         PyObject *self = (PyObject *)dir_baton, *ret;
356         ret = PyObject_CallMethod(self, "close", "");
357         Py_DECREF(self);
358         if (ret == NULL)
359                 return py_svn_error();
360         Py_DECREF(ret);
361         return NULL;
362 }
363
364 static svn_error_t *py_cb_editor_absent_directory(const char *path, void *parent_baton, apr_pool_t *pool)
365 {
366         PyObject *self = (PyObject *)parent_baton, *ret;
367         ret = PyObject_CallMethod(self, "absent_directory", "s", path);
368         if (ret == NULL)
369                 return py_svn_error();
370         Py_DECREF(ret);
371         return NULL;
372 }
373
374 static svn_error_t *py_cb_editor_add_file(const char *path, void *parent_baton, const char *copy_path, long copy_revision, apr_pool_t *file_pool, void **file_baton)
375 {
376         PyObject *self = (PyObject *)parent_baton, *ret;
377         if (copy_path == NULL) {
378                 ret = PyObject_CallMethod(self, "add_file", "s", path);
379         } else {
380                 ret = PyObject_CallMethod(self, "add_file", "ssl", path, copy_path, 
381                                                                   copy_revision);
382         }
383         if (ret == NULL)
384                 return py_svn_error();
385         *file_baton = (void *)ret;
386         return NULL;
387 }
388
389 static svn_error_t *py_cb_editor_open_file(const char *path, void *parent_baton, long base_revision, apr_pool_t *file_pool, void **file_baton)
390 {
391         PyObject *self = (PyObject *)parent_baton, *ret;
392         ret = PyObject_CallMethod(self, "open_file", "sl", path, base_revision);
393         if (ret == NULL)
394                 return py_svn_error();
395         *file_baton = (void *)ret;
396         return NULL;
397 }
398
399 static svn_error_t *py_txdelta_window_handler(svn_txdelta_window_t *window, void *baton)
400 {
401         int i;
402         PyObject *ops, *ret;
403         PyObject *fn = (PyObject *)baton, *py_new_data, *py_window;
404         if (fn == Py_None) {
405                 /* User doesn't care about deltas */
406                 return NULL;
407         }
408
409         if (window == NULL) {
410                 py_window = Py_None;
411                 Py_INCREF(py_window);
412         } else {
413                 ops = PyList_New(window->num_ops);
414                 if (ops == NULL)
415                         return NULL;
416                 for (i = 0; i < window->num_ops; i++) {
417                         PyList_SetItem(ops, i, Py_BuildValue("(iII)", window->ops[i].action_code, 
418                                                 window->ops[i].offset, 
419                                                 window->ops[i].length));
420                 }
421                 if (window->new_data != NULL && window->new_data->data != NULL) {
422                         py_new_data = PyString_FromStringAndSize(window->new_data->data, window->new_data->len);
423                 } else {
424                         py_new_data = Py_None;
425                 }
426                 py_window = Py_BuildValue("((LIIiOO))", window->sview_offset, window->sview_len, window->tview_len, 
427                                                                         window->src_ops, ops, py_new_data);
428                 Py_DECREF(ops);
429                 Py_DECREF(py_new_data);
430         }
431         ret = PyObject_CallFunction(fn, "O", py_window);
432         Py_DECREF(py_window);
433         if (window == NULL) {
434                 /* Signals all delta windows have been received */
435                 Py_DECREF(fn);
436         }
437         if (ret == NULL)
438                 return py_svn_error();
439         Py_DECREF(ret);
440         return NULL;
441 }
442
443 static svn_error_t *py_cb_editor_apply_textdelta(void *file_baton, const char *base_checksum, apr_pool_t *pool, svn_txdelta_window_handler_t *handler, void **handler_baton)
444 {
445         PyObject *self = (PyObject *)file_baton, *ret;
446         *handler_baton = NULL;
447
448         ret = PyObject_CallMethod(self, "apply_textdelta", "z", base_checksum);
449         if (ret == NULL)
450                 return py_svn_error();
451         *handler_baton = (void *)ret;
452         *handler = py_txdelta_window_handler;
453         return NULL;
454 }
455
456 static svn_error_t *py_cb_editor_close_file(void *file_baton, 
457                                                                                  const char *text_checksum, apr_pool_t *pool)
458 {
459         PyObject *self = (PyObject *)file_baton, *ret;
460
461         if (text_checksum != NULL) {
462                 ret = PyObject_CallMethod(self, "close", "");
463         } else {
464                 ret = PyObject_CallMethod(self, "close", "s", text_checksum);
465         }
466         Py_DECREF(self);
467         if (ret == NULL)
468                 return py_svn_error();
469         Py_DECREF(ret);
470         return NULL;
471 }
472
473 static svn_error_t *py_cb_editor_absent_file(const char *path, void *parent_baton, apr_pool_t *pool)
474 {
475         PyObject *self = (PyObject *)parent_baton, *ret;
476         ret = PyObject_CallMethod(self, "absent_file", "s", path);
477         if (ret == NULL)
478                 return py_svn_error();
479         Py_DECREF(ret);
480         return NULL;
481 }
482
483 static svn_error_t *py_cb_editor_close_edit(void *edit_baton, apr_pool_t *pool)
484 {
485         PyObject *self = (PyObject *)edit_baton, *ret;
486         ret = PyObject_CallMethod(self, "close", "");
487         Py_DECREF(self);
488         if (ret == NULL)
489                 return py_svn_error();
490         Py_DECREF(ret);
491         return NULL;
492 }
493
494 static svn_error_t *py_cb_editor_abort_edit(void *edit_baton, apr_pool_t *pool)
495 {
496         PyObject *self = (PyObject *)edit_baton, *ret;
497         ret = PyObject_CallMethod(self, "abort", "");
498         Py_DECREF(self);
499         if (ret == NULL)
500                 return py_svn_error();
501         Py_DECREF(ret);
502         return NULL;
503 }
504
505 static const svn_delta_editor_t py_editor = {
506         py_cb_editor_set_target_revision,
507         py_cb_editor_open_root,
508         py_cb_editor_delete_entry,
509         py_cb_editor_add_directory,
510         py_cb_editor_open_directory,
511         py_cb_editor_change_prop,
512         py_cb_editor_close_directory,
513         py_cb_editor_absent_directory,
514         py_cb_editor_add_file,
515         py_cb_editor_open_file,
516         py_cb_editor_apply_textdelta,
517         py_cb_editor_change_prop,
518         py_cb_editor_close_file,
519         py_cb_editor_absent_file,
520         py_cb_editor_close_edit,
521         py_cb_editor_abort_edit
522 };
523
524 static svn_error_t *py_file_rev_handler(void *baton, const char *path, svn_revnum_t rev, apr_hash_t *rev_props, svn_txdelta_window_handler_t *delta_handler, void **delta_baton, apr_array_header_t *prop_diffs, apr_pool_t *pool)
525 {
526         PyObject *fn = (PyObject *)baton, *ret, *py_rev_props;
527
528         py_rev_props = prop_hash_to_dict(rev_props);
529         if (py_rev_props == NULL)
530                 return py_svn_error();
531
532         ret = PyObject_CallFunction(fn, "slO", path, rev, py_rev_props);
533         Py_DECREF(py_rev_props);
534         if (ret == NULL)
535                 return py_svn_error();
536
537         *delta_baton = (void *)ret;
538         *delta_handler = py_txdelta_window_handler;
539         return NULL;
540 }
541
542
543 static void ra_done_handler(void *_ra)
544 {
545         RemoteAccessObject *ra = (RemoteAccessObject *)_ra;
546
547         ra->busy = false;
548
549         Py_XDECREF(ra);
550 }
551
552 #define RUN_RA_WITH_POOL(pool, ra, cmd)  \
553         if (!check_error((cmd))) { \
554                 apr_pool_destroy(pool); \
555                 ra->busy = false; \
556                 return NULL; \
557         } \
558         ra->busy = false;
559
560 static bool ra_check_busy(RemoteAccessObject *raobj)
561 {
562         if (raobj->busy) {
563                 PyErr_SetString(busy_exc, "Remote access object already in use");
564                 return true;
565         }
566         raobj->busy = true;
567         return false;
568 }
569
570 #if SVN_VER_MAJOR >= 1 && SVN_VER_MINOR >= 5
571 static svn_error_t *py_get_client_string(void *baton, const char **name, apr_pool_t *pool)
572 {
573         RemoteAccessObject *self = (RemoteAccessObject *)baton;
574         PyObject *ret;
575
576         if (self->client_string_func == Py_None) {
577                 *name = NULL;
578                 return NULL;
579         }
580
581         ret = PyObject_CallFunction(self->client_string_func, "");
582
583         if (ret == NULL)
584                 return py_svn_error();
585
586         *name = apr_pstrdup(pool, PyString_AsString(ret));
587         Py_DECREF(ret);
588
589         return NULL;
590 }
591 #endif
592
593 /* Based on svn_swig_py_make_file() from Subversion */
594 static svn_error_t *py_open_tmp_file(apr_file_t **fp, void *callback,
595                                                                          apr_pool_t *pool)
596 {
597         RemoteAccessObject *self = (RemoteAccessObject *)callback;
598         PyObject *ret;
599         apr_status_t status;
600
601         if (self->open_tmp_file_func == Py_None) {
602                 const char *path;
603
604                 SVN_ERR (svn_io_temp_dir (&path, pool));
605                 path = svn_path_join (path, "tempfile", pool);
606                 SVN_ERR (svn_io_open_unique_file (fp, NULL, path, ".tmp", TRUE, pool));
607
608                 return NULL;
609         }
610
611         ret = PyObject_CallFunction(self->open_tmp_file_func, "");
612
613         if (ret == NULL) 
614                 return py_svn_error();
615         
616         if (PyString_Check(ret)) {
617                 char* fname = PyString_AsString(ret);
618                 status = apr_file_open(fp, fname, APR_CREATE | APR_READ | APR_WRITE, APR_OS_DEFAULT, 
619                                                                 pool);
620                 if (status) {
621                         PyErr_SetAprStatus(status);
622                         Py_DECREF(ret);
623                         return NULL;
624                 }
625                 Py_DECREF(ret);
626         } else if (PyFile_Check(ret)) {
627                 FILE *file;
628                 apr_os_file_t osfile;
629
630                 file = PyFile_AsFile(ret);
631 #ifdef WIN32
632                 osfile = (apr_os_file_t)_get_osfhandle(_fileno(file));
633 #else
634                 osfile = (apr_os_file_t)fileno(file);
635 #endif
636                 status = apr_os_file_put(fp, &osfile, O_CREAT | O_WRONLY, pool);
637                 if (status) {
638                         PyErr_SetAprStatus(status);
639                         Py_DECREF(ret);
640                         return NULL;
641                 }
642         } else {
643                 PyErr_SetString(PyExc_TypeError, "Unknown type for file variable");
644                 Py_DECREF(ret);
645                 return NULL;
646         }       
647
648         return NULL;
649 }
650
651 static void py_progress_func(apr_off_t progress, apr_off_t total, void *baton, apr_pool_t *pool)
652 {
653         RemoteAccessObject *ra = (RemoteAccessObject *)baton;
654         PyObject *fn = (PyObject *)ra->progress_func, *ret;
655         if (fn == Py_None) {
656                 return;
657         }
658         ret = PyObject_CallFunction(fn, "ll", progress, total);
659         /* TODO: What to do with exceptions raised here ? */
660         Py_XDECREF(ret);
661 }
662
663 static PyObject *ra_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
664 {
665         char *kwnames[] = { "url", "progress_cb", "auth", "config", "client_string_func", 
666                                                 "open_tmp_file_func", NULL };
667         char *url;
668         PyObject *progress_cb = Py_None;
669         AuthObject *auth = (AuthObject *)Py_None;
670         PyObject *config = Py_None;
671         PyObject *client_string_func = Py_None, *open_tmp_file_func = Py_None;
672         RemoteAccessObject *ret;
673         apr_hash_t *config_hash;
674         svn_ra_callbacks2_t *callbacks2;
675         svn_auth_baton_t *auth_baton;
676
677         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|OOOOO", kwnames, &url, &progress_cb, 
678                                                                          (PyObject **)&auth, &config, &client_string_func,
679                                                                          &open_tmp_file_func))
680                 return NULL;
681
682         ret = PyObject_New(RemoteAccessObject, &RemoteAccess_Type);
683         if (ret == NULL)
684                 return NULL;
685
686         if ((PyObject *)auth == Py_None) {
687                 auth_baton = NULL;
688                 ret->auth = NULL;
689         } else {
690                 /* FIXME: check auth is an instance of Auth_Type */
691                 Py_INCREF(auth);
692                 ret->auth = auth;
693                 auth_baton = ret->auth->auth_baton;
694         }
695
696         ret->root = NULL;
697         ret->pool = Pool(NULL);
698         if (ret->pool == NULL)
699                 return NULL;
700         ret->url = apr_pstrdup(ret->pool, url);
701         if (!check_error(svn_ra_create_callbacks(&callbacks2, ret->pool))) {
702                 apr_pool_destroy(ret->pool);
703                 PyObject_Del(ret);
704                 return NULL;
705         }
706
707         ret->client_string_func = client_string_func;
708         ret->open_tmp_file_func = open_tmp_file_func;
709         Py_INCREF(client_string_func);
710         callbacks2->progress_func = py_progress_func;
711         callbacks2->auth_baton = auth_baton;
712         callbacks2->open_tmp_file = py_open_tmp_file;
713         ret->progress_func = progress_cb;
714         callbacks2->progress_baton = (void *)ret;
715 #if SVN_VER_MAJOR >= 1 && SVN_VER_MINOR >= 5
716         callbacks2->get_client_string = py_get_client_string;
717 #endif
718         Py_INCREF(config);
719         config_hash = config_hash_from_object(config, ret->pool);
720         if (config_hash == NULL) {
721                 apr_pool_destroy(ret->pool);
722                 PyObject_Del(ret);
723                 return NULL;
724         }
725         if (!check_error(svn_ra_open2(&ret->ra, apr_pstrdup(ret->pool, url), 
726                                                                   callbacks2, ret, config_hash, ret->pool))) {
727                 apr_pool_destroy(ret->pool);
728                 PyObject_Del(ret);
729                 return NULL;
730         }
731         ret->busy = false;
732         return (PyObject *)ret;
733 }
734
735  /**
736   * Obtain the globally unique identifier for this repository.
737   */
738 static PyObject *ra_get_uuid(PyObject *self)
739 {
740         const char *uuid;
741         RemoteAccessObject *ra = (RemoteAccessObject *)self;
742         PyObject *ret;
743         apr_pool_t *temp_pool;
744
745         if (ra_check_busy(ra))
746                 return NULL;
747
748         temp_pool = Pool(NULL);
749         if (temp_pool == NULL)
750                 return NULL;
751         RUN_RA_WITH_POOL(temp_pool, ra, svn_ra_get_uuid(ra->ra, &uuid, temp_pool));
752         ret = PyString_FromString(uuid);
753         apr_pool_destroy(temp_pool);
754         return ret;
755 }
756
757 /** Switch to a different url. */
758 static PyObject *ra_reparent(PyObject *self, PyObject *args)
759 {
760         char *url;
761         apr_pool_t *temp_pool;
762         RemoteAccessObject *ra = (RemoteAccessObject *)self;
763
764         if (!PyArg_ParseTuple(args, "s", &url))
765                 return NULL;
766
767         if (ra_check_busy(ra))
768                 return NULL;
769
770         temp_pool = Pool(NULL);
771         if (temp_pool == NULL)
772                 return NULL;
773         ra->url = svn_path_canonicalize(url, ra->pool);
774         RUN_RA_WITH_POOL(temp_pool, ra, svn_ra_reparent(ra->ra, ra->url, temp_pool));
775         apr_pool_destroy(temp_pool);
776         Py_RETURN_NONE;
777 }
778
779 /**
780  * Obtain the number of the latest committed revision in the 
781  * connected repository.
782  */
783 static PyObject *ra_get_latest_revnum(PyObject *self)
784 {
785         RemoteAccessObject *ra = (RemoteAccessObject *)self;
786         svn_revnum_t latest_revnum;
787         apr_pool_t *temp_pool;
788         if (ra_check_busy(ra))
789                 return NULL;
790
791         temp_pool = Pool(NULL);
792         if (temp_pool == NULL)
793                 return NULL;
794         RUN_RA_WITH_POOL(temp_pool, ra,
795                                   svn_ra_get_latest_revnum(ra->ra, &latest_revnum, temp_pool));
796         apr_pool_destroy(temp_pool);
797         return PyInt_FromLong(latest_revnum);
798 }
799
800 static PyObject *ra_get_log(PyObject *self, PyObject *args, PyObject *kwargs)
801 {
802         char *kwnames[] = { "callback", "paths", "start", "end", "limit",
803                 "discover_changed_paths", "strict_node_history", "include_merged_revisions", "revprops", NULL };
804         PyObject *callback, *paths;
805         svn_revnum_t start = 0, end = 0;
806         int limit=0; 
807         bool discover_changed_paths=false, strict_node_history=true,include_merged_revisions=false;
808         RemoteAccessObject *ra = (RemoteAccessObject *)self;
809         PyObject *revprops = Py_None;
810         apr_pool_t *temp_pool;
811         apr_array_header_t *apr_paths;
812         apr_array_header_t *apr_revprops;
813
814         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OOll|ibbbO:get_log", kwnames, 
815                                                  &callback, &paths, &start, &end, &limit,
816                                                  &discover_changed_paths, &strict_node_history,
817                                                  &include_merged_revisions, &revprops))
818                 return NULL;
819
820         if (ra_check_busy(ra))
821                 return NULL;
822
823         temp_pool = Pool(NULL);
824         if (temp_pool == NULL)
825                 return NULL;
826         if (paths == Py_None) {
827                 /* FIXME: The subversion libraries don't behave as expected, 
828                  * so tweak our own parameters a bit. */
829                 apr_paths = apr_array_make(temp_pool, 1, sizeof(char *));
830                 APR_ARRAY_PUSH(apr_paths, char *) = apr_pstrdup(temp_pool, "");
831                 apr_paths = NULL;
832         } else if (!string_list_to_apr_array(temp_pool, paths, &apr_paths)) {
833                 apr_pool_destroy(temp_pool);
834                 return NULL;
835         }
836
837 #if SVN_VER_MAJOR <= 1 && SVN_VER_MINOR < 5
838         if (revprops == Py_None) {
839                 PyErr_SetString(PyExc_NotImplementedError, "fetching all revision properties not supported");   
840                 apr_pool_destroy(temp_pool);
841                 return NULL;
842         } else if (!PyList_Check(revprops)) {
843                 PyErr_SetString(PyExc_TypeError, "revprops should be a list");
844                 apr_pool_destroy(temp_pool);
845                 return NULL;
846         } else {
847                 int i;
848                 for (i = 0; i < PyList_Size(revprops); i++) {
849                         const char *n = PyString_AsString(PyList_GetItem(revprops, i));
850                         if (strcmp(SVN_PROP_REVISION_LOG, n) && 
851                                 strcmp(SVN_PROP_REVISION_AUTHOR, n) &&
852                                 strcmp(SVN_PROP_REVISION_DATE, n)) {
853                                 PyErr_SetString(PyExc_NotImplementedError, 
854                                                                 "fetching custom revision properties not supported");   
855                                 apr_pool_destroy(temp_pool);
856                                 return NULL;
857                         }
858                 }
859         }
860
861         if (include_merged_revisions) {
862                 PyErr_SetString(PyExc_NotImplementedError, "include_merged_revisions not supported in Subversion 1.4");
863                 apr_pool_destroy(temp_pool);
864                 return NULL;
865         }
866 #endif
867
868         if (!string_list_to_apr_array(temp_pool, revprops, &apr_revprops)) {
869                 apr_pool_destroy(temp_pool);
870                 return NULL;
871         }
872
873 #if SVN_VER_MAJOR == 1 && SVN_VER_MINOR >= 5
874         RUN_RA_WITH_POOL(temp_pool, ra, svn_ra_get_log2(ra->ra, 
875                         apr_paths, start, end, limit,
876                         discover_changed_paths, strict_node_history, 
877                         include_merged_revisions,
878                         apr_revprops,
879                         py_svn_log_entry_receiver, 
880                         callback, temp_pool));
881 #else
882         RUN_RA_WITH_POOL(temp_pool, ra, svn_ra_get_log(ra->ra, 
883                         apr_paths, start, end, limit,
884                         discover_changed_paths, strict_node_history, py_svn_log_wrapper, 
885                         callback, temp_pool));
886 #endif
887         apr_pool_destroy(temp_pool);
888         Py_RETURN_NONE;
889 }
890
891 /**
892  * Obtain the URL of the root of this repository.
893  */
894 static PyObject *ra_get_repos_root(PyObject *self)
895 {
896         RemoteAccessObject *ra = (RemoteAccessObject *)self;
897         const char *root;
898         apr_pool_t *temp_pool;
899
900         if (ra->root == NULL) {
901                 if (ra_check_busy(ra))
902                         return NULL;
903
904                 temp_pool = Pool(NULL);
905                 if (temp_pool == NULL)
906                         return NULL;
907                 RUN_RA_WITH_POOL(temp_pool, ra,
908                                                   svn_ra_get_repos_root(ra->ra, &root, temp_pool));
909                 ra->root = apr_pstrdup(ra->pool, root);
910                 apr_pool_destroy(temp_pool);
911         }
912
913         return PyString_FromString(ra->root);
914 }
915
916 static PyObject *ra_do_update(PyObject *self, PyObject *args)
917 {
918         svn_revnum_t revision_to_update_to;
919         char *update_target; 
920         bool recurse;
921         PyObject *update_editor;
922         const svn_ra_reporter2_t *reporter;
923         void *report_baton;
924         apr_pool_t *temp_pool;
925         ReporterObject *ret;
926         RemoteAccessObject *ra = (RemoteAccessObject *)self;
927
928         if (!PyArg_ParseTuple(args, "lsbO:do_update", &revision_to_update_to, &update_target, &recurse, &update_editor))
929                 return NULL;
930
931         if (ra_check_busy(ra))
932                 return NULL;
933
934         temp_pool = Pool(NULL);
935         if (temp_pool == NULL)
936                 return NULL;
937
938         Py_INCREF(update_editor);
939         if (!check_error(svn_ra_do_update(ra->ra, &reporter, 
940                                                                                                   &report_baton, 
941                                                                                                   revision_to_update_to, 
942                                                                                                   update_target, recurse, 
943                                                                                                   &py_editor, update_editor, 
944                                                                                                   temp_pool))) {
945                 apr_pool_destroy(temp_pool);
946                 ra->busy = false;
947                 return NULL;
948         }
949         ret = PyObject_New(ReporterObject, &Reporter_Type);
950         if (ret == NULL)
951                 return NULL;
952         ret->reporter = reporter;
953         ret->report_baton = report_baton;
954         ret->pool = temp_pool;
955         Py_INCREF(ra);
956         ret->ra = ra;
957         return (PyObject *)ret;
958 }
959
960 static PyObject *ra_do_switch(PyObject *self, PyObject *args)
961 {
962         RemoteAccessObject *ra = (RemoteAccessObject *)self;
963         svn_revnum_t revision_to_update_to;
964         char *update_target; 
965         bool recurse;
966         char *switch_url; 
967         PyObject *update_editor;
968         const svn_ra_reporter2_t *reporter;
969         void *report_baton;
970         apr_pool_t *temp_pool;
971         ReporterObject *ret;
972
973         if (!PyArg_ParseTuple(args, "lsbsO:do_switch", &revision_to_update_to, &update_target, 
974                                                   &recurse, &switch_url, &update_editor))
975                 return NULL;
976         if (ra_check_busy(ra))
977                 return NULL;
978
979         temp_pool = Pool(NULL);
980         if (temp_pool == NULL)
981                 return NULL;
982         Py_INCREF(update_editor);
983         if (!check_error(svn_ra_do_switch(
984                                                 ra->ra, &reporter, &report_baton, 
985                                                 revision_to_update_to, update_target, 
986                                                 recurse, switch_url, &py_editor, 
987                                                 update_editor, temp_pool))) {
988                 apr_pool_destroy(temp_pool);
989                 ra->busy = false;
990                 return NULL;
991         }
992         ret = PyObject_New(ReporterObject, &Reporter_Type);
993         if (ret == NULL)
994                 return NULL;
995         ret->reporter = reporter;
996         ret->report_baton = report_baton;
997         ret->pool = temp_pool;
998         Py_INCREF(ra);
999         ret->ra = ra;
1000         return (PyObject *)ret;
1001 }
1002
1003 static PyObject *ra_replay(PyObject *self, PyObject *args)
1004 {
1005         RemoteAccessObject *ra = (RemoteAccessObject *)self;
1006         apr_pool_t *temp_pool;
1007         svn_revnum_t revision, low_water_mark;
1008         PyObject *update_editor;
1009         bool send_deltas = true;
1010
1011         if (!PyArg_ParseTuple(args, "llO|b", &revision, &low_water_mark, &update_editor, &send_deltas))
1012                 return NULL;
1013
1014         if (ra_check_busy(ra))
1015                 return NULL;
1016
1017         temp_pool = Pool(NULL);
1018         if (temp_pool == NULL)
1019                 return NULL;
1020         Py_INCREF(update_editor);
1021         RUN_RA_WITH_POOL(temp_pool, ra,
1022                                           svn_ra_replay(ra->ra, revision, low_water_mark,
1023                                                                         send_deltas, &py_editor, update_editor, 
1024                                                                         temp_pool));
1025         apr_pool_destroy(temp_pool);
1026
1027         Py_RETURN_NONE;
1028 }
1029
1030 static svn_error_t *py_revstart_cb(svn_revnum_t revision, void *replay_baton,
1031    const svn_delta_editor_t **editor, void **edit_baton, apr_hash_t *rev_props, apr_pool_t *pool)
1032 {
1033         PyObject *cbs = (PyObject *)replay_baton;
1034         PyObject *py_start_fn = PyTuple_GetItem(cbs, 0);
1035         PyObject *py_revprops = prop_hash_to_dict(rev_props);
1036         PyObject *ret;
1037
1038         ret = PyObject_CallFunction(py_start_fn, "lO", revision, py_revprops);
1039         if (ret == NULL) 
1040                 return py_svn_error();
1041
1042         *editor = &py_editor;
1043         *edit_baton = ret;
1044
1045         return NULL;
1046 }
1047
1048 static svn_error_t *py_revfinish_cb(svn_revnum_t revision, void *replay_baton, 
1049                                                                         const svn_delta_editor_t *editor, void *edit_baton, 
1050                                                                         apr_hash_t *rev_props, apr_pool_t *pool)
1051 {
1052         PyObject *cbs = (PyObject *)replay_baton;
1053         PyObject *py_finish_fn = PyTuple_GetItem(cbs, 1);
1054         PyObject *py_revprops = prop_hash_to_dict(rev_props);
1055         PyObject *ret;
1056
1057         ret = PyObject_CallFunction(py_finish_fn, "lOO", revision, py_revprops, edit_baton);
1058         if (ret == NULL) 
1059                 return py_svn_error();
1060
1061         Py_DECREF((PyObject *)edit_baton);
1062         Py_DECREF(ret);
1063
1064         return NULL;
1065 }
1066
1067 static PyObject *ra_replay_range(PyObject *self, PyObject *args)
1068 {
1069 #if SVN_VER_MAJOR >= 1 && SVN_VER_MINOR >= 5
1070         RemoteAccessObject *ra = (RemoteAccessObject *)self;
1071         apr_pool_t *temp_pool;
1072         svn_revnum_t start_revision, end_revision, low_water_mark;
1073         PyObject *cbs;
1074         bool send_deltas = true;
1075
1076         if (!PyArg_ParseTuple(args, "lllO|b", &start_revision, &end_revision, &low_water_mark, &cbs, &send_deltas))
1077                 return NULL;
1078
1079         if (!PyTuple_Check(cbs)) {
1080                 PyErr_SetString(PyExc_TypeError, "Expected tuple with callbacks");
1081                 return NULL;
1082         }
1083
1084         if (ra_check_busy(ra))
1085                 return NULL;
1086
1087         temp_pool = Pool(NULL);
1088         if (temp_pool == NULL)
1089                 return NULL;
1090
1091         Py_INCREF(cbs);
1092         RUN_RA_WITH_POOL(temp_pool, ra,
1093                                           svn_ra_replay_range(ra->ra, start_revision, end_revision, low_water_mark,
1094                                                                         send_deltas, py_revstart_cb, py_revfinish_cb, cbs, 
1095                                                                         temp_pool));
1096         apr_pool_destroy(temp_pool);
1097
1098         Py_RETURN_NONE;
1099 #else
1100         PyErr_SetString(PyExc_NotImplementedError, "svn_ra_replay not available with Subversion 1.4");
1101         return NULL;
1102 #endif
1103 }
1104
1105
1106
1107 static PyObject *ra_rev_proplist(PyObject *self, PyObject *args)
1108 {
1109         apr_pool_t *temp_pool;
1110         apr_hash_t *props;
1111         RemoteAccessObject *ra = (RemoteAccessObject *)self;
1112         svn_revnum_t rev;
1113         PyObject *py_props;
1114         if (!PyArg_ParseTuple(args, "l", &rev))
1115                 return NULL;
1116
1117         if (ra_check_busy(ra))
1118                 return NULL;
1119
1120         temp_pool = Pool(NULL);
1121         if (temp_pool == NULL)
1122                 return NULL;
1123         RUN_RA_WITH_POOL(temp_pool, ra,
1124                                           svn_ra_rev_proplist(ra->ra, rev, &props, temp_pool));
1125         py_props = prop_hash_to_dict(props);
1126         apr_pool_destroy(temp_pool);
1127         return py_props;
1128 }
1129
1130 static PyObject *get_commit_editor(PyObject *self, PyObject *args, PyObject *kwargs)
1131 {
1132         char *kwnames[] = { "revprops", "callback", "lock_tokens", "keep_locks", 
1133                 NULL };
1134         PyObject *revprops, *commit_callback = Py_None, *lock_tokens = Py_None;
1135         bool keep_locks = false;
1136         apr_pool_t *pool;
1137         const svn_delta_editor_t *editor;
1138         void *edit_baton;
1139         RemoteAccessObject *ra = (RemoteAccessObject *)self;
1140         apr_hash_t *hash_lock_tokens;
1141
1142         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OOb", kwnames, &revprops, &commit_callback, &lock_tokens, &keep_locks))
1143                 return NULL;
1144
1145         pool = Pool(NULL);
1146         if (pool == NULL)
1147                 return NULL;
1148         if (lock_tokens == Py_None) {
1149                 hash_lock_tokens = NULL;
1150         } else {
1151                 Py_ssize_t idx = 0;
1152                 PyObject *k, *v;
1153                 hash_lock_tokens = apr_hash_make(pool);
1154                 while (PyDict_Next(lock_tokens, &idx, &k, &v)) {
1155                         apr_hash_set(hash_lock_tokens, PyString_AsString(k), 
1156                                                  PyString_Size(k), PyString_AsString(v));
1157                 }
1158         }
1159
1160         if (!PyDict_Check(revprops)) {
1161                 apr_pool_destroy(pool);
1162                 PyErr_SetString(PyExc_TypeError, "Expected dictionary with revision properties");
1163                 return NULL;
1164         }
1165
1166         if (ra_check_busy(ra))
1167                 return NULL;
1168
1169         if (!check_error(svn_ra_get_commit_editor2(ra->ra, &editor, 
1170                 &edit_baton, 
1171                 PyString_AsString(PyDict_GetItemString(revprops, SVN_PROP_REVISION_LOG)), py_commit_callback, 
1172                 commit_callback, hash_lock_tokens, keep_locks, pool))) {
1173                 apr_pool_destroy(pool);
1174                 ra->busy = false;
1175                 return NULL;
1176         }
1177
1178         Py_INCREF(ra);
1179         return new_editor_object(editor, edit_baton, pool, 
1180                                                                   &Editor_Type, ra_done_handler, ra);
1181 }
1182
1183 static PyObject *ra_change_rev_prop(PyObject *self, PyObject *args)
1184 {
1185         svn_revnum_t rev;
1186         char *name;
1187         RemoteAccessObject *ra = (RemoteAccessObject *)self;
1188         char *value;
1189         int vallen;
1190         apr_pool_t *temp_pool;
1191         svn_string_t *val_string;
1192
1193         if (!PyArg_ParseTuple(args, "lss#", &rev, &name, &value, &vallen))
1194                 return NULL;
1195         if (ra_check_busy(ra))
1196                 return NULL;
1197
1198         temp_pool = Pool(NULL);
1199         if (temp_pool == NULL)
1200                 return NULL;
1201         val_string = svn_string_ncreate(value, vallen, temp_pool);
1202         RUN_RA_WITH_POOL(temp_pool, ra,
1203                                           svn_ra_change_rev_prop(ra->ra, rev, name, val_string, 
1204                                                                                          temp_pool));
1205         apr_pool_destroy(temp_pool);
1206         Py_RETURN_NONE;
1207 }
1208         
1209 static PyObject *ra_get_dir(PyObject *self, PyObject *args)
1210 {
1211         apr_pool_t *temp_pool;
1212         apr_hash_t *dirents;
1213         apr_hash_index_t *idx;
1214         apr_hash_t *props;
1215         svn_revnum_t fetch_rev;
1216         const char *key;
1217         RemoteAccessObject *ra = (RemoteAccessObject *)self;
1218         svn_dirent_t *dirent;
1219         apr_ssize_t klen;
1220         char *path;
1221         svn_revnum_t revision = -1;
1222         int dirent_fields = 0;
1223         PyObject *py_dirents, *py_props;
1224
1225         if (!PyArg_ParseTuple(args, "s|li", &path, &revision, &dirent_fields))
1226                 return NULL;
1227
1228         if (ra_check_busy(ra))
1229                 return NULL;
1230
1231         temp_pool = Pool(NULL);
1232         if (temp_pool == NULL)
1233                 return NULL;
1234
1235         if (revision != SVN_INVALID_REVNUM)
1236                 fetch_rev = revision;
1237
1238         RUN_RA_WITH_POOL(temp_pool, ra, svn_ra_get_dir2(ra->ra, &dirents, &fetch_rev, &props,
1239                                          path, revision, dirent_fields, temp_pool));
1240
1241         if (dirents == NULL) {
1242                 py_dirents = Py_None;
1243         } else {
1244                 py_dirents = PyDict_New();
1245                 idx = apr_hash_first(temp_pool, dirents);
1246                 while (idx != NULL) {
1247                         PyObject *py_dirent;
1248                         apr_hash_this(idx, (const void **)&key, &klen, (void **)&dirent);
1249                         py_dirent = PyDict_New();
1250                         if (dirent_fields & 0x1)
1251                                 PyDict_SetItemString(py_dirent, "kind", 
1252                                                                          PyInt_FromLong(dirent->kind));
1253                         if (dirent_fields & 0x2)
1254                                 PyDict_SetItemString(py_dirent, "size", 
1255                                                                          PyLong_FromLong(dirent->size));
1256                         if (dirent_fields & 0x4)
1257                                 PyDict_SetItemString(py_dirent, "has_props",
1258                                                                          PyBool_FromLong(dirent->has_props));
1259                         if (dirent_fields & 0x8)
1260                                 PyDict_SetItemString(py_dirent, "created_rev", 
1261                                                                          PyLong_FromLong(dirent->created_rev));
1262                         if (dirent_fields & 0x10)
1263                                 PyDict_SetItemString(py_dirent, "time", 
1264                                                                          PyLong_FromLong(dirent->time));
1265                         if (dirent_fields & 0x20)
1266                                 PyDict_SetItemString(py_dirent, "last_author",
1267                                                                          PyString_FromString(dirent->last_author));
1268                         PyDict_SetItemString(py_dirents, key, py_dirent);
1269                         idx = apr_hash_next(idx);
1270                 }
1271         }
1272
1273         py_props = prop_hash_to_dict(props);
1274         if (py_props == NULL) {
1275                 apr_pool_destroy(temp_pool);
1276                 return NULL;
1277         }
1278         apr_pool_destroy(temp_pool);
1279         return Py_BuildValue("(NlN)", py_dirents, fetch_rev, py_props);
1280 }
1281
1282 static PyObject *ra_get_file(PyObject *self, PyObject *args)
1283 {
1284         char *path;
1285         svn_revnum_t revision = -1;
1286         RemoteAccessObject *ra = (RemoteAccessObject *)self;
1287         apr_hash_t *props;
1288         svn_revnum_t fetch_rev;
1289         PyObject *py_stream, *py_props;
1290         apr_pool_t *temp_pool;
1291
1292         if (!PyArg_ParseTuple(args, "sO|l", &path, &py_stream, &revision))
1293                 return NULL;
1294
1295         if (ra_check_busy(ra))
1296                 return NULL;
1297
1298         temp_pool = Pool(NULL);
1299         if (temp_pool == NULL)
1300                 return NULL;
1301
1302         if (revision != SVN_INVALID_REVNUM)
1303                 fetch_rev = revision;
1304
1305         RUN_RA_WITH_POOL(temp_pool, ra, svn_ra_get_file(ra->ra, path, revision, 
1306                                                                                                         new_py_stream(temp_pool, py_stream), 
1307                                                                                                         &fetch_rev, &props, temp_pool));
1308
1309         py_props = prop_hash_to_dict(props);
1310         if (py_props == NULL) {
1311                 apr_pool_destroy(temp_pool);
1312                 return NULL;
1313         }
1314
1315         apr_pool_destroy(temp_pool);
1316                  
1317         return Py_BuildValue("(lN)", fetch_rev, py_props);
1318 }
1319
1320 static PyObject *ra_get_lock(PyObject *self, PyObject *args)
1321 {
1322         char *path;
1323         RemoteAccessObject *ra = (RemoteAccessObject *)self;
1324         svn_lock_t *lock;
1325         apr_pool_t *temp_pool;
1326
1327         if (!PyArg_ParseTuple(args, "s", &path))
1328                 return NULL;
1329
1330         if (ra_check_busy(ra))
1331                 return NULL;
1332
1333         temp_pool = Pool(NULL);
1334         if (temp_pool == NULL)
1335                 return NULL;
1336         RUN_RA_WITH_POOL(temp_pool, ra,
1337                                   svn_ra_get_lock(ra->ra, &lock, path, temp_pool));
1338         apr_pool_destroy(temp_pool);
1339         return wrap_lock(lock);
1340 }
1341
1342 static PyObject *ra_check_path(PyObject *self, PyObject *args)
1343 {
1344         char *path; 
1345         RemoteAccessObject *ra = (RemoteAccessObject *)self;
1346         svn_revnum_t revision;
1347         svn_node_kind_t kind;
1348         apr_pool_t *temp_pool;
1349
1350         if (!PyArg_ParseTuple(args, "sl", &path, &revision))
1351                 return NULL;
1352         if (ra_check_busy(ra))
1353                 return NULL;
1354
1355         temp_pool = Pool(NULL);
1356         if (temp_pool == NULL)
1357                 return NULL;
1358         RUN_RA_WITH_POOL(temp_pool, ra,
1359                                           svn_ra_check_path(ra->ra, path, revision, &kind, 
1360                                          temp_pool));
1361         apr_pool_destroy(temp_pool);
1362         return PyInt_FromLong(kind);
1363 }
1364
1365 static PyObject *ra_has_capability(PyObject *self, PyObject *args)
1366 {
1367 #if SVN_VER_MAJOR >= 1 && SVN_VER_MINOR >= 5
1368         char *capability;
1369         apr_pool_t *temp_pool;
1370         RemoteAccessObject *ra = (RemoteAccessObject *)self;
1371         int has = 0;
1372
1373         if (!PyArg_ParseTuple(args, "s", &capability))
1374                 return NULL;
1375         
1376         if (ra_check_busy(ra))
1377                 return NULL;
1378
1379         temp_pool = Pool(NULL);
1380         if (temp_pool == NULL)
1381                 return NULL;
1382         RUN_RA_WITH_POOL(temp_pool, ra,
1383                                           svn_ra_has_capability(ra->ra, &has, capability, temp_pool));
1384         apr_pool_destroy(temp_pool);
1385         return PyBool_FromLong(has);
1386 #else
1387         PyErr_SetString(PyExc_NotImplementedError, "has_capability is only supported in Subversion >= 1.5");
1388         return NULL;
1389 #endif
1390 }
1391
1392 static PyObject *ra_unlock(PyObject *self, PyObject *args)
1393 {
1394         RemoteAccessObject *ra = (RemoteAccessObject *)self;
1395         PyObject *path_tokens, *lock_func, *k, *v;
1396         bool break_lock;
1397         apr_ssize_t idx;
1398         apr_pool_t *temp_pool;
1399         apr_hash_t *hash_path_tokens;
1400
1401         if (!PyArg_ParseTuple(args, "ObO", &path_tokens, &break_lock, &lock_func))
1402                 return NULL;
1403
1404         if (ra_check_busy(ra))
1405                 return NULL;
1406
1407         temp_pool = Pool(NULL);
1408         if (temp_pool == NULL)
1409                 return NULL;
1410         hash_path_tokens = apr_hash_make(temp_pool);
1411         while (PyDict_Next(path_tokens, &idx, &k, &v)) {
1412                 apr_hash_set(hash_path_tokens, PyString_AsString(k), PyString_Size(k), (char *)PyString_AsString(v));
1413         }
1414         RUN_RA_WITH_POOL(temp_pool, ra, svn_ra_unlock(ra->ra, hash_path_tokens, break_lock,
1415                                          py_lock_func, lock_func, temp_pool));
1416
1417         apr_pool_destroy(temp_pool);
1418         Py_RETURN_NONE;
1419 }
1420
1421 static PyObject *ra_lock(PyObject *self, PyObject *args)
1422 {
1423         RemoteAccessObject *ra = (RemoteAccessObject *)self;
1424         PyObject *path_revs;
1425         char *comment;
1426         int steal_lock;
1427         PyObject *lock_func, *k, *v;
1428         apr_pool_t *temp_pool;
1429         apr_hash_t *hash_path_revs;
1430         svn_revnum_t *rev;
1431         Py_ssize_t idx = 0;
1432
1433         if (!PyArg_ParseTuple(args, "OsbO", &path_revs, &comment, &steal_lock, 
1434                                                   &lock_func))
1435                 return NULL;
1436
1437         if (ra_check_busy(ra))
1438                 return NULL;
1439
1440         temp_pool = Pool(NULL);
1441         if (temp_pool == NULL)
1442                 return NULL;
1443         if (path_revs == Py_None) {
1444                 hash_path_revs = NULL;
1445         } else {
1446                 hash_path_revs = apr_hash_make(temp_pool);
1447         }
1448
1449         while (PyDict_Next(path_revs, &idx, &k, &v)) {
1450                 rev = (svn_revnum_t *)apr_palloc(temp_pool, sizeof(svn_revnum_t));
1451                 *rev = PyLong_AsLong(v);
1452                 apr_hash_set(hash_path_revs, PyString_AsString(k), PyString_Size(k), 
1453                                          PyString_AsString(v));
1454         }
1455         RUN_RA_WITH_POOL(temp_pool, ra, svn_ra_lock(ra->ra, hash_path_revs, comment, steal_lock,
1456                                          py_lock_func, lock_func, temp_pool));
1457         apr_pool_destroy(temp_pool);
1458         return NULL;
1459 }
1460
1461 static PyObject *ra_get_locks(PyObject *self, PyObject *args)
1462 {
1463         char *path;
1464         apr_pool_t *temp_pool;
1465         apr_hash_t *hash_locks;
1466         apr_hash_index_t *idx;
1467         RemoteAccessObject *ra = (RemoteAccessObject *)self;
1468         char *key;
1469         apr_ssize_t klen;
1470         svn_lock_t *lock;
1471         PyObject *ret;
1472
1473         if (!PyArg_ParseTuple(args, "s", &path))
1474                 return NULL;
1475
1476         if (ra_check_busy(ra))
1477                 return NULL;
1478
1479         temp_pool = Pool(NULL);
1480         if (temp_pool == NULL)
1481                 return NULL;
1482         RUN_RA_WITH_POOL(temp_pool, ra, svn_ra_get_locks(ra->ra, &hash_locks, path, temp_pool));
1483
1484         ret = PyDict_New();
1485         for (idx = apr_hash_first(temp_pool, hash_locks); idx != NULL;
1486                  idx = apr_hash_next(idx)) {
1487                 apr_hash_this(idx, (const void **)&key, &klen, (void **)&lock);
1488                 PyDict_SetItemString(ret, key, pyify_lock(lock));
1489         }
1490
1491         apr_pool_destroy(temp_pool);
1492         return ret;
1493 }
1494
1495 static PyObject *ra_get_locations(PyObject *self, PyObject *args)
1496 {
1497         char *path;
1498         RemoteAccessObject *ra = (RemoteAccessObject *)self;
1499         svn_revnum_t peg_revision;
1500         PyObject *location_revisions;
1501         apr_pool_t *temp_pool;
1502         apr_hash_t *hash_locations;
1503         apr_hash_index_t *idx;
1504         svn_revnum_t *key;
1505         PyObject *ret;
1506         apr_ssize_t klen;
1507         char *val;
1508
1509         if (!PyArg_ParseTuple(args, "slO", &path, &peg_revision, &location_revisions))
1510                 return NULL;
1511
1512         if (ra_check_busy(ra))
1513                 return NULL;
1514
1515         temp_pool = Pool(NULL);
1516         if (temp_pool == NULL)
1517                 return NULL;
1518         RUN_RA_WITH_POOL(temp_pool, ra, svn_ra_get_locations(ra->ra, &hash_locations,
1519                                         path, peg_revision, 
1520                                         revnum_list_to_apr_array(temp_pool, location_revisions),
1521                                         temp_pool));
1522         ret = PyDict_New();
1523
1524         for (idx = apr_hash_first(temp_pool, hash_locations); idx != NULL; 
1525                 idx = apr_hash_next(idx)) {
1526                 apr_hash_this(idx, (const void **)&key, &klen, (void **)&val);
1527                 PyDict_SetItem(ret, PyInt_FromLong(*key), PyString_FromString(val));
1528         }
1529         apr_pool_destroy(temp_pool);
1530         return ret;
1531 }
1532         
1533 static PyObject *ra_get_file_revs(PyObject *self, PyObject *args)
1534 {
1535         char *path;
1536         svn_revnum_t start, end;
1537         PyObject *file_rev_handler;
1538         apr_pool_t *temp_pool;
1539         RemoteAccessObject *ra = (RemoteAccessObject *)self;
1540
1541         if (!PyArg_ParseTuple(args, "sllO", &path, &start, &end, &file_rev_handler))
1542                 return NULL;
1543
1544         if (ra_check_busy(ra))
1545                 return NULL;
1546
1547         temp_pool = Pool(NULL);
1548         if (temp_pool == NULL)
1549                 return NULL;
1550
1551         RUN_RA_WITH_POOL(temp_pool, ra, svn_ra_get_file_revs(ra->ra, path, start, end, 
1552                                 py_file_rev_handler, (void *)file_rev_handler, 
1553                                         temp_pool));
1554
1555         apr_pool_destroy(temp_pool);
1556
1557         Py_RETURN_NONE;
1558 }
1559
1560 static void ra_dealloc(PyObject *self)
1561 {
1562         RemoteAccessObject *ra = (RemoteAccessObject *)self;
1563         Py_XDECREF(ra->progress_func);
1564         apr_pool_destroy(ra->pool);
1565         Py_XDECREF(ra->auth);
1566         PyObject_Del(self);
1567 }
1568
1569 static PyObject *ra_repr(PyObject *self)
1570 {
1571         RemoteAccessObject *ra = (RemoteAccessObject *)self;
1572         return PyString_FromFormat("RemoteAccess(%s)", ra->url);
1573 }
1574
1575 static int ra_set_progress_func(PyObject *self, PyObject *value, void *closure)
1576 {
1577         RemoteAccessObject *ra = (RemoteAccessObject *)self;
1578         Py_XDECREF(ra->progress_func);
1579         ra->progress_func = value;
1580         Py_INCREF(ra->progress_func);
1581         return 0;
1582 }
1583
1584 static PyGetSetDef ra_getsetters[] = { 
1585         { "progress_func", NULL, ra_set_progress_func, NULL },
1586         { NULL }
1587 };
1588
1589 static PyMethodDef ra_methods[] = {
1590         { "get_file_revs", ra_get_file_revs, METH_VARARGS, NULL },
1591         { "get_locations", ra_get_locations, METH_VARARGS, NULL },
1592         { "get_locks", ra_get_locks, METH_VARARGS, NULL },
1593         { "lock", ra_lock, METH_VARARGS, NULL },
1594         { "unlock", ra_unlock, METH_VARARGS, NULL },
1595         { "has_capability", ra_has_capability, METH_VARARGS, NULL },
1596         { "check_path", ra_check_path, METH_VARARGS, NULL },
1597         { "get_lock", ra_get_lock, METH_VARARGS, NULL },
1598         { "get_dir", ra_get_dir, METH_VARARGS, NULL },
1599         { "get_file", ra_get_file, METH_VARARGS, NULL },
1600         { "change_rev_prop", ra_change_rev_prop, METH_VARARGS, NULL },
1601         { "get_commit_editor", (PyCFunction)get_commit_editor, METH_VARARGS|METH_KEYWORDS, NULL },
1602         { "rev_proplist", ra_rev_proplist, METH_VARARGS, NULL },
1603         { "replay", ra_replay, METH_VARARGS, NULL },
1604         { "replay_range", ra_replay_range, METH_VARARGS, NULL },
1605         { "do_switch", ra_do_switch, METH_VARARGS, NULL },
1606         { "do_update", ra_do_update, METH_VARARGS, NULL },
1607         { "get_repos_root", (PyCFunction)ra_get_repos_root, METH_VARARGS|METH_NOARGS, NULL },
1608         { "get_log", (PyCFunction)ra_get_log, METH_VARARGS|METH_KEYWORDS, NULL },
1609         { "get_latest_revnum", (PyCFunction)ra_get_latest_revnum, METH_NOARGS, NULL },
1610         { "reparent", ra_reparent, METH_VARARGS, NULL },
1611         { "get_uuid", (PyCFunction)ra_get_uuid, METH_NOARGS, NULL },
1612         { NULL, }
1613 };
1614
1615 static PyMemberDef ra_members[] = {
1616         { "busy", T_BYTE, offsetof(RemoteAccessObject, busy), READONLY, NULL },
1617         { "url", T_STRING, offsetof(RemoteAccessObject, url), READONLY, NULL },
1618         { NULL, }
1619 };
1620
1621 PyTypeObject RemoteAccess_Type = {
1622         PyObject_HEAD_INIT(NULL) 0,
1623         "ra.RemoteAccess", /*   const char *tp_name;  For printing, in format "<module>.<name>" */
1624         sizeof(RemoteAccessObject), 
1625         0,/*    Py_ssize_t tp_basicsize, tp_itemsize;  For allocation */
1626         
1627         /* Methods to implement standard operations */
1628         
1629         ra_dealloc, /*  destructor tp_dealloc;  */
1630         NULL, /*        printfunc tp_print;     */
1631         NULL, /*        getattrfunc tp_getattr; */
1632         NULL, /*        setattrfunc tp_setattr; */
1633         NULL, /*        cmpfunc tp_compare;     */
1634         ra_repr, /*     reprfunc tp_repr;       */
1635         
1636         /* Method suites for standard classes */
1637         
1638         NULL, /*        PyNumberMethods *tp_as_number;  */
1639         NULL, /*        PySequenceMethods *tp_as_sequence;      */
1640         NULL, /*        PyMappingMethods *tp_as_mapping;        */
1641         
1642         /* More standard operations (here for binary compatibility) */
1643         
1644         NULL, /*        hashfunc tp_hash;       */
1645         NULL, /*        ternaryfunc tp_call;    */
1646         NULL, /*        reprfunc tp_str;        */
1647         NULL, /*        getattrofunc tp_getattro;       */
1648         NULL, /*        setattrofunc tp_setattro;       */
1649         
1650         /* Functions to access object as input/output buffer */
1651         NULL, /*        PyBufferProcs *tp_as_buffer;    */
1652         
1653         /* Flags to define presence of optional/expanded features */
1654         0, /*   long tp_flags;  */
1655         
1656         NULL, /*        const char *tp_doc;  Documentation string */
1657         
1658         /* Assigned meaning in release 2.0 */
1659         /* call function for all accessible objects */
1660         NULL, /*        traverseproc tp_traverse;       */
1661         
1662         /* delete references to contained objects */
1663         NULL, /*        inquiry tp_clear;       */
1664         
1665         /* Assigned meaning in release 2.1 */
1666         /* rich comparisons */
1667         NULL, /*        richcmpfunc tp_richcompare;     */
1668         
1669         /* weak reference enabler */
1670         0, /*   Py_ssize_t tp_weaklistoffset;   */
1671         
1672         /* Added in release 2.2 */
1673         /* Iterators */
1674         NULL, /*        getiterfunc tp_iter;    */
1675         NULL, /*        iternextfunc tp_iternext;       */
1676         
1677         /* Attribute descriptor and subclassing stuff */
1678         ra_methods, /*  struct PyMethodDef *tp_methods; */
1679         ra_members, /*  struct PyMemberDef *tp_members; */
1680         ra_getsetters, /*       struct PyGetSetDef *tp_getset;  */
1681         NULL, /*        struct _typeobject *tp_base;    */
1682         NULL, /*        PyObject *tp_dict;      */
1683         NULL, /*        descrgetfunc tp_descr_get;      */
1684         NULL, /*        descrsetfunc tp_descr_set;      */
1685         0, /*   Py_ssize_t tp_dictoffset;       */
1686         NULL, /*        initproc tp_init;       */
1687         NULL, /*        allocfunc tp_alloc;     */
1688         ra_new, /*      newfunc tp_new; */
1689
1690 };
1691
1692 typedef struct { 
1693         PyObject_HEAD
1694         apr_pool_t *pool;
1695         svn_auth_provider_object_t *provider;
1696 } AuthProviderObject;
1697
1698 static void auth_provider_dealloc(PyObject *self)
1699 {
1700         AuthProviderObject *auth_provider = (AuthProviderObject *)self;
1701         apr_pool_destroy(auth_provider->pool);
1702         PyObject_Del(self);
1703 }
1704
1705 PyTypeObject AuthProvider_Type = { 
1706         PyObject_HEAD_INIT(NULL) 0,
1707         "ra.AuthProvider", /*   const char *tp_name;  For printing, in format "<module>.<name>" */
1708         sizeof(AuthProviderObject), 
1709         0,/*    Py_ssize_t tp_basicsize, tp_itemsize;  For allocation */
1710         
1711         /* Methods to implement standard operations */
1712         
1713         auth_provider_dealloc, /*       destructor tp_dealloc;  */
1714
1715 };
1716
1717 static PyObject *auth_init(PyTypeObject *type, PyObject *args, PyObject *kwargs)
1718 {
1719         char *kwnames[] = { "providers", NULL };
1720         apr_array_header_t *c_providers;
1721         svn_auth_provider_object_t **el;
1722         PyObject *providers = Py_None;
1723         AuthObject *ret;
1724         int i;
1725
1726         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O", kwnames, &providers))
1727                 return NULL;
1728
1729         ret = PyObject_New(AuthObject, &Auth_Type);
1730         if (ret == NULL)
1731                 return NULL;
1732
1733         if (!PyList_Check(providers)) {
1734                 PyErr_SetString(PyExc_TypeError, "Auth providers should be list");
1735                 return NULL;
1736         }
1737
1738         ret->pool = Pool(NULL);
1739         if (ret->pool == NULL)
1740                 return NULL;
1741
1742         ret->providers = providers;
1743         Py_INCREF(providers);
1744
1745         c_providers = apr_array_make(ret->pool, PyList_Size(providers), sizeof(svn_auth_provider_object_t *));
1746         if (c_providers == NULL) {
1747                 PyErr_NoMemory();
1748                 return NULL;
1749         }
1750         for (i = 0; i < PyList_Size(providers); i++) {
1751                 AuthProviderObject *provider;
1752                 el = (svn_auth_provider_object_t **)apr_array_push(c_providers);
1753                 /* FIXME: Check that provider is indeed a AuthProviderObject object */
1754                 provider = (AuthProviderObject *)PyList_GetItem(providers, i);
1755                 *el = provider->provider;
1756         }
1757         svn_auth_open(&ret->auth_baton, c_providers, ret->pool);
1758         return (PyObject *)ret;
1759 }
1760
1761 static PyObject *auth_set_parameter(PyObject *self, PyObject *args)
1762 {
1763         AuthObject *auth = (AuthObject *)self;
1764         char *name;
1765         PyObject *value;
1766         void *vvalue;
1767         if (!PyArg_ParseTuple(args, "sO", &name, &value))
1768                 return NULL;
1769
1770         if (!strcmp(name, SVN_AUTH_PARAM_SSL_SERVER_FAILURES)) {
1771                 vvalue = apr_pcalloc(auth->pool, sizeof(apr_uint32_t));
1772                 *((apr_uint32_t *)vvalue) = PyInt_AsLong(value);
1773         } else if (!strcmp(name, SVN_AUTH_PARAM_DEFAULT_USERNAME) || 
1774                            !strcmp(name, SVN_AUTH_PARAM_DEFAULT_PASSWORD)) {
1775                 vvalue = apr_pstrdup(auth->pool, PyString_AsString(value));
1776         } else {
1777                 PyErr_Format(PyExc_TypeError, "Unsupported auth parameter %s", name);
1778                 return NULL;
1779         }
1780
1781         svn_auth_set_parameter(auth->auth_baton, name, (char *)vvalue);
1782
1783         Py_RETURN_NONE;
1784 }
1785
1786 static PyObject *auth_get_parameter(PyObject *self, PyObject *args)
1787 {
1788         char *name;
1789         const void *value;
1790         AuthObject *auth = (AuthObject *)self;
1791
1792         if (!PyArg_ParseTuple(args, "s", &name))
1793                 return NULL;
1794
1795         value = svn_auth_get_parameter(auth->auth_baton, name);
1796
1797         if (!strcmp(name, SVN_AUTH_PARAM_SSL_SERVER_FAILURES)) {
1798                 return PyInt_FromLong(*((apr_uint32_t *)value));
1799         } else if (!strcmp(name, SVN_AUTH_PARAM_DEFAULT_USERNAME) ||
1800                            !strcmp(name, SVN_AUTH_PARAM_DEFAULT_PASSWORD)) {
1801                 return PyString_FromString((const char *)value);
1802         } else {
1803                 PyErr_Format(PyExc_TypeError, "Unsupported auth parameter %s", name);
1804                 return NULL;
1805         }
1806 }
1807
1808 typedef struct { 
1809         PyObject_HEAD
1810         apr_pool_t *pool;
1811         char *cred_kind;
1812         svn_auth_iterstate_t *state;
1813         void *credentials;
1814 } CredentialsIterObject;
1815
1816 static PyObject *auth_first_credentials(PyObject *self, PyObject *args)
1817 {
1818         char *cred_kind;
1819         char *realmstring;
1820         AuthObject *auth = (AuthObject *)self;
1821         void *creds;
1822         apr_pool_t *pool;
1823         CredentialsIterObject *ret;
1824         svn_auth_iterstate_t *state;
1825         
1826         if (!PyArg_ParseTuple(args, "ss", &cred_kind, &realmstring))
1827                 return NULL;
1828
1829         pool = Pool(NULL);
1830         if (pool == NULL)
1831                 return NULL;
1832
1833         RUN_SVN_WITH_POOL(pool, 
1834                                           svn_auth_first_credentials(&creds, &state, cred_kind, realmstring, auth->auth_baton, pool));
1835
1836         ret = PyObject_New(CredentialsIterObject, &CredentialsIter_Type);
1837         if (ret == NULL)
1838                 return NULL;
1839
1840         ret->pool = pool;
1841         ret->cred_kind = apr_pstrdup(pool, cred_kind);
1842         ret->state = state;
1843         ret->credentials = creds;
1844
1845         return (PyObject *)ret;
1846 }
1847
1848 static void credentials_iter_dealloc(PyObject *self)
1849 {
1850         CredentialsIterObject *credsiter = (CredentialsIterObject *)self;
1851         apr_pool_destroy(credsiter->pool);
1852         PyObject_Del(self);
1853 }
1854
1855 static PyObject *credentials_iter_next(CredentialsIterObject *iterator)
1856 {
1857         PyObject *ret;
1858
1859         if (iterator->credentials == NULL) {
1860                 PyErr_SetString(PyExc_StopIteration, "No more credentials available");
1861                 return NULL;
1862         }
1863
1864         if (!strcmp(iterator->cred_kind, SVN_AUTH_CRED_SIMPLE)) {
1865                 svn_auth_cred_simple_t *simple = iterator->credentials;
1866                 ret = Py_BuildValue("(zzb)", simple->username, simple->password, simple->may_save);
1867         } else if (!strcmp(iterator->cred_kind, SVN_AUTH_CRED_USERNAME)) {
1868                 svn_auth_cred_username_t *uname = iterator->credentials;
1869                 ret = Py_BuildValue("(zb)", uname->username, uname->may_save);
1870         } else if (!strcmp(iterator->cred_kind, SVN_AUTH_CRED_SSL_CLIENT_CERT)) {
1871                 svn_auth_cred_ssl_client_cert_t *ccert = iterator->credentials;
1872                 ret = Py_BuildValue("(zb)", ccert->cert_file, ccert->may_save);
1873         } else if (!strcmp(iterator->cred_kind, SVN_AUTH_CRED_SSL_CLIENT_CERT_PW)) {
1874                 svn_auth_cred_ssl_client_cert_pw_t *ccert = iterator->credentials;
1875                 ret = Py_BuildValue("(zb)", ccert->password, ccert->may_save);
1876         } else if (!strcmp(iterator->cred_kind, SVN_AUTH_CRED_SSL_SERVER_TRUST)) {
1877                 svn_auth_cred_ssl_server_trust_t *ccert = iterator->credentials;
1878                 ret = Py_BuildValue("(ib)", ccert->accepted_failures, ccert->may_save);
1879         } else {
1880                 PyErr_Format(PyExc_RuntimeError, "Unknown cred kind %s", iterator->cred_kind);
1881                 return NULL;
1882         }
1883
1884         RUN_SVN_WITH_POOL(iterator->pool, 
1885                                           svn_auth_next_credentials(&iterator->credentials, iterator->state, iterator->pool));
1886
1887         return ret;
1888 }
1889
1890 PyTypeObject CredentialsIter_Type = {
1891         PyObject_HEAD_INIT(NULL) 0,
1892         "ra.CredentialsIter", /*        const char *tp_name;  For printing, in format "<module>.<name>" */
1893         sizeof(CredentialsIterObject), 
1894         0,/*    Py_ssize_t tp_basicsize, tp_itemsize;  For allocation */
1895         
1896         /* Methods to implement standard operations */
1897         
1898         (destructor)credentials_iter_dealloc, /*        destructor tp_dealloc;  */
1899         NULL, /*        printfunc tp_print;     */
1900         NULL, /*        getattrfunc tp_getattr; */
1901         NULL, /*        setattrfunc tp_setattr; */
1902         NULL, /*        cmpfunc tp_compare;     */
1903         NULL, /*        reprfunc tp_repr;       */
1904         
1905         /* Method suites for standard classes */
1906         
1907         NULL, /*        PyNumberMethods *tp_as_number;  */
1908         NULL, /*        PySequenceMethods *tp_as_sequence;      */
1909         NULL, /*        PyMappingMethods *tp_as_mapping;        */
1910         
1911         /* More standard operations (here for binary compatibility) */
1912         
1913         NULL, /*        hashfunc tp_hash;       */
1914         NULL, /*        ternaryfunc tp_call;    */
1915         NULL, /*        reprfunc tp_str;        */
1916         NULL, /*        getattrofunc tp_getattro;       */
1917         NULL, /*        setattrofunc tp_setattro;       */
1918         
1919         /* Functions to access object as input/output buffer */
1920         NULL, /*        PyBufferProcs *tp_as_buffer;    */
1921         
1922         /* Flags to define presence of optional/expanded features */
1923         0, /*   long tp_flags;  */
1924         
1925         NULL, /*        const char *tp_doc;  Documentation string */
1926         
1927         /* Assigned meaning in release 2.0 */
1928         /* call function for all accessible objects */
1929         NULL, /*        traverseproc tp_traverse;       */
1930         
1931         /* delete references to contained objects */
1932         NULL, /*        inquiry tp_clear;       */
1933         
1934         /* Assigned meaning in release 2.1 */
1935         /* rich comparisons */
1936         NULL, /*        richcmpfunc tp_richcompare;     */
1937         
1938         /* weak reference enabler */
1939         0, /*   Py_ssize_t tp_weaklistoffset;   */
1940         
1941         /* Added in release 2.2 */
1942         /* Iterators */
1943         NULL, /*        getiterfunc tp_iter;    */
1944         (iternextfunc)credentials_iter_next, /* iternextfunc tp_iternext;       */
1945
1946 };
1947
1948 static PyMethodDef auth_methods[] = {
1949         { "set_parameter", auth_set_parameter, METH_VARARGS, NULL },
1950         { "get_parameter", auth_get_parameter, METH_VARARGS, NULL },
1951         { "credentials", auth_first_credentials, METH_VARARGS, NULL },
1952         { NULL, }
1953 };
1954
1955 static void auth_dealloc(PyObject *self)
1956 {
1957         AuthObject *auth = (AuthObject *)self;
1958         apr_pool_destroy(auth->pool);
1959         Py_DECREF(auth->providers);     
1960 }
1961
1962 PyTypeObject Auth_Type = {
1963         PyObject_HEAD_INIT(NULL) 0,
1964         "ra.Auth", /*   const char *tp_name;  For printing, in format "<module>.<name>" */
1965         sizeof(AuthObject), 
1966         0,/*    Py_ssize_t tp_basicsize, tp_itemsize;  For allocation */
1967         
1968         /* Methods to implement standard operations */
1969         
1970         auth_dealloc, /*        destructor tp_dealloc;  */
1971         NULL, /*        printfunc tp_print;     */
1972         NULL, /*        getattrfunc tp_getattr; */
1973         NULL, /*        setattrfunc tp_setattr; */
1974         NULL, /*        cmpfunc tp_compare;     */
1975         NULL, /*        reprfunc tp_repr;       */
1976         
1977         /* Method suites for standard classes */
1978         
1979         NULL, /*        PyNumberMethods *tp_as_number;  */
1980         NULL, /*        PySequenceMethods *tp_as_sequence;      */
1981         NULL, /*        PyMappingMethods *tp_as_mapping;        */
1982         
1983         /* More standard operations (here for binary compatibility) */
1984         
1985         NULL, /*        hashfunc tp_hash;       */
1986         NULL, /*        ternaryfunc tp_call;    */
1987         NULL, /*        reprfunc tp_str;        */
1988         NULL, /*        getattrofunc tp_getattro;       */
1989         NULL, /*        setattrofunc tp_setattro;       */
1990         
1991         /* Functions to access object as input/output buffer */
1992         NULL, /*        PyBufferProcs *tp_as_buffer;    */
1993         
1994         /* Flags to define presence of optional/expanded features */
1995         0, /*   long tp_flags;  */
1996         
1997         NULL, /*        const char *tp_doc;  Documentation string */
1998         
1999         /* Assigned meaning in release 2.0 */
2000         /* call function for all accessible objects */
2001         NULL, /*        traverseproc tp_traverse;       */
2002         
2003         /* delete references to contained objects */
2004         NULL, /*        inquiry tp_clear;       */
2005         
2006         /* Assigned meaning in release 2.1 */
2007         /* rich comparisons */
2008         NULL, /*        richcmpfunc tp_richcompare;     */
2009         
2010         /* weak reference enabler */
2011         0, /*   Py_ssize_t tp_weaklistoffset;   */
2012         
2013         /* Added in release 2.2 */
2014         /* Iterators */
2015         NULL, /*        getiterfunc tp_iter;    */
2016         NULL, /*        iternextfunc tp_iternext;       */
2017         
2018         /* Attribute descriptor and subclassing stuff */
2019         auth_methods, /*        struct PyMethodDef *tp_methods; */
2020         NULL, /*        struct PyMemberDef *tp_members; */
2021         NULL, /*        struct PyGetSetDef *tp_getset;  */
2022         NULL, /*        struct _typeobject *tp_base;    */
2023         NULL, /*        PyObject *tp_dict;      */
2024         NULL, /*        descrgetfunc tp_descr_get;      */
2025         NULL, /*        descrsetfunc tp_descr_set;      */
2026         0, /*   Py_ssize_t tp_dictoffset;       */
2027         NULL, /*        initproc tp_init;       */
2028         NULL, /*        allocfunc tp_alloc;     */
2029         auth_init, /*   newfunc tp_new; */
2030
2031 };
2032
2033 static svn_error_t *py_username_prompt(svn_auth_cred_username_t **cred, void *baton, const char *realm, int may_save, apr_pool_t *pool)
2034 {
2035         PyObject *fn = (PyObject *)baton, *ret;
2036         PyObject *py_username, *py_may_save;
2037         ret = PyObject_CallFunction(fn, "sb", realm, may_save);
2038         if (ret == NULL)
2039                 return py_svn_error();
2040
2041         if (ret == Py_None)
2042                 return NULL;
2043
2044         if (!PyTuple_Check(ret)) {
2045                 PyErr_SetString(PyExc_TypeError, "expected tuple with username credentials");
2046                 return py_svn_error();
2047         }
2048
2049         if (PyTuple_Size(ret) != 2) {
2050                 PyErr_SetString(PyExc_TypeError, "expected tuple with username credentials to be size 2");
2051                 return py_svn_error();
2052         }
2053
2054         py_may_save = PyTuple_GetItem(ret, 1);
2055         if (!PyBool_Check(py_may_save)) {
2056                 PyErr_SetString(PyExc_TypeError, "may_save should be boolean");
2057                 return py_svn_error();
2058         }
2059         py_username = PyTuple_GetItem(ret, 0);
2060         if (!PyString_Check(py_username)) {
2061                 PyErr_SetString(PyExc_TypeError, "username hsould be string");
2062                 return py_svn_error();
2063         }
2064
2065         *cred = apr_pcalloc(pool, sizeof(**cred));
2066         (*cred)->username = apr_pstrdup(pool, PyString_AsString(py_username));
2067         (*cred)->may_save = (py_may_save == Py_True);
2068         Py_DECREF(ret);
2069         return NULL;
2070 }
2071
2072 static PyObject *get_username_prompt_provider(PyObject *self, PyObject *args)
2073 {
2074         AuthProviderObject *auth;
2075         PyObject *prompt_func;
2076         int retry_limit;
2077         if (!PyArg_ParseTuple(args, "Oi", &prompt_func, &retry_limit))
2078                 return NULL;
2079         auth = PyObject_New(AuthProviderObject, &AuthProvider_Type);
2080         auth->pool = Pool(NULL);
2081         if (auth->pool == NULL)
2082                 return NULL;
2083         Py_INCREF(prompt_func);
2084         svn_auth_get_username_prompt_provider(&auth->provider, py_username_prompt, (void *)prompt_func, retry_limit, auth->pool);
2085         return (PyObject *)auth;
2086 }
2087
2088 static svn_error_t *py_simple_prompt(svn_auth_cred_simple_t **cred, void *baton, const char *realm, const char *username, int may_save, apr_pool_t *pool)
2089 {
2090         PyObject *fn = (PyObject *)baton, *ret;
2091         PyObject *py_may_save, *py_username, *py_password;
2092         ret = PyObject_CallFunction(fn, "ssb", realm, username, may_save);
2093         if (ret == NULL)
2094                 return py_svn_error();
2095         if (!PyTuple_Check(ret)) {
2096                 PyErr_SetString(PyExc_TypeError, "expected tuple with simple credentials");
2097                 return py_svn_error();
2098         }
2099         if (PyTuple_Size(ret) != 3) {
2100                 PyErr_SetString(PyExc_TypeError, "expected tuple of size 3");
2101                 return py_svn_error();
2102         }
2103
2104         py_may_save = PyTuple_GetItem(ret, 2);
2105
2106         if (!PyBool_Check(py_may_save)) {
2107                 PyErr_SetString(PyExc_TypeError, "may_save should be boolean");
2108                 return py_svn_error();
2109         }
2110         
2111         py_username = PyTuple_GetItem(ret, 0);
2112         if (!PyString_Check(py_username)) {
2113                 PyErr_SetString(PyExc_TypeError, "username should be string");
2114                 return py_svn_error();
2115         }
2116
2117         py_password = PyTuple_GetItem(ret, 1);
2118         if (!PyString_Check(py_password)) {
2119                 PyErr_SetString(PyExc_TypeError, "password should be string");
2120                 return py_svn_error();
2121         }
2122
2123         *cred = apr_pcalloc(pool, sizeof(**cred));
2124         (*cred)->username = apr_pstrdup(pool, PyString_AsString(py_username));
2125         (*cred)->password = apr_pstrdup(pool, PyString_AsString(py_password));
2126         (*cred)->may_save = (py_may_save == Py_True);
2127         Py_DECREF(ret);
2128         return NULL;
2129 }
2130
2131 static PyObject *get_simple_prompt_provider(PyObject *self, PyObject *args)
2132 {
2133         PyObject *prompt_func;
2134         int retry_limit;
2135         AuthProviderObject *auth;
2136
2137         if (!PyArg_ParseTuple(args, "Oi", &prompt_func, &retry_limit))
2138                 return NULL;
2139
2140         auth = PyObject_New(AuthProviderObject, &AuthProvider_Type);
2141         auth->pool = Pool(NULL);
2142         if (auth->pool == NULL)
2143                 return NULL;
2144         Py_INCREF(prompt_func);
2145         svn_auth_get_simple_prompt_provider (&auth->provider, py_simple_prompt, (void *)prompt_func, retry_limit, auth->pool);
2146         return (PyObject *)auth;
2147 }
2148
2149 static svn_error_t *py_ssl_server_trust_prompt(svn_auth_cred_ssl_server_trust_t **cred, void *baton, const char *realm, apr_uint32_t failures, const svn_auth_ssl_server_cert_info_t *cert_info, svn_boolean_t may_save, apr_pool_t *pool)
2150 {
2151         PyObject *fn = (PyObject *)baton;
2152         PyObject *ret;
2153         PyObject *py_cert, *py_may_save, *py_accepted_failures;
2154
2155         if (cert_info == NULL) {
2156                 py_cert = Py_None;
2157         } else {
2158                 py_cert = Py_BuildValue("(sssss)", cert_info->hostname, cert_info->fingerprint, 
2159                                                   cert_info->valid_from, cert_info->valid_until, 
2160                                                   cert_info->issuer_dname, cert_info->ascii_cert);
2161         }
2162
2163         ret = PyObject_CallFunction(fn, "slOb", realm, failures, py_cert, may_save);
2164         Py_DECREF(py_cert);
2165         if (ret == NULL)
2166                 return py_svn_error();
2167
2168         if (!PyTuple_Check(ret)) {
2169                 PyErr_SetString(PyExc_TypeError, "expected tuple with server trust credentials");
2170                 return py_svn_error();
2171         }
2172         if (PyTuple_Size(ret) != 2) {
2173                 PyErr_SetString(PyExc_TypeError, "expected tuple of size 2");
2174                 return py_svn_error();
2175         }
2176
2177         py_accepted_failures = PyTuple_GetItem(ret, 0);
2178         if (!PyInt_Check(py_accepted_failures)) {
2179                 PyErr_SetString(PyExc_TypeError, "accepted_failures should be integer");
2180                 return py_svn_error();
2181         }
2182
2183         py_may_save = PyTuple_GetItem(ret, 1);
2184         if (!PyBool_Check(py_may_save)) {
2185                 PyErr_SetString(PyExc_TypeError, "may_save should be boolean");
2186                 return py_svn_error();
2187         }
2188         
2189         *cred = apr_pcalloc(pool, sizeof(**cred));
2190         (*cred)->accepted_failures = PyInt_AsLong(py_accepted_failures);
2191         (*cred)->may_save = (py_may_save == Py_True);
2192
2193         Py_DECREF(ret);
2194         return NULL;
2195 }
2196
2197 static PyObject *get_ssl_server_trust_prompt_provider(PyObject *self, PyObject *args)
2198 {
2199         AuthProviderObject *auth;
2200         PyObject *prompt_func;
2201
2202         if (!PyArg_ParseTuple(args, "O", &prompt_func))
2203                 return NULL;
2204
2205         auth = PyObject_New(AuthProviderObject, &AuthProvider_Type);
2206         if (auth == NULL)
2207                 return NULL;
2208         auth->pool = Pool(NULL);
2209         if (auth->pool == NULL)
2210                 return NULL;
2211         Py_INCREF(prompt_func);
2212         svn_auth_get_ssl_server_trust_prompt_provider (&auth->provider, py_ssl_server_trust_prompt, (void *)prompt_func, auth->pool);
2213         return (PyObject *)auth;
2214 }
2215
2216 static svn_error_t *py_ssl_client_cert_pw_prompt(svn_auth_cred_ssl_client_cert_pw_t **cred, void *baton, const char *realm, svn_boolean_t may_save, apr_pool_t *pool)
2217 {
2218         PyObject *fn = (PyObject *)baton, *ret, *py_may_save, *py_password;
2219         ret = PyObject_CallFunction(fn, "sb", realm, may_save);
2220         if (ret == NULL) 
2221                 return py_svn_error();
2222         if (!PyTuple_Check(ret)) {
2223                 PyErr_SetString(PyExc_TypeError, "expected tuple with client cert pw credentials");
2224                 return py_svn_error();
2225         }
2226
2227         if (PyTuple_Size(ret) != 2) {
2228                 PyErr_SetString(PyExc_TypeError, "expected tuple of size 2");
2229                 return py_svn_error();
2230         }
2231         py_may_save = PyTuple_GetItem(ret, 1);
2232         if (!PyBool_Check(py_may_save)) {
2233                 PyErr_SetString(PyExc_TypeError, "may_save should be boolean");
2234                 return py_svn_error();
2235         }
2236         py_password = PyTuple_GetItem(ret, 0);
2237         if (!PyString_Check(py_password)) {
2238                 PyErr_SetString(PyExc_TypeError, "password should be string");
2239                 return py_svn_error();
2240         }
2241         *cred = apr_pcalloc(pool, sizeof(**cred));
2242         (*cred)->password = apr_pstrdup(pool, PyString_AsString(py_password));
2243         (*cred)->may_save = (py_may_save == Py_True);
2244         Py_DECREF(ret);
2245         return NULL;
2246 }
2247
2248 static svn_error_t *py_ssl_client_cert_prompt(svn_auth_cred_ssl_client_cert_t **cred, void *baton, const char *realm, svn_boolean_t may_save, apr_pool_t *pool)
2249 {
2250         PyObject *fn = (PyObject *)baton, *ret, *py_may_save, *py_cert_file;
2251         ret = PyObject_CallFunction(fn, "sb", realm, may_save);
2252         if (ret == NULL) 
2253                 return py_svn_error();
2254
2255         if (!PyTuple_Check(ret)) {
2256                 PyErr_SetString(PyExc_TypeError, "expected tuple with client cert credentials");
2257                 return py_svn_error();
2258         }
2259
2260         if (PyTuple_Size(ret) != 2) {
2261                 PyErr_SetString(PyExc_TypeError, "expected tuple of size 2");
2262                 return py_svn_error();
2263         }
2264         py_may_save = PyTuple_GetItem(ret, 1);
2265         if (!PyBool_Check(py_may_save)) {
2266                 PyErr_SetString(PyExc_TypeError, "may_save should be boolean");
2267                 return py_svn_error();
2268         }
2269
2270         py_cert_file = PyTuple_GetItem(ret, 0);
2271         if (!PyString_Check(py_cert_file)) {
2272                 PyErr_SetString(PyExc_TypeError, "cert_file should be string");
2273                 return py_svn_error();
2274         }
2275
2276         *cred = apr_pcalloc(pool, sizeof(**cred));
2277         (*cred)->cert_file = apr_pstrdup(pool, PyString_AsString(py_cert_file));
2278         (*cred)->may_save = (py_may_save == Py_True);
2279         Py_DECREF(ret);
2280         return NULL;
2281 }
2282
2283
2284
2285 static PyObject *get_ssl_client_cert_pw_prompt_provider(PyObject *self, PyObject *args)
2286 {
2287         PyObject *prompt_func;
2288         int retry_limit;
2289         AuthProviderObject *auth;
2290
2291         if (!PyArg_ParseTuple(args, "Oi", &prompt_func, &retry_limit))
2292                 return NULL;
2293
2294         auth = PyObject_New(AuthProviderObject, &AuthProvider_Type);
2295         if (auth == NULL)
2296                 return NULL;
2297         auth->pool = Pool(NULL);
2298         if (auth->pool == NULL)
2299                 return NULL;
2300         Py_INCREF(prompt_func);
2301         svn_auth_get_ssl_client_cert_pw_prompt_provider (&auth->provider, py_ssl_client_cert_pw_prompt, (void *)prompt_func, retry_limit, auth->pool);
2302         return (PyObject *)auth;
2303 }
2304
2305 static PyObject *get_ssl_client_cert_prompt_provider(PyObject *self, PyObject *args)
2306 {
2307         PyObject *prompt_func;
2308         int retry_limit;
2309         AuthProviderObject *auth;
2310
2311         if (!PyArg_ParseTuple(args, "Oi", &prompt_func, &retry_limit))
2312                 return NULL;
2313
2314         auth = PyObject_New(AuthProviderObject, &AuthProvider_Type);
2315         if (auth == NULL)
2316                 return NULL;
2317         auth->pool = Pool(NULL);
2318         if (auth->pool == NULL)
2319                 return NULL;
2320         Py_INCREF(prompt_func);
2321         svn_auth_get_ssl_client_cert_prompt_provider (&auth->provider, py_ssl_client_cert_prompt, (void *)prompt_func, retry_limit, auth->pool);
2322         return (PyObject *)auth;
2323 }
2324
2325 static PyObject *get_username_provider(PyObject *self)
2326 {
2327         AuthProviderObject *auth;
2328         auth = PyObject_New(AuthProviderObject, &AuthProvider_Type);
2329         if (auth == NULL)
2330                 return NULL;
2331         auth->pool = Pool(NULL);
2332         if (auth->pool == NULL)
2333                 return NULL;
2334         svn_auth_get_username_provider(&auth->provider, auth->pool);
2335         return (PyObject *)auth;
2336 }
2337
2338 static PyObject *get_simple_provider(PyObject *self)
2339 {
2340         AuthProviderObject *auth = PyObject_New(AuthProviderObject, 
2341                                                                                         &AuthProvider_Type);
2342         auth->pool = Pool(NULL);
2343         if (auth->pool == NULL)
2344                 return NULL;
2345         svn_auth_get_simple_provider(&auth->provider, auth->pool);
2346         return (PyObject *)auth;
2347 }
2348
2349 static PyObject *get_ssl_server_trust_file_provider(PyObject *self)
2350 {
2351         AuthProviderObject *auth = PyObject_New(AuthProviderObject, &AuthProvider_Type);
2352         auth->pool = Pool(NULL);
2353         if (auth->pool == NULL)
2354                 return NULL;
2355         svn_auth_get_ssl_server_trust_file_provider(&auth->provider, auth->pool);
2356         return (PyObject *)auth;
2357 }
2358
2359 static PyObject *get_ssl_client_cert_file_provider(PyObject *self)
2360 {
2361         AuthProviderObject *auth = PyObject_New(AuthProviderObject, &AuthProvider_Type);
2362         auth->pool = Pool(NULL);
2363         if (auth->pool == NULL)
2364                 return NULL;
2365         svn_auth_get_ssl_client_cert_file_provider(&auth->provider, auth->pool);
2366         return (PyObject *)auth;
2367 }
2368
2369 static PyObject *get_ssl_client_cert_pw_file_provider(PyObject *self)
2370 {
2371         AuthProviderObject *auth = PyObject_New(AuthProviderObject, &AuthProvider_Type);
2372         auth->pool = Pool(NULL);
2373         if (auth->pool == NULL)
2374                 return NULL;
2375         svn_auth_get_ssl_client_cert_pw_file_provider(&auth->provider, auth->pool);
2376         return (PyObject *)auth;
2377 }
2378
2379 static PyMethodDef ra_module_methods[] = {
2380         { "version", (PyCFunction)version, METH_NOARGS, NULL },
2381         { "get_ssl_client_cert_pw_file_provider", (PyCFunction)get_ssl_client_cert_pw_file_provider, METH_NOARGS, NULL },
2382         { "get_ssl_client_cert_file_provider", (PyCFunction)get_ssl_client_cert_file_provider, METH_NOARGS, NULL },
2383         { "get_ssl_server_trust_file_provider", (PyCFunction)get_ssl_server_trust_file_provider, METH_NOARGS, NULL },
2384         { "get_simple_provider", (PyCFunction)get_simple_provider, METH_NOARGS, NULL },
2385         { "get_username_prompt_provider", (PyCFunction)get_username_prompt_provider, METH_VARARGS, NULL },
2386         { "get_simple_prompt_provider", (PyCFunction)get_simple_prompt_provider, METH_VARARGS, NULL },
2387         { "get_ssl_server_trust_prompt_provider", (PyCFunction)get_ssl_server_trust_prompt_provider, METH_VARARGS, NULL },
2388         { "get_ssl_client_cert_prompt_provider", (PyCFunction)get_ssl_client_cert_prompt_provider, METH_VARARGS, NULL },
2389         { "get_ssl_client_cert_pw_prompt_provider", (PyCFunction)get_ssl_client_cert_pw_prompt_provider, METH_VARARGS, NULL },
2390         { "get_username_provider", (PyCFunction)get_username_provider, METH_NOARGS, NULL },
2391         { NULL, }
2392 };
2393
2394 void initra(void)
2395 {
2396         static apr_pool_t *pool;
2397         PyObject *mod;
2398
2399         if (PyType_Ready(&RemoteAccess_Type) < 0)
2400                 return;
2401
2402         if (PyType_Ready(&Editor_Type) < 0)
2403                 return;
2404
2405         if (PyType_Ready(&FileEditor_Type) < 0)
2406                 return;
2407
2408         if (PyType_Ready(&DirectoryEditor_Type) < 0)
2409                 return;
2410
2411         if (PyType_Ready(&Reporter_Type) < 0)
2412                 return;
2413
2414         if (PyType_Ready(&TxDeltaWindowHandler_Type) < 0)
2415                 return;
2416
2417         if (PyType_Ready(&Auth_Type) < 0)
2418                 return;
2419
2420         if (PyType_Ready(&CredentialsIter_Type) < 0)
2421                 return;
2422
2423         if (PyType_Ready(&AuthProvider_Type) < 0)
2424                 return;
2425
2426         apr_initialize();
2427         pool = Pool(NULL);
2428         if (pool == NULL)
2429                 return;
2430         svn_ra_initialize(pool);
2431
2432         mod = Py_InitModule3("ra", ra_module_methods, "Remote Access");
2433         if (mod == NULL)
2434                 return;
2435
2436         PyModule_AddObject(mod, "RemoteAccess", (PyObject *)&RemoteAccess_Type);
2437         Py_INCREF(&RemoteAccess_Type);
2438
2439         PyModule_AddObject(mod, "Auth", (PyObject *)&Auth_Type);
2440         Py_INCREF(&Auth_Type);
2441
2442         busy_exc = PyErr_NewException("ra.BusyException", NULL, NULL);
2443         PyModule_AddObject(mod, "BusyException", busy_exc);
2444
2445         PyModule_AddIntConstant(mod, "DIRENT_KIND", SVN_DIRENT_KIND);
2446         PyModule_AddIntConstant(mod, "DIRENT_SIZE", SVN_DIRENT_SIZE);
2447         PyModule_AddIntConstant(mod, "DIRENT_HAS_PROPS", SVN_DIRENT_HAS_PROPS);
2448         PyModule_AddIntConstant(mod, "DIRENT_CREATED_REV", SVN_DIRENT_CREATED_REV);
2449         PyModule_AddIntConstant(mod, "DIRENT_TIME", SVN_DIRENT_TIME);
2450         PyModule_AddIntConstant(mod, "DIRENT_LAST_AUTHOR", SVN_DIRENT_LAST_AUTHOR);
2451         PyModule_AddIntConstant(mod, "DIRENT_ALL", SVN_DIRENT_ALL);
2452
2453 #ifdef SVN_VER_REVISION
2454         PyModule_AddIntConstant(mod, "SVN_REVISION", SVN_VER_REVISION);
2455 #endif
2456 }