[vlc-devel] [RFC PATCH 3/8] dsm: refactorize

Thomas Guillem thomas at gllm.fr
Thu Nov 27 14:01:45 CET 2014



On Thu, Nov 27, 2014, at 12:00, Thomas Guillem wrote:
> Move browser.c to common.c. This new file contains common browsing
> functions
> that can be used from an access_t or from a services_discovery_t.
> ---
>  modules/access/Makefile.am   |   2 +-
>  modules/access/dsm/access.c  | 340 ++++++------------------------
>  modules/access/dsm/browser.c | 191 -----------------
>  modules/access/dsm/common.c  | 483
>  +++++++++++++++++++++++++++++++++++++++++++
>  modules/access/dsm/common.h  |  25 ++-
>  5 files changed, 572 insertions(+), 469 deletions(-)
>  delete mode 100644 modules/access/dsm/browser.c
>  create mode 100644 modules/access/dsm/common.c
> 
> diff --git a/modules/access/Makefile.am b/modules/access/Makefile.am
> index e154bee..528ddc0 100644
> --- a/modules/access/Makefile.am
> +++ b/modules/access/Makefile.am
> @@ -413,7 +413,7 @@ access_LTLIBRARIES += $(LTLIBsmb)
>  EXTRA_LTLIBRARIES += libsmb_plugin.la
>  
>  libdsm_plugin_la_SOURCES = access/dsm/access.c access/dsm/common.h \
> -       access/dsm/browser.c access/dsm/sd.c
> +       access/dsm/common.c access/dsm/sd.c
>  libdsm_plugin_la_CFLAGS = $(AM_CFLAGS) $(DSM_CFLAGS)
>  libdsm_plugin_la_LIBADD = $(DSM_LIBS)
>  libdsm_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(sddir)'
> diff --git a/modules/access/dsm/access.c b/modules/access/dsm/access.c
> index 6269b77..5ec3b2a 100644
> --- a/modules/access/dsm/access.c
> +++ b/modules/access/dsm/access.c
> @@ -33,12 +33,6 @@
>  #include <vlc_variables.h>
>  #include <vlc_dialog.h>
>  
> -#include <string.h>
> -#include <sys/socket.h>
> -#include <netinet/in.h>
> -#include <arpa/inet.h>
> -#include <netdb.h>
> -
>  /*****************************************************************************
>   * Module descriptor
>   *****************************************************************************/
> @@ -87,15 +81,9 @@ static ssize_t Read( access_t *, uint8_t *, size_t );
>  static int Seek( access_t *, uint64_t );
>  static int Control( access_t *, int, va_list );
>  
> -static void split_domain_login( char **psz_login, char **psz_domain );
> -static void get_credentials( access_t *p_access, access_sys_t *p_sys );
> -static bool get_address( access_t *p_access, access_sys_t *p_sys );
>  static void login_dialog( access_t *p_access, access_sys_t *p_sys );
> -static bool login( access_t *p_access, access_sys_t *p_sys );
> -static void backslash_path( vlc_url_t *p_url );
> -static bool get_path( access_t *p_access, access_sys_t *p_sys );
> -static bool bdsm_init( access_t *p_access, access_sys_t *p_sys );
> -static void bdsm_destroy( access_sys_t *p_sys );
> +static void login( void *p_ctx );
> +static int BrowserInit( access_t *p_access );
>  
>  /*****************************************************************************
>   * Dialog strings
> @@ -112,6 +100,7 @@ int Open( vlc_object_t *p_this )
>  {
>      access_t     *p_access = (access_t*)p_this;
>      access_sys_t *p_sys;
> +    bdsm_login_cb_t login_cb;
>  
>      /* Init p_access */
>      access_InitFields( p_access );
> @@ -119,46 +108,24 @@ int Open( vlc_object_t *p_this )
>      if( p_access->p_sys == NULL )
>          return VLC_ENOMEM;
>  
> -    if( !bdsm_init( p_access, p_sys ) )
> -        goto error;
> -
> -    if( !get_path( p_access, p_sys ) )
> -        return BrowserInit( p_access );
> -    msg_Dbg( p_access, "Path: Share name = %s, path = %s",
> p_sys->psz_share,
> -             p_sys->psz_path );
> -
> -
> -    /* Connect to the share */
> -    p_sys->i_tid = smb_tree_connect( p_sys->p_session, p_sys->psz_share
> );
> -    if( !p_sys->i_tid )
> -    {
> -        msg_Err( p_access, "Unable to connect to share %s",
> p_sys->psz_share );
> +    if( bdsm_Init( p_sys, VLC_OBJECT(p_access) ) != VLC_SUCCESS )
>          goto error;
> -    }
>  
> -    /* Let's finally ask a handle to the file we wanna read ! */
> -    p_sys->i_fd = smb_fopen( p_sys->p_session, p_sys->i_tid,
> p_sys->psz_path,
> -                             SMB_MOD_RO );
> -    if( !p_sys->i_fd )
> -    {
> -        msg_Err( p_access, "Unable to open file with path %s (in share
> %s)",
> -                 p_sys->psz_path, p_sys->psz_share );
> +    login_cb.pf_login = login;
> +    login_cb.p_ctx = p_access;
> +    if( bdsm_Connect( p_sys, &login_cb, p_access->psz_location ) !=
> VLC_SUCCESS )
>          goto error;
> -    }
>  
> -    smb_stat st = smb_stat_fd( p_sys->p_session, p_sys->i_fd );
> -    if( smb_stat_get( st, SMB_STAT_ISDIR ) )
> -    {
> -        smb_fclose( p_sys->p_session, p_sys->i_fd );
> +    if( p_sys->b_is_browsing )
>          return BrowserInit( p_access );
> -    }
>  
>      msg_Dbg( p_access, "Successfully opened smb://%s",
>      p_access->psz_location );
> +
>      ACCESS_SET_CALLBACKS( Read, NULL, Control, Seek );
>      return VLC_SUCCESS;
>  
>      error:
> -        bdsm_destroy( p_sys );
> +        bdsm_Destroy( p_sys );
>          free( p_sys );
>          return VLC_EGENERIC;
>  }
> @@ -171,8 +138,7 @@ void Close( vlc_object_t *p_this )
>      access_t     *p_access = (access_t*)p_this;
>      access_sys_t *p_sys = p_access->p_sys;
>  
> -    smb_fclose( p_sys->p_session, p_sys->i_fd );
> -    bdsm_destroy( p_sys );
> +    bdsm_Destroy( p_sys );
>      free( p_sys );
>  }
>  
> @@ -180,96 +146,6 @@ void Close( vlc_object_t *p_this )
>   * Local functions
>   *****************************************************************************/
>  
> -/* Split DOMAIN\User if it finds a '\' in psz_login. */
> -static void split_domain_login( char **psz_login, char **psz_domain )
> -{
> -    char *user = strchr( *psz_login, '\\' );
> -
> -    if( user != NULL )
> -    {
> -        *psz_domain = *psz_login;
> -        *user = '\0';
> -        *psz_login = strdup( user + 1 );
> -    }
> -}
> -
> -/* Get credentials from uri or variables. */
> -static void get_credentials( access_t *p_access, access_sys_t *p_sys )
> -{
> -    /* Fetch credentials, either from URI or from options if not
> provided */
> -    if( p_sys->url.psz_password == NULL )
> -        p_sys->creds.password = var_InheritString( p_access, "smb-pwd"
> );
> -    else
> -        p_sys->creds.password = strdup( p_sys->url.psz_password );
> -
> -    /* Here we support smb://DOMAIN\User:password@XXX, get user from
> options
> -       or default to "Guest" as last resort */
> -    if( p_sys->url.psz_username != NULL )
> -    {
> -        p_sys->creds.login = strdup( p_sys->url.psz_username );
> -        split_domain_login( &p_sys->creds.login, &p_sys->creds.domain );
> -    }
> -    else
> -    {
> -        p_sys->creds.login = var_InheritString( p_access, "smb-user" );
> -        if( p_sys->creds.login == NULL )
> -            p_sys->creds.login = strdup( "Guest" );
> -    }
> -
> -    if( p_sys->creds.domain == NULL )
> -        p_sys->creds.domain = var_InheritString( p_access, "smb-domain"
> );
> -
> -}
> -
> -/* Returns false if it wasn't able to get an ip address to connect to */
> -static bool get_address( access_t *p_access, access_sys_t *p_sys )
> -{
> -    if( !inet_aton( p_sys->url.psz_host, &p_sys->addr ) )
> -    {
> -        /* This is not an ip address, let's try netbios/dns resolve */
> -        struct addrinfo *p_info = NULL;
> -
> -        /* Is this a netbios name on this LAN ? */
> -        if( netbios_ns_resolve( p_sys->p_ns, p_sys->url.psz_host, 0x20,
> -                                &p_sys->addr.s_addr) )
> -        {
> -            strlcpy( p_sys->netbios_name, p_sys->url.psz_host, 16);
> -            return true;
> -        }
> -        /* or is it an existing dns name ? */
> -        else if( getaddrinfo( p_sys->url.psz_host, NULL, NULL, &p_info )
> == 0 )
> -        {
> -            if( p_info->ai_family == AF_INET )
> -            {
> -                struct sockaddr_in *in = (struct sockaddr_in
> *)p_info->ai_addr;
> -                p_sys->addr.s_addr = in->sin_addr.s_addr;
> -            }
> -            freeaddrinfo( p_info );
> -            if( p_info->ai_family != AF_INET )
> -                return false;
> -        }
> -        else
> -            return false;
> -    }
> -
> -    /* We have an IP address, let's find the NETBIOS name */
> -    const char *psz_nbt = netbios_ns_inverse( p_sys->p_ns,
> p_sys->addr.s_addr );
> -    if( psz_nbt != NULL )
> -        strlcpy( p_sys->netbios_name, psz_nbt, 16 );
> -    else
> -    {
> -        msg_Warn( p_access, "Unable to get netbios name of %s",
> -            p_sys->url.psz_host );
> -        p_sys->netbios_name[0] = '\0';
> -    }
> -
> -    /* If no domain was explicitly specified, let's use the machine name
> */
> -    if( p_sys->creds.domain == NULL && p_sys->netbios_name[0] )
> -        p_sys->creds.domain = strdup( p_sys->netbios_name );
> -
> -    return true;
> -}
> -
>  /* Displays a dialog for the user to enter his/her credentials */
>  static void login_dialog( access_t *p_access, access_sys_t *p_sys )
>  {
> @@ -290,7 +166,7 @@ static void login_dialog( access_t *p_access,
> access_sys_t *p_sys )
>          if( p_sys->creds.login != NULL )
>              free( p_sys->creds.login );
>          p_sys->creds.login = psz_login;
> -        split_domain_login( &p_sys->creds.login, &p_sys->creds.domain );
> +        bdsm_SplitDomainLogin( &p_sys->creds.login, &p_sys->creds.domain
> );
>      }
>  
>      if( psz_pass != NULL )
> @@ -301,164 +177,78 @@ static void login_dialog( access_t *p_access,
> access_sys_t *p_sys )
>      }
>  }
>  
> -/* Performs login with existing credentials and ask the user for new
> ones on
> -   failure */
> -static bool login( access_t *p_access, access_sys_t *p_sys )
> +static void login( void *p_ctx )
>  {
> -    if( p_sys->creds.login == NULL )
> -        p_sys->creds.login = strdup( "Guest" );
> -    if( p_sys->creds.password == NULL )
> -        p_sys->creds.password = strdup( "Guest" );
> -    if( p_sys->creds.domain == NULL )
> -        p_sys->creds.domain = strdup( "WORKGROUP" );
> -
> -    /* Try to authenticate on the remote machine */
> -    smb_session_set_creds( p_sys->p_session, p_sys->creds.domain,
> -                           p_sys->creds.login, p_sys->creds.password );
> -    if( !smb_session_login( p_sys->p_session ) )
> -    {
> -        for( int i = 0; i < BDSM_LOGIN_DIALOG_RETRY; i++ )
> -        {
> -            login_dialog( p_access, p_sys );
> -            smb_session_set_creds( p_sys->p_session,
> p_sys->creds.domain,
> -                                   p_sys->creds.login,
> p_sys->creds.password );
> -            if( smb_session_login( p_sys->p_session ) )
> -                return true;
> -        }
> -
> -        /* FIXME, Try to force netbios name as domain then WORKGROUP
> here */
> -        msg_Err( p_access, "Unable to login with username = %s, password
> = %s, domain = %s",
> -                   p_sys->creds.login, p_sys->creds.password,
> -                   p_sys->creds.domain );
> -        return false;
> -    }
> -    else if( smb_session_is_guest( p_sys->p_session ) == 1 )
> -        msg_Warn( p_access, "Login failure but you were logged in as a
> Guest");
> +    access_t *p_access = p_ctx;
> +    access_sys_t *p_sys = p_access->p_sys;
>  
> -    return true;
> +    for( int i = 0; i < BDSM_LOGIN_DIALOG_RETRY; i++ )
> +        login_dialog( p_access, p_sys );
>  }
>  
> -static void backslash_path( vlc_url_t *p_url )
> +static int AddToNode( void *p_ctx, input_item_t *p_item )
>  {
> -    char *iter = p_url->psz_path;
> -
> -    /* Let's switch the path delimiters from / to \ */
> -    while( *iter != '\0' )
> -    {
> -        if( *iter == '/' )
> -            *iter = '\\';
> -        iter++;
> -    }
> +    input_item_node_t *p_node = p_ctx;
> +    input_item_CopyOptions( p_node->p_item, p_item );
> +    return input_item_node_AppendItem( p_node, p_item ) != NULL ?
> VLC_SUCCESS
> +                                                                : 
> VLC_EGENERIC;
>  }
>  
> -/* Get the share and filepath from uri (also replace all / by \ in
> url.psz_path) */
> -static bool get_path( access_t *p_access, access_sys_t *p_sys )
> +static int BrowseShare( access_t *p_access, input_item_node_t *p_node )
>  {
> -    VLC_UNUSED( p_access );
> -
> -    char *iter;
> -
> -    if( p_sys->url.psz_path == NULL )
> -        return false;
> -
> -    backslash_path( &p_sys->url );
> -
> -    /* Is path longer than just "/" ? */
> -    if( strlen( p_sys->url.psz_path ) > 1 )
> -    {
> -        iter = p_sys->url.psz_path;
> -        while( *iter == '\\' ) iter++; /* Handle smb://Host/////Share/
> */
> +    bdsm_item_cb_t cb;
> +    cb.pf_add_item = AddToNode;
> +    cb.p_ctx = p_node;
> +    return bdsm_BrowseShare( p_access->p_sys, &cb,
> p_node->p_item->psz_uri );
> +}
>  
> -        p_sys->psz_share = strdup( iter );
> -        if ( p_sys->psz_share == NULL )
> -            return false;
> -    }
> -    else
> -    {
> -        msg_Dbg( p_access, "no share, nor file path provided, will
> switch to browser");
> -        return false;
> -    }
> +static int BrowseDirectory( access_t *p_access, input_item_node_t
> *p_node )
> +{
> +    bdsm_item_cb_t cb;
> +    cb.pf_add_item = AddToNode;
> +    cb.p_ctx = p_node;
> +    return bdsm_BrowseDirectory( p_access->p_sys, &cb,
> p_node->p_item->psz_uri );
> +}
>  
> +static int BrowserControl( access_t *p_access, int i_query, va_list args
> )
> +{
> +    VLC_UNUSED( p_access );
>  
> -    iter = strchr( p_sys->psz_share, '\\' );
> -    if( iter == NULL || strlen(iter + 1) == 0 )
> +    switch( i_query )
>      {
> -        if( iter != NULL ) /* Remove the trailing \ */
> -            *iter = '\0';
> -        p_sys->psz_path = strdup( "" );
> -
> -        msg_Dbg( p_access, "no file path provided, will switch to
> browser ");
> -        return true;
> -    }
> -
> -    p_sys->psz_path = strdup( iter + 1); /* Skip the first \ */
> -    *iter = '\0';
> -    if( p_sys->psz_path == NULL )
> -        return false;
> -
> -    return true;
> +        case ACCESS_CAN_SEEK:
> +        case ACCESS_CAN_FASTSEEK:
> +            *va_arg( args, bool* ) = false;
> +            break;
> +
> +        case ACCESS_CAN_PAUSE:
> +        case ACCESS_CAN_CONTROL_PACE:
> +            *va_arg( args, bool* ) = true;
> +            break;
> +
> +        case ACCESS_GET_PTS_DELAY:
> +            *va_arg( args, int64_t * ) = DEFAULT_PTS_DELAY * 1000;
> +            break;
> +
> +        default:
> +            return VLC_EGENERIC;
> +     }
> +     return VLC_SUCCESS;
>  }
>  
> -/* get ip address/path/creds, then connects and try to authenticate */
> -static bool bdsm_init( access_t *p_access, access_sys_t *p_sys )
> +static int BrowserInit( access_t *p_access )
>  {
> -    p_sys->url.psz_buffer = NULL;
> -    p_sys->creds.login    = NULL;
> -    p_sys->creds.password = NULL;
> -    p_sys->creds.domain   = NULL;
> -    p_sys->psz_share      = NULL;
> -    p_sys->psz_path       = NULL;
> -    p_sys->i_fd           = 0;
> -    p_sys->i_tid          = 0;
> -
> -    p_sys->p_session = smb_session_new();
> -    if( p_sys->p_session == NULL )
> -        return false;
> -
> -    p_sys->p_ns = netbios_ns_new();
> -    if( p_sys->p_ns == NULL )
> -        return false;
> -
> -    vlc_UrlParse( &p_sys->url, p_access->psz_location, 0 );
> -    get_credentials( p_access, p_sys );
> -    if( !get_address( p_access, p_sys ) )
> -        return false;
> -
> -    msg_Dbg( p_access, "Creds: username = %s, password = %s, domain =
> %s",
> -             p_sys->creds.login, p_sys->creds.password,
> -             p_sys->creds.domain );
> -    msg_Dbg( p_access, "Session: Host name = %s, ip = %s",
> p_sys->netbios_name,
> -             inet_ntoa( p_sys->addr ) );
> -
> -    /* Now that we have the required data, let's establish a session */
> -    if( !smb_session_connect( p_sys->p_session, p_sys->netbios_name,
> -                              p_sys->addr.s_addr, SMB_TRANSPORT_TCP ))
> -    {
> -        msg_Err( p_access, "Unable to connect/negotiate SMB session");
> -        return false;
> -    }
> -
> -    if( !login( p_access, p_sys ) )
> -        return false;
> -
> +    access_sys_t *p_sys = p_access->p_sys;
>  
> +    if( p_sys->psz_share == NULL )
> +        p_access->pf_readdir = BrowseShare;
> +    else
> +        p_access->pf_readdir = BrowseDirectory;
> +    p_access->pf_control = BrowserControl;
>  
> -    return true;
> +    return VLC_SUCCESS;
>  }
>  
> -/* Cleanup libdsm stuff */
> -static void bdsm_destroy( access_sys_t *p_sys )
> -{
> -    smb_session_destroy( p_sys->p_session );
> -    netbios_ns_destroy( p_sys->p_ns );
> -
> -    free( p_sys->creds.login );
> -    free( p_sys->creds.password );
> -    free( p_sys->creds.domain );
> -    free( p_sys->url.psz_buffer );
> -    free( p_sys->psz_share );
> -    free( p_sys->psz_path );
> -}
>  
>  /*****************************************************************************
>   * Seek: try to go at the right place
> diff --git a/modules/access/dsm/browser.c b/modules/access/dsm/browser.c
> deleted file mode 100644
> index 40dd314..0000000
> --- a/modules/access/dsm/browser.c
> +++ /dev/null
> @@ -1,191 +0,0 @@
> -/*****************************************************************************
> - * bdsm/access.c: liBDSM based SMB/CIFS access module
> -
> *****************************************************************************
> - * Copyright (C) 2001-2014 VLC authors and VideoLAN
> - *
> - * Authors: Julien 'Lta' BALLET <contact # lta 'dot' io>
> - *
> - * This program is free software; you can redistribute it and/or modify
> it
> - * under the terms of the GNU Lesser General Public License as published
> by
> - * the Free Software Foundation; either version 2.1 of the License, or
> - * (at your option) any later version.
> - *
> - * This program is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> - * GNU Lesser General Public License for more details.
> - *
> - * You should have received a copy of the GNU Lesser General Public
> License
> - * along with this program; if not, write to the Free Software
> Foundation,
> - * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
> -
> *****************************************************************************/
> -
> -/*****************************************************************************
> - * Preamble
> -
> *****************************************************************************/
> -#ifdef HAVE_CONFIG_H
> -# include "config.h"
> -#endif
> -
> -#include "common.h"
> -
> -static int Control (access_t *p_access, int i_query, va_list args);
> -static int BrowseShare( access_t *p_access, input_item_node_t *p_node );
> -static int BrowseDirectory( access_t *p_access, input_item_node_t
> *p_node );
> -static bool AddToNode( access_t *p_access, input_item_node_t *p_node,
> -                       const char *psz_name );
> -
> -int BrowserInit( access_t *p_access )
> -{
> -    access_sys_t *p_sys = p_access->p_sys;
> -
> -    if( p_sys->psz_share == NULL )
> -        p_access->pf_readdir = BrowseShare;
> -    else
> -        p_access->pf_readdir = BrowseDirectory;
> -    p_access->pf_control = Control;
> -
> -    return VLC_SUCCESS;
> -}
> -
> -static int BrowseShare( access_t *p_access, input_item_node_t *p_node )
> -{
> -    smb_share_list  shares;
> -    const char     *psz_name;
> -    size_t          share_count;
> -
> -    share_count = smb_share_get_list( p_access->p_sys->p_session,
> &shares );
> -    if( !share_count )
> -        return VLC_ENOITEM;
> -
> -    for( size_t i = 0; i < share_count; i++ )
> -    {
> -        psz_name = smb_share_list_at( shares, i );
> -
> -        if( psz_name[strlen( psz_name ) - 1] == '$')
> -            continue;
> -
> -        AddToNode( p_access, p_node, psz_name );
> -    }
> -
> -    smb_share_list_destroy( shares );
> -    return VLC_SUCCESS;
> -}
> -
> -static int BrowseDirectory( access_t *p_access, input_item_node_t
> *p_node )
> -{
> -    access_sys_t   *p_sys = p_access->p_sys;
> -    smb_stat_list   files;
> -    smb_stat        st;
> -    char           *psz_query;
> -    const char     *psz_name;
> -    size_t          files_count;
> -    int             i_ret;
> -
> -    if( p_sys->psz_path != NULL )
> -    {
> -        i_ret = asprintf( &psz_query, "%s\\*", p_sys->psz_path );
> -        if( i_ret == -1 )
> -            return VLC_ENOMEM;
> -        files = smb_find( p_sys->p_session, p_sys->i_tid, psz_query );
> -        free( psz_query );
> -    }
> -    else
> -        files = smb_find( p_sys->p_session, p_sys->i_tid, "\\*" );
> -
> -    if( files == NULL )
> -        return VLC_ENOITEM;
> -
> -    files_count = smb_stat_list_count( files );
> -    for( size_t i = 0; i < files_count; i++ )
> -    {
> -        st = smb_stat_list_at( files, i );
> -
> -        if( st == NULL )
> -            goto error;
> -
> -        psz_name = smb_stat_name( st );
> -
> -        /* Avoid infinite loop */
> -        if( !strcmp( psz_name, ".") || !strcmp( psz_name, "..") )
> -            continue;
> -
> -        AddToNode( p_access, p_node, psz_name );
> -    }
> -
> -    smb_stat_list_destroy( files );
> -    return VLC_SUCCESS;
> -
> -    error:
> -        smb_stat_list_destroy( files );
> -        return VLC_ENOITEM;
> -}
> -
> -/*****************************************************************************
> - * Control:
> -
> *****************************************************************************/
> -static int Control( access_t *p_access, int i_query, va_list args )
> -{
> -    VLC_UNUSED( p_access );
> -
> -    switch( i_query )
> -    {
> -        case ACCESS_CAN_SEEK:
> -        case ACCESS_CAN_FASTSEEK:
> -            *va_arg( args, bool* ) = false;
> -            break;
> -
> -        case ACCESS_CAN_PAUSE:
> -        case ACCESS_CAN_CONTROL_PACE:
> -            *va_arg( args, bool* ) = true;
> -            break;
> -
> -        case ACCESS_GET_PTS_DELAY:
> -            *va_arg( args, int64_t * ) = DEFAULT_PTS_DELAY * 1000;
> -            break;
> -
> -        default:
> -            return VLC_EGENERIC;
> -     }
> -     return VLC_SUCCESS;
> - }
> -
> -static bool AddToNode( access_t *p_access, input_item_node_t *p_node,
> -                       const char *psz_name )
> -{
> -    access_sys_t *p_sys = p_access->p_sys;
> -    input_item_t *p_item;
> -    char         *psz_uri, *psz_option;
> -    int           i_ret;
> -
> -    i_ret = asprintf( &psz_uri, "%s/%s", p_node->p_item->psz_uri,
> psz_name );
> -    /* XXX Handle ENOMEM by enabling retry */
> -    if( i_ret == -1 )
> -        return false;
> -
> -    p_item = input_item_New( psz_uri, psz_name );
> -    free( psz_uri );
> -    if( p_item == NULL )
> -        return false;
> -
> -    input_item_CopyOptions( p_node->p_item, p_item );
> -    input_item_node_AppendItem( p_node, p_item );
> -
> -    /* Here we save on the node the credentials that allowed us to
> login.
> -     * That way the user isn't prompted more than once for credentials
> */
> -    i_ret = asprintf( &psz_option, "smb-user=%s", p_sys->creds.login );
> -    if( i_ret != -1 )
> -        input_item_AddOption( p_item, psz_option,
> VLC_INPUT_OPTION_TRUSTED );
> -    free( psz_option );
> -    i_ret = asprintf( &psz_option, "smb-pwd=%s", p_sys->creds.password
> );
> -    if( i_ret != -1 )
> -        input_item_AddOption( p_item, psz_option,
> VLC_INPUT_OPTION_TRUSTED );
> -    free( psz_option );
> -    asprintf( &psz_option, "smb-domain=%s", p_sys->creds.domain );
> -    if( i_ret != -1 )
> -        input_item_AddOption( p_item, psz_option,
> VLC_INPUT_OPTION_TRUSTED );
> -    free( psz_option );
> -
> -    input_item_Release( p_item );
> -    return true;
> -}
> diff --git a/modules/access/dsm/common.c b/modules/access/dsm/common.c
> new file mode 100644
> index 0000000..2b566d4
> --- /dev/null
> +++ b/modules/access/dsm/common.c
> @@ -0,0 +1,483 @@
> +/*****************************************************************************
> + * bdsm/common.c: liBDSM based SMB/CIFS access module
> +
> *****************************************************************************
> + * Copyright (C) 2001-2014 VLC authors and VideoLAN
> + *
> + * Authors: Julien 'Lta' BALLET <contact # lta 'dot' io>
> + *
> + * This program is free software; you can redistribute it and/or modify
> it
> + * under the terms of the GNU Lesser General Public License as published
> by
> + * the Free Software Foundation; either version 2.1 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> License
> + * along with this program; if not, write to the Free Software
> Foundation,
> + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
> +
> *****************************************************************************/
> +
> +/*****************************************************************************
> + * Preamble
> +
> *****************************************************************************/
> +#ifdef HAVE_CONFIG_H
> +# include "config.h"
> +#endif
> +
> +#include "common.h"
> +
> +#include <netinet/in.h>
> +#include <arpa/inet.h>
> +#include <netdb.h>
> +
> +static void cleanup( bdsm_sys_t *p_sys );
> +static bool get_path( bdsm_sys_t *p_sys );
> +static int get_address(  bdsm_sys_t *p_sys );
> +static void get_credentials( bdsm_sys_t *p_sys );
> +static int login( bdsm_sys_t *p_sys, bdsm_login_cb_t *p_login_cb );
> +static int add_item( bdsm_sys_t *p_sys, bdsm_item_cb_t *p_cb,
> +                    const char *psz_parent_uri, const char *psz_name );
> +
> +/* get ip address/path/creds, then connects and try to authenticate */
> +int bdsm_Init( bdsm_sys_t *p_sys, vlc_object_t *p_obj )
> +{
> +    memset( p_sys, 0, sizeof(bdsm_sys_t) );
> +
> +    p_sys->p_obj = p_obj;
> +
> +    p_sys->p_ns = netbios_ns_new();
> +    if( p_sys->p_ns == NULL )
> +        return VLC_EGENERIC;
> +
> +    return VLC_SUCCESS;
> +}
> +
> +int bdsm_Connect( bdsm_sys_t *p_sys, bdsm_login_cb_t *p_login_cb,
> +                  const char *psz_uri )
> +{
> +    smb_stat st;
> +
> +    cleanup( p_sys );
> +
> +    p_sys->p_session = smb_session_new();
> +    if( p_sys->p_session == NULL )
> +        goto error;
> +
> +    vlc_UrlParse( &p_sys->url, psz_uri, 0 );
> +    get_credentials( p_sys );
> +    if( get_address( p_sys ) != VLC_SUCCESS )
> +        goto error;
> +
> +    msg_Dbg( p_sys->p_obj, "Creds: username = %s, password = %s, domain
> = %s",
> +             p_sys->creds.login, p_sys->creds.password,
> +             p_sys->creds.domain );
> +    msg_Dbg( p_sys->p_obj, "Session: Host name = %s, ip = %s",
> p_sys->netbios_name,
> +             inet_ntoa( p_sys->addr ) );
> +
> +    /* Now that we have the required data, let's establish a session */
> +    if( !smb_session_connect( p_sys->p_session, p_sys->netbios_name,
> +                              p_sys->addr.s_addr, SMB_TRANSPORT_TCP ) )
> +    {
> +        msg_Err( p_sys->p_obj, "Unable to connect/negotiate SMB
> session");
> +        goto error;
> +    }
> +
> +    if( login( p_sys, p_login_cb ) != VLC_SUCCESS )
> +        goto error;
> +
> +    if( !get_path( p_sys ) )
> +    {
> +        p_sys->b_is_browsing = true;
> +        return VLC_SUCCESS;
> +    }
> +
> +    msg_Dbg( p_sys->p_obj, "Path: Share name = %s, path = %s",
> p_sys->psz_share,
> +             p_sys->psz_path );
> +
> +    /* Connect to the share */
> +    p_sys->i_tid = smb_tree_connect( p_sys->p_session, p_sys->psz_share
> );
> +    if( !p_sys->i_tid )
> +    {
> +        msg_Err( p_sys->p_obj, "Unable to connect to share %s",
> p_sys->psz_share );
> +        goto error;
> +    }
> +
> +    /* Let's finally ask a handle to the file we wanna read ! */
> +    p_sys->i_fd = smb_fopen( p_sys->p_session, p_sys->i_tid,
> p_sys->psz_path,
> +                             SMB_MOD_RO );
> +    if( !p_sys->i_fd )
> +    {
> +        msg_Err( p_sys->p_obj, "Unable to open file with path %s (in
> share %s)",
> +                 p_sys->psz_path, p_sys->psz_share );
> +        goto error;
> +    }
> +
> +    st = smb_stat_fd( p_sys->p_session, p_sys->i_fd );
> +    if( smb_stat_get( st, SMB_STAT_ISDIR ) )
> +    {
> +        smb_fclose( p_sys->p_session, p_sys->i_fd );
> +        p_sys->b_is_browsing = true;
> +    }
> +    return VLC_SUCCESS;
> +    error:
> +        cleanup( p_sys );
> +        return VLC_EGENERIC;
> +}
> +
> +/* cleanup libdsm stuff */
> +void bdsm_Destroy( bdsm_sys_t *p_sys )
> +{
> +    cleanup( p_sys );
> +    if( p_sys->p_ns )
> +        netbios_ns_destroy( p_sys->p_ns );
> +}
> +
> +/* Split DOMAIN\User if it finds a '\' in psz_login. */
> +void bdsm_SplitDomainLogin( char **psz_login, char **psz_domain )
> +{
> +    char *user = strchr( *psz_login, '\\' );
> +
> +    if( user != NULL )
> +    {
> +        *psz_domain = *psz_login;
> +        *user = '\0';
> +        *psz_login = strdup( user + 1 );
> +    }
> +}
> +
> +int bdsm_BrowseShare( bdsm_sys_t *p_sys, bdsm_item_cb_t *p_cb,
> +                      const char *psz_uri )
> +{
> +    smb_share_list  shares;
> +    const char     *psz_name;
> +    size_t          share_count;
> +    int             i_ret;
> +
> +    share_count = smb_share_get_list( p_sys->p_session, &shares );
> +    if( !share_count )
> +        return VLC_ENOITEM;
> +
> +    for( size_t i = 0; i < share_count; i++ )
> +    {
> +        psz_name = smb_share_list_at( shares, i );
> +
> +        if( psz_name[strlen( psz_name ) - 1] == '$')
> +            continue;
> +
> +        i_ret = add_item( p_sys, p_cb, psz_uri, psz_name );
> +        if( i_ret != VLC_SUCCESS )
> +            goto error;
> +    }
> +
> +    smb_share_list_destroy( shares );
> +    return VLC_SUCCESS;
> +    error:
> +        smb_share_list_destroy( shares );
> +        return i_ret;
> +}
> +
> +int bdsm_BrowseDirectory( bdsm_sys_t *p_sys, bdsm_item_cb_t *p_cb,
> +                          const char *psz_uri )
> +{
> +    smb_stat_list   files;
> +    smb_stat        st;
> +    char           *psz_query;
> +    const char     *psz_name;
> +    size_t          files_count;
> +    int             i_ret;
> +
> +    if( p_sys->psz_path != NULL )
> +    {
> +        i_ret = asprintf( &psz_query, "%s\\*", p_sys->psz_path );
> +        if( i_ret == -1 )
> +            return VLC_ENOMEM;
> +        files = smb_find( p_sys->p_session, p_sys->i_tid, psz_query );
> +        free( psz_query );
> +    }
> +    else
> +        files = smb_find( p_sys->p_session, p_sys->i_tid, "\\*" );
> +
> +    if( files == NULL )
> +        return VLC_ENOITEM;
> +
> +    files_count = smb_stat_list_count( files );
> +    for( size_t i = 0; i < files_count; i++ )
> +    {
> +        st = smb_stat_list_at( files, i );
> +
> +        if( st == NULL ) {
> +            i_ret = VLC_ENOITEM;
> +            goto error;
> +        }
> +
> +        psz_name = smb_stat_name( st );
> +
> +        /* Avoid infinite loop */
> +        if( !strcmp( psz_name, ".") || !strcmp( psz_name, "..") )
> +            continue;
> +
> +        i_ret = add_item( p_sys, p_cb, psz_uri, psz_name );
> +        if( i_ret != VLC_SUCCESS )
> +            goto error;
> +    }
> +
> +    smb_stat_list_destroy( files );
> +    return VLC_SUCCESS;
> +
> +    error:
> +        smb_stat_list_destroy( files );
> +        return i_ret;
> +}
> +
> +/*****************************************************************************
> + * Local functions
> +
> *****************************************************************************/
> +
> +static void cleanup( bdsm_sys_t *p_sys )
> +{
> +    p_sys->b_is_browsing = false;
> +
> +    if( p_sys->i_fd )
> +        smb_fclose( p_sys->p_session, p_sys->i_fd );
> +    p_sys->i_fd = 0;
> +
> +    if( p_sys->p_session )
> +        smb_session_destroy( p_sys->p_session );
> +    p_sys->p_session = NULL;
> +    p_sys->i_tid = 0;
> +
> +    free( p_sys->creds.login );
> +    p_sys->creds.login = NULL;
> +
> +    free( p_sys->creds.password );
> +    p_sys->creds.password = NULL;
> +
> +    free( p_sys->creds.domain );
> +    p_sys->creds.domain = NULL;
> +
> +    free( p_sys->url.psz_buffer );
> +    p_sys->url.psz_buffer = NULL;
> +
> +    free( p_sys->psz_share );
> +    p_sys->psz_share = NULL;
> +
> +    free( p_sys->psz_path );
> +    p_sys->psz_path = NULL;
> +}
> +
> +static void backslash_path( vlc_url_t *p_url )
> +{
> +    char *iter = p_url->psz_path;
> +
> +    /* Let's switch the path delimiters from / to \ */
> +    while( *iter != '\0' )
> +    {
> +        if( *iter == '/' )
> +            *iter = '\\';
> +        iter++;
> +    }
> +}
> +
> +/* Get the share and filepath from uri (also replace all / by \ in
> url.psz_path) */
> +static bool get_path( bdsm_sys_t *p_sys )
> +{
> +    char *iter;
> +
> +    if( p_sys->url.psz_path == NULL )
> +        return false;
> +
> +    backslash_path( &p_sys->url );
> +
> +    /* Is path longer than just "/" ? */
> +    if( strlen( p_sys->url.psz_path ) > 1 )
> +    {
> +        iter = p_sys->url.psz_path;
> +        while( *iter == '\\' ) iter++; /* Handle smb://Host/////Share/
> */
> +
> +        p_sys->psz_share = strdup( iter );
> +        if ( p_sys->psz_share == NULL )
> +            return false;
> +    }
> +    else
> +    {
> +        msg_Dbg( p_sys->p_obj, "no share, nor file path provided, will
> switch to browser");
> +        return false;
> +    }
> +
> +
> +    iter = strchr( p_sys->psz_share, '\\' );
> +    if( iter == NULL || strlen(iter + 1) == 0 )
> +    {
> +        if( iter != NULL ) /* Remove the trailing \ */
> +            *iter = '\0';
> +        p_sys->psz_path = strdup( "" );
> +
> +        msg_Dbg( p_sys->p_obj, "no file path provided, will switch to
> browser ");
> +        return true;
> +    }
> +
> +    p_sys->psz_path = strdup( iter + 1); /* Skip the first \ */
> +    *iter = '\0';
> +    if( p_sys->psz_path == NULL )
> +        return false;
> +
> +    return true;
> +}
> +
> +/* Returns false if it wasn't able to get an ip address to connect to */
> +static int get_address( bdsm_sys_t *p_sys )
> +{
> +    if( !inet_aton( p_sys->url.psz_host, &p_sys->addr ) )
> +    {
> +        /* This is not an ip address, let's try netbios/dns resolve */
> +        struct addrinfo *p_info = NULL;
> +
> +        /* Is this a netbios name on this LAN ? */
> +        if( netbios_ns_resolve( p_sys->p_ns, p_sys->url.psz_host, 0x20,
> +                                &p_sys->addr.s_addr) )
> +        {
> +            strlcpy( p_sys->netbios_name, p_sys->url.psz_host, 16);
> +            return VLC_SUCCESS;
> +        }
> +        /* or is it an existing dns name ? */
> +        else if( getaddrinfo( p_sys->url.psz_host, NULL, NULL, &p_info )
> == 0 )
> +        {
> +            if( p_info->ai_family == AF_INET )
> +            {
> +                struct sockaddr_in *in = (struct sockaddr_in
> *)p_info->ai_addr;
> +                p_sys->addr.s_addr = in->sin_addr.s_addr;
> +            }
> +            freeaddrinfo( p_info );
> +            if( p_info->ai_family != AF_INET )
> +                return VLC_EGENERIC;
> +        }
> +        else
> +            return VLC_EGENERIC;
> +    }
> +
> +    /* We have an IP address, let's find the NETBIOS name */
> +    const char *psz_nbt = netbios_ns_inverse( p_sys->p_ns,
> p_sys->addr.s_addr );
> +    if( psz_nbt != NULL )
> +        strlcpy( p_sys->netbios_name, psz_nbt, 16 );
> +    else
> +    {
> +        msg_Warn( p_sys->p_obj, "Unable to get netbios name of %s",
> +            p_sys->url.psz_host );
> +        p_sys->netbios_name[0] = '\0';
> +    }
> +
> +    /* If no domain was explicitly specified, let's use the machine name
> */
> +    if( p_sys->creds.domain == NULL && p_sys->netbios_name[0] )
> +        p_sys->creds.domain = strdup( p_sys->netbios_name );
> +
> +    return VLC_SUCCESS;
> +}
> +
> +/* Get credentials from uri or variables. */
> +static void get_credentials( bdsm_sys_t *p_sys )
> +{
> +    /* Fetch credentials, either from URI or from options if not
> provided */
> +    if( p_sys->url.psz_password == NULL )
> +        p_sys->creds.password = var_InheritString( p_sys->p_obj,
> "smb-pwd" );
> +    else
> +        p_sys->creds.password = strdup( p_sys->url.psz_password );
> +
> +    /* Here we support smb://DOMAIN\User:password@XXX, get user from
> options
> +       or default to "Guest" as last resort */
> +    if( p_sys->url.psz_username != NULL )
> +    {
> +        p_sys->creds.login = strdup( p_sys->url.psz_username );
> +        bdsm_SplitDomainLogin( &p_sys->creds.login, &p_sys->creds.domain
> );
> +    }
> +    else
> +    {
> +        p_sys->creds.login = var_InheritString( p_sys->p_obj, "smb-user"
> );
> +        if( p_sys->creds.login == NULL )
> +            p_sys->creds.login = strdup( "Guest" );
> +    }
> +
> +    if( p_sys->creds.domain == NULL )
> +        p_sys->creds.domain = var_InheritString( p_sys->p_obj,
> "smb-domain" );
> +}
> +
> +/* Performs login with existing credentials and ask the user for new
> ones on
> +   failure */
> +static int login( bdsm_sys_t *p_sys, bdsm_login_cb_t *p_login_cb )
> +{
> +    if( p_sys->creds.login == NULL )
> +        p_sys->creds.login = strdup( "Guest" );
> +    if( p_sys->creds.password == NULL )
> +        p_sys->creds.password = strdup( "Guest" );
> +    if( p_sys->creds.domain == NULL )
> +        p_sys->creds.domain = strdup( "WORKGROUP" );
> +
> +    /* Try to authenticate on the remote machine */
> +    smb_session_set_creds( p_sys->p_session, p_sys->creds.domain,
> +                           p_sys->creds.login, p_sys->creds.password );
> +    if( !smb_session_login( p_sys->p_session ) )
> +    {
> +        if( p_login_cb != NULL )
> +        {
> +            p_login_cb->pf_login( p_login_cb->p_ctx );
> +            smb_session_set_creds( p_sys->p_session,
> p_sys->creds.domain,
> +                                   p_sys->creds.login,
> p_sys->creds.password );
> +            if( smb_session_login( p_sys->p_session ) )
> +                return VLC_SUCCESS;
> +        }
> +
> +        /* FIXME, Try to force netbios name as domain then WORKGROUP
> here */
> +        msg_Err( p_sys->p_obj, "Unable to login with username = %s,
> password = %s, domain = %s",
> +                   p_sys->creds.login, p_sys->creds.password,
> +                   p_sys->creds.domain );
> +        return VLC_EGENERIC;
> +    }
> +    else if( smb_session_is_guest( p_sys->p_session ) == 1 )
> +        msg_Warn( p_sys->p_obj, "Login failure but you were logged in as
> a Guest");
> +
> +    return VLC_SUCCESS;
> +}
> +
> +static int add_item( bdsm_sys_t *p_sys, bdsm_item_cb_t *p_cb,
> +                    const char *psz_parent_uri, const char *psz_name )
> +{
> +    input_item_t *p_item;
> +    char         *psz_uri, *psz_option;
> +    int           i_ret;
> +
> +    i_ret = asprintf( &psz_uri, "%s/%s", psz_parent_uri, psz_name );
> +    if( i_ret == -1 )
> +        return VLC_ENOMEM;
> +
> +    p_item = input_item_New( psz_uri, psz_name );
> +    free( psz_uri );
> +    if( p_item == NULL )
> +        return VLC_ENOMEM;
> +
> +    /* Here we save on the node the credentials that allowed us to
> login.
> +     * That way the user isn't prompted more than once for credentials
> */
> +    i_ret = asprintf( &psz_option, "smb-user=%s", p_sys->creds.login );
> +    if( i_ret == -1 )
> +        return VLC_ENOMEM;
> +    input_item_AddOption( p_item, psz_option, VLC_INPUT_OPTION_TRUSTED
> );
> +    free( psz_option );
> +
> +    i_ret = asprintf( &psz_option, "smb-pwd=%s", p_sys->creds.password
> );
> +    if( i_ret == -1 )
> +        return VLC_ENOMEM;
> +    input_item_AddOption( p_item, psz_option, VLC_INPUT_OPTION_TRUSTED
> );
> +    free( psz_option );
> +
> +    i_ret = asprintf( &psz_option, "smb-domain=%s", p_sys->creds.domain
> );
> +    if( i_ret == -1 )
> +        return VLC_ENOMEM;
> +    input_item_AddOption( p_item, psz_option, VLC_INPUT_OPTION_TRUSTED
> );
> +    free( psz_option );
> +
> +    i_ret = p_cb->pf_add_item( p_cb->p_ctx, p_item );
> +
> +    input_item_Release( p_item );
> +    return i_ret;
> +}
> diff --git a/modules/access/dsm/common.h b/modules/access/dsm/common.h
> index cae5ab7..9e14b6d 100644
> --- a/modules/access/dsm/common.h
> +++ b/modules/access/dsm/common.h
> @@ -36,10 +36,9 @@ int SdOpen( vlc_object_t * );
>  void SdClose( vlc_object_t * );
>  int vlc_sd_probe_Open( vlc_object_t * );
>  
> -int BrowserInit( access_t *p_access );
> -
>  struct access_sys_t
>  {
> +    vlc_object_t       *p_obj;
>      netbios_ns         *p_ns;               /**< Netbios name service */
>      smb_session        *p_session;          /**< bdsm SMB Session object
>      */
>      smb_creds           creds;              /**< Credentials used to
>      connect */
> @@ -53,5 +52,27 @@ struct access_sys_t
>  
>      smb_fd              i_fd;               /**< SMB fd for the file
>      we're reading */
>      smb_tid             i_tid;              /**< SMB Tree ID we're
>      connected to */
> +    bool                b_is_browsing;
> +};
> +typedef struct access_sys_t bdsm_sys_t;
> +
> +typedef struct bdsm_item_cb_t bdsm_item_cb_t;
> +struct bdsm_item_cb_t {
> +    int ( *pf_add_item ) ( void *p_ctx, input_item_t * );
> +    void *p_ctx;
>  };
>  
> +typedef struct bdsm_login_cb_t bdsm_login_cb_t;
> +struct bdsm_login_cb_t {
> +    void ( *pf_login ) ( void *p_ctx );
> +    void *p_ctx;
> +};

Finally, it's not needed. It's better to add dialog in libvlc. see Trac
#8704

> +
> +/* get ip address/path/creds, then connects and try to authenticate */
> +int bdsm_Init( bdsm_sys_t *, vlc_object_t * );
> +int bdsm_Connect( bdsm_sys_t *, bdsm_login_cb_t *, const char * );
> +void bdsm_Destroy( bdsm_sys_t * );
> +void bdsm_SplitDomainLogin( char **psz_login, char **psz_domain );
> +
> +int bdsm_BrowseShare( bdsm_sys_t *, bdsm_item_cb_t *, const char * );
> +int bdsm_BrowseDirectory( bdsm_sys_t *, bdsm_item_cb_t *, const char *
> );
> -- 
> 2.1.3
> 




More information about the vlc-devel mailing list