# Plugin for TWiki Collaboration Platform, http://TWiki.org/ # # Copyright (C) 2000-2003 Andrea Sterbini, a.sterbini@flashnet.it # Copyright (C) 2001-2003 Peter Thoeny, peter@thoeny.com # Copyright (C) 2003 Jonathan Cline, jcline.at.ieee.org # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details, published at # http://www.gnu.org/copyleft/gpl.html # # ========================= # package TWiki::Plugins::SlashFilenamePlugin; # This plugin implements rendering of slash paths detected in wiki text into # RFC2396 URI specifications. # Handles: # Microsoft Windows pathnames (drive spec or server spec) # Samba (SMB) pathnames (functionally same as MS-Windows) # unix style mount points # cvs source repository modules (functionally same as mount points) # # Example 1 wiki text, for MS-Windows pathnames: # H:\Documents\BestPractices.doc # anchors as: # file:///H:/Documents/BestPractices.doc # # Example 2 wiki text, for MS-Windows Sharing or Samba: # \\MYSERVER\DOCS\Corporate\NDA.doc # anchors as: # file:////MYSERVER/DOCS/Corporate/NDA.doc # # Example 3 wiki text, for cvs repository module: # /src/current/kern/arch/arm32/Makefile # might anchor as: # http://intranet/cvsweb.cgi/current/kern/arch/arm32/Makefile # # Note the use of seemingly redundant slashes for file:// # which are actually important: # # absoluteURI = scheme ":" (heir_part) # hier_part = ( net_path | abs_path ) [ "?" query ] # net_path = "//" authority [ abs_path ] # abs_path = "/" path_segments # ========================= use vars qw( $web $topic $user $installWeb $VERSION $pluginName $debug %Shares $StrictFilenames %Mounts $EnableServerMap $EnableDriveMapExtReq $EnableDriveMapDelimited $EnableShareMap $EnableMountMap $FileChars ); $VERSION = '1.050'; $pluginName = 'SlashFilenamePlugin'; # Name of this Plugin # ========================= sub initPlugin { ( $topic, $web, $user, $installWeb ) = @_; # check for Plugins.pm versions if( $TWiki::Plugins::VERSION < 1 ) { TWiki::Func::writeWarning( "Version mismatch between $pluginName and Plugins.pm" ); return 0; } # XXX: Manual config required, since array prefs would be ugly # ----------------------------------------------------- # EDIT THE BELOW TO CONFIGURE THIS PLUGIN # ----------------------------------------------------- # SHARE CONFIGURATION %Shares # # Format is: # "fake mount point" "file:////server/share_name_here" # Not case sensitive. # # i.e. wiki text: "\doc\current\" # will anchor as "file:////SERVER/blah/blah/doc/current\" %Shares = ( 'd2share', 'file:////d2fs1/d2share', 'doc', 'file:////d2fs1/doc', 'projects', 'file:////d2fs1/projects', 'library', 'file:////d2fs1/library', 'testvec', 'file:////d2fs1/testvec' ); # MOUNT POINTS %Mounts # Note, there are three slashes in file:/// mounts # (two from file://, one from /directory) # put file: mounts first, url: mounts (cvsweb modules) second %Mounts = ( '/home/', 'file:///home/', '/var/log/messages', 'file:///var/log/messages', '/linux/kernel', # LXR ROOT URL: 'http://lxr.linux.no/source/'. # MODULE: 'arch/i386/kernel', '/src/sys/arch', # CVSROOT URL: 'http://cvsweb.netbsd.org/bsdweb.cgi/'. # MODULE: 'src/sys/arch', '/twiki/', # CVSROOT URL: 'http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/twiki' # MODULE: .'/twiki/' ); # CONFIGURATION FOR MODES # In case you want to turn one type of anchoring completely off, # set to zero. # XXX: Make these pref vars $EnableServerMap = 1; $EnableDriveMapExtReq = 1; $EnableDriveMapDelimited = 1; $EnableShareMap = 1; $EnableMountMap = 1; # ------------------------------------------------------------------------ # END OF CONFIGURATION SECTION, DON'T EDIT ANY OF THE BELOW WITHOUT RISK # ------------------------------------------------------------------------ # get Preferences $debug = TWiki::Func::getPreferencesFlag( "\U$pluginName\E_DEBUG" ) || "off"; # allow only URI-valid (RFC2396) chars in filenames # the following are reserved (not to be used): ;/?:@&=+$, # the following are ok: -_.!~*')( # but the following will cause problems: *)( $StrictFilenames = TWiki::Func::getPreferencesFlag( "\U$pluginName\E_STRICT" ) || "off"; $FileChars = '-.!~'."'"; if ( $StrictFilenames =~ /off/i ) { # allow some reserved/unwise characters in filenames (be careful) # definitely never allow ():<>?* or things will really break $FileChars .= '`$,[]+'; # XXX: the reserved characters should be escaped instead of dis/allowed } $FileChars =~ s/(.)/\\$1/g; # must escape the wierd ones, so escape all # Plugin correctly initialized TWiki::Func::writeDebug( "- TWiki::Plugins::${pluginName}::initPlugin( $web.$topic ) is OK" ) if $debug; return 1; } # ========================= sub DISABLE_startRenderingHandler { ### my ( $text, $web ) = @_; # do not uncomment, use $_[0], $_[1] instead my $sharePathStart; TWiki::Func::writeDebug( "- ${pluginName}::startRenderingHandler( $_[1] )" ) if $debug; # This handler is called by getRenderedVersion just before the line loop # do custom extension rule, like for example: # $_[0] =~ s/old/new/g; } # ========================= sub DISABLE_commonTagsHandler { ### my ( $text, $topic, $web ) = @_; # do not uncomment, use $_[0], $_[1]... instead TWiki::Func::writeDebug( "- ${pluginName}::commonTagsHandler( $_[2].$_[1] )" ) if $debug; # This is the place to define customized tags and variables # Called by sub handleCommonTags, after %INCLUDE:"..."% # do custom extension rule, like for example: # $_[0] =~ s/%XYZ%/&handleXyz()/ge; # $_[0] =~ s/%XYZ{(.*?)}%/&handleXyz($1)/ge; } # ========================= sub DISABLE_outsidePREHandler { ### my ( $text ) = @_; # do not uncomment, use $_[0] instead TWiki::Func::writeDebug( "- ${pluginName}::outsidePREHandler( $renderingWeb.$topic )" ) if $debug; # This handler is called by getRenderedVersion, once per line, before any changes, # for lines outside
 and  tags. 
    # Use it to define customized rendering rules.
    # Note: This is an expensive function to comment out.
    # Consider startRenderingHandler instead

    # do custom extension rule, like for example:
    # $_[0] =~ s/old/new/g;


}

# =========================
sub endRenderingHandler
{
### my ( $text ) = @_;   # do not uncomment, use $_[0] instead

    my $url;
    my $sharepath;
    my $mount;

    TWiki::Func::writeDebug( "- ${pluginName}::endRenderingHandler( $web.$topic )" ) if $debug;

    # This handler is called by getRenderedVersion just after the line loop,
    # that is, after almost all XHTML rendering of a topic.  tags are
    # removed after this.


# --- Server Mapping
# map \\server\share\path\name\file 
#  or //server/share/path/name/file
#  to file:////server/share/path/name/file link
# the //server/share part is required, the rest is gobbled
    $_[0] =~ s|
            # outside a word or link://
            ([\s])
            # slash slash
            [/\\]{2}
            # server name - no underlines
            # XXX: what's the correct max length?
            ([a-z\d\-]{1,30})
            # slash
            [/\\]
            # share name
            # XXX: what's the correct max length?
            ([\w\d\-]{1,30})
            # slash plus optional path/name
            (
                [\w$FileChars\\\/]{1,255}
            )
            |$1//$2/$3$4|gix
            # scheme slash slash
            # slash slash server
            # slash share slash path/name
        if $EnableServerMap;

# --- Drive mapping, extension required
#  x:/some/dir ectory/name of file.ext
# spaces in filenames allowed with extension
# This usage is purposely forced to display in uppercase (CP/M lives!)

    $_[0] =~ s!
            # outside a word or link
            ([^:a-z/]|[>])     
            # drive_letter colon
            ([a-z]\:)    
            # slash
            [/\\]                       
            # path & base name (may include extensions also)
            (
                ([\w$FileChars\\/]
                |
                [\s]){1,255}
            )
            # dot
            (\.)
            # final ending extension
            ([\w$FileChars]{1,9})
            !$1\U$2/$3$5$6\E!gix
            # scheme slash slash
            # slash drive_letter colon
            # slash path/name
        if $EnableDriveMapExtReq;

# --- Drive mapping, delimiter required
# map common filename with drive letter, delimiter required
#  x:/some/dir ectory/name of file without extension
# spaces in filenames allowed with \W boundary
# This usage is purposely forced to display in uppercase
    $_[0] =~ s!
            ([\s>(])     # outside a word or link, or inside delimiter
            ([a-z]\:)    # drive_letter colon
            [/\\]                       # slash
            # path & base name
            # path/path path/path path \W
            (
                ([\w$FileChars\\/]
                |
                [\s]){1,255}
            )
            # delimiter matches any funny char
            ([\W]{1})             
#           # delimiter matches only html delimiter < or ):
#            ([\<)\:]{1})             
            !$1\U$2/$3\E$5!gix
            # scheme slash slash
            # slash drive_letter colon
            # slash path/name
        if $EnableDriveMapDelimited;


# map shares
# spaces in filenames not allowed (maybe in next version?)

# XXX: optimize this loop
    if ($EnableShareMap) { 
        foreach $share (keys %Shares) { 
            $sharepath = $Shares{$share};
            $_[0] =~ s|
                    # outside a word or link
                    ([\s])     
                    # slash
                    [/\\]               
                    # sharename
                    ($share)            
                    # slash
                    [/\\]               
                    # path/name (required)
                    (
                        [\w$FileChars\\\/]{1,255}
                    )
                    |$1/$2/$3|gix;
        } 
    }

# map mount points
# spaces in filenames not allowed

# XXX: optimize this loop
    if ($EnableMountMap) { 
        foreach $mount (keys %Mounts) { 
            $url = $Mounts{$mount};
            $_[0] =~ s!
                    # outside a word or link
                    ([^\w$FileChars\\/])
                    # "directory" - key
                    ($mount)         
                    # path - text to concatenate to url, may include slash
                    (
                        [\w$FileChars\\/]{0,255}
                    )
                    !$1$2$3!gix;
        } 
    }
}


1;