/*============================================================================== Copyright (C) 2007 Martin Furter This file is part of svntar svntar is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. svntar is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with svntar; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. ==============================================================================*/ #include "svntar_support.h" #include "svn_config.h" #include "svn_path.h" #define SVNTAR_VERSION "0.3.0" #ifdef SVN_IO_PIPE_STDIN #define SVN_HAS_SVN_IO_START_CMD2 #endif /* Display a prompt and read a one-line response into the provided buffer, * removing a trailing newline if present. */ static svn_error_t* prompt_and_read_line( const char* prompt, char* buffer, size_t max ) { int len; printf( "%s: ", prompt ); if( fgets( buffer, max, stdin ) == NULL ) { return svn_error_create( 0, NULL, "error reading stdin" ); } len = strlen( buffer ); if( len > 0 && buffer[len-1] == '\n' ) { buffer[len-1] = 0; } return SVN_NO_ERROR; } /* A tiny callback function of type 'svn_auth_simple_prompt_func_t'. * For a much better example, see svn_cl__auth_simple_prompt in the * official svn cmdline client. */ static svn_error_t* my_simple_prompt_callback( svn_auth_cred_simple_t** cred, void* baton, const char* realm, const char* username, svn_boolean_t may_save, apr_pool_t* pool ) { svn_auth_cred_simple_t* ret = apr_pcalloc( pool, sizeof(* ret ) ); char answerbuf[100]; if( realm ) { printf( "Authentication realm: %s\n", realm ); } if( username ) { ret->username = apr_pstrdup( pool, username ); } else { SVN_ERR( prompt_and_read_line( "Username", answerbuf, sizeof( answerbuf ) ) ); ret->username = apr_pstrdup( pool, answerbuf ); } SVN_ERR( prompt_and_read_line( "Password", answerbuf, sizeof( answerbuf ) ) ); ret->password = apr_pstrdup( pool, answerbuf ); *cred = ret; return SVN_NO_ERROR; } /* A tiny callback function of type 'svn_auth_username_prompt_func_t'. * For a much better example, see svn_cl__auth_username_prompt in the * official svn cmdline client. */ static svn_error_t* my_username_prompt_callback( svn_auth_cred_username_t** cred, void* baton, const char* realm, svn_boolean_t may_save, apr_pool_t* pool ) { svn_auth_cred_username_t* ret = apr_pcalloc( pool, sizeof(* ret ) ); char answerbuf[100]; if( realm ) { printf( "Authentication realm: %s\n", realm ); } SVN_ERR( prompt_and_read_line( "Username", answerbuf, sizeof( answerbuf ) ) ); ret->username = apr_pstrdup( pool, answerbuf ); *cred = ret; return SVN_NO_ERROR; } svn_error_t* svntar_init_client_context( svn_client_ctx_t** pctx, apr_pool_t* pool ) { svn_client_ctx_t* ctx; svn_auth_provider_object_t* provider; /* Make sure the ~/.subversion run-time config files exist */ SVN_ERR( svn_config_ensure( NULL, pool ) ); /* Initialize and allocate the client_ctx object. */ SVN_ERR( svn_client_create_context( pctx, pool ) ); ctx = *pctx; /* Load the run-time config file into a hash */ SVN_ERR( svn_config_get_config( &( ctx->config ), NULL, pool ) ); #ifdef WIN32 /* Set the working copy administrative directory name. */ if( getenv( "SVN_ASP_DOT_NET_HACK" ) ) { SVN_ERR( svn_wc_set_adm_dir( "_svn", pool ) ); } #endif /* Depending on what your client does, you'll want to read about * (and implement) the various callback function types below. */ /* A func (& context) which receives event signals during * checkouts, updates, commits, etc. */ /* ctx->notify_func = my_notification_func; ctx->notify_baton = NULL; */ /* A func (& context) which can receive log messages */ /* ctx->log_msg_func = my_log_msg_receiver_func; ctx->log_msg_baton = NULL; */ /* A func (& context) which checks whether the user cancelled */ /* ctx->cancel_func = my_cancel_checking_func; ctx->cancel_baton = NULL; */ /* Make the client_ctx capable of authenticating users */ /* There are many different kinds of authentication back-end * "providers". See svn_auth.h for a full overview. * * If you want to get the auth behavior of the 'svn' program, * you can use svn_cmdline_setup_auth_baton, which will give * you the exact set of auth providers it uses. This program * doesn't use it because it's only appropriate for a command * line program, and this is supposed to be a general purpose * example. */ apr_array_header_t* providers = apr_array_make( pool, 4, sizeof( svn_auth_provider_object_t* ) ); svn_auth_get_simple_prompt_provider( &provider, my_simple_prompt_callback, NULL /* baton */, 2 /* retry limit */, pool ); APR_ARRAY_PUSH( providers, svn_auth_provider_object_t* )= provider; svn_auth_get_username_prompt_provider( &provider, my_username_prompt_callback, NULL /* baton */, 2 /* retry limit */, pool ); APR_ARRAY_PUSH( providers, svn_auth_provider_object_t* )= provider; /* Register the auth-providers into the context's auth_baton. */ svn_auth_open( &ctx->auth_baton, providers, pool ); return SVN_NO_ERROR; } #ifndef SVN_HAS_SVN_IO_START_CMD2 svn_error_t* svntar_start_cmd( apr_proc_t* cmd_proc, const char* const* args, apr_file_t* outfile, apr_pool_t* pool ) { apr_status_t apr_err; apr_procattr_t* cmdproc_attr; int num_args; const char** args_native; const char* cmd_apr; const char* cmd = args[0]; /* Create the process attributes. */ apr_err = apr_procattr_create( &cmdproc_attr, pool ); if( apr_err ) { return svn_error_wrap_apr( apr_err, _( "Can't create process '%s' attributes" ), cmd ); } /* Make sure we invoke cmd directly, not through a shell. */ apr_err = apr_procattr_cmdtype_set( cmdproc_attr, APR_PROGRAM_PATH ); if( apr_err ) { return svn_error_wrap_apr( apr_err, _( "Can't set process '%s' cmdtype" ), cmd ); } /* Use requested inputs and outputs. ### Unfortunately each of these apr functions creates a pipe and then overwrites the pipe file descriptor with the descriptor we pass in. The pipes can then never be closed. This is an APR bug. */ apr_procattr_io_set( cmdproc_attr, 1, 0, 0 ); if( outfile ) { apr_err = apr_procattr_child_out_set( cmdproc_attr, outfile, NULL ); if( apr_err ) { return svn_error_wrap_apr( apr_err, _( "Can't set process '%s' child outfile" ), cmd ); } } /* Convert cmd and args from UTF-8 */ SVN_ERR( svn_path_cstring_from_utf8( &cmd_apr, cmd, pool ) ); for( num_args = 0; args[num_args]; num_args++ ) { /* just counting */ } args_native = apr_palloc( pool,( num_args + 1 ) * sizeof(char*) ); args_native[num_args] = NULL; while( num_args-- ) { /* ### Well, it turns out that on APR on Windows expects all program args to be in UTF-8. Callers of svn_io_run_cmd should be aware of that. */ SVN_ERR( svn_path_cstring_from_utf8( &args_native[num_args], args[num_args], pool ) ); } /* Start the cmd command. */ apr_err = apr_proc_create( cmd_proc, cmd_apr, args_native, NULL, cmdproc_attr, pool ); if( apr_err ) { return svn_error_wrap_apr( apr_err, _( "Can't start process '%s'" ), cmd ); } return SVN_NO_ERROR; } #else /* !SVN_HAS_SVN_IO_START_CMD2 */ svn_error_t* svntar_start_cmd( apr_proc_t* cmd_proc, const char* const* args, apr_file_t* outfile, apr_pool_t* pool ) { return svn_io_start_cmd2( cmd_proc, ".", args[0], args, TRUE, NULL, file, NULL, SVN_IO_PIPE_STDIN, tb->pool ); } #endif /* !SVN_HAS_SVN_IO_START_CMD2 */