001/* 002 Licensed to the Apache Software Foundation (ASF) under one 003 or more contributor license agreements. See the NOTICE file 004 distributed with this work for additional information 005 regarding copyright ownership. The ASF licenses this file 006 to you under the Apache License, Version 2.0 (the 007 "License"); you may not use this file except in compliance 008 with the License. You may obtain a copy of the License at 009 010 http://www.apache.org/licenses/LICENSE-2.0 011 012 Unless required by applicable law or agreed to in writing, 013 software distributed under the License is distributed on an 014 "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 KIND, either express or implied. See the License for the 016 specific language governing permissions and limitations 017 under the License. 018 */ 019package org.apache.wiki.plugin; 020 021import java.util.Locale; 022import org.apache.wiki.api.core.Attachment; 023import org.apache.wiki.api.core.Context; 024import org.apache.wiki.api.core.ContextEnum; 025import org.apache.wiki.api.core.Engine; 026import org.apache.wiki.api.exceptions.PluginException; 027import org.apache.wiki.api.exceptions.ProviderException; 028import org.apache.wiki.api.plugin.Plugin; 029import org.apache.wiki.attachment.AttachmentManager; 030import org.apache.wiki.parser.MarkupParser; 031import org.apache.wiki.util.TextUtil; 032 033import java.util.Map; 034import java.util.ResourceBundle; 035 036 037/** 038 * Provides an image plugin for better control than is possible with a simple image inclusion. 039 * <br> Most parameters are equivalents of the html image attributes. 040 * 041 * <p>Parameters : </p> 042 * <ul> 043 * <li><b>src</b> - the source (a URL) of the image (required parameter)</li> 044 * <li><b>align</b> - the alignment of the image</li> 045 * <li><b>height</b> - the height of the image</li> 046 * <li><b>width</b> - the width of the image</li> 047 * <li><b>alt</b> - alternate text</li> 048 * <li><b>caption</b> - the caption for the image</li> 049 * <li><b>link</b> - the hyperlink for the image</li> 050 * <li><b>target</b> - the target (frame) to be used for opening the image</li> 051 * <li><b>style</b> - the style attribute of the image</li> 052 * <li><b>class</b> - the associated class for the image</li> 053 * <li><b>border</b> - the border for the image</li> 054 * <li><b>title</b> - the title for the image, can be presented as a tooltip to the user</li> 055 * </ul> 056 * 057 * @since 2.1.4. 058 */ 059// FIXME: It is not yet possible to do wiki internal links. In order to do this cleanly, a TranslatorReader revamp is needed. 060public class Image implements Plugin { 061 062 /** The parameter name for setting the src. Value is <tt>{@value}</tt>. */ 063 public static final String PARAM_SRC = "src"; 064 /** The parameter name for setting the align parameter. Value is <tt>{@value}</tt>. */ 065 public static final String PARAM_ALIGN = "align"; 066 /** The parameter name for setting the height. Value is <tt>{@value}</tt>. */ 067 public static final String PARAM_HEIGHT = "height"; 068 /** The parameter name for setting the width. Value is <tt>{@value}</tt>. */ 069 public static final String PARAM_WIDTH = "width"; 070 /** The parameter name for setting the alt. Value is <tt>{@value}</tt>. */ 071 public static final String PARAM_ALT = "alt"; 072 /** The parameter name for setting the caption. Value is <tt>{@value}</tt>. */ 073 public static final String PARAM_CAPTION = "caption"; 074 /** The parameter name for setting the link. Value is <tt>{@value}</tt>. */ 075 public static final String PARAM_LINK = "link"; 076 /** The parameter name for setting the target. Value is <tt>{@value}</tt>. */ 077 public static final String PARAM_TARGET = "target"; 078 /** The parameter name for setting the style. Value is <tt>{@value}</tt>. */ 079 public static final String PARAM_STYLE = "style"; 080 /** The parameter name for setting the class. Value is <tt>{@value}</tt>. */ 081 public static final String PARAM_CLASS = "class"; 082 /** The parameter name for setting the border. Value is <tt>{@value}</tt>. */ 083 public static final String PARAM_BORDER = "border"; 084 /** The parameter name for setting the title. Value is <tt>{@value}</tt>. */ 085 public static final String PARAM_TITLE = "title"; 086 087 /** 088 * This method is used to clean away things like quotation marks which 089 * a malicious user could use to stop processing and insert javascript. 090 */ 091 private static String getCleanParameter( final Map< String, String > params, final String paramId ) { 092 return TextUtil.replaceEntities( params.get( paramId ) ); 093 } 094 095 @Override 096 public String getDisplayName(Locale locale) { 097 final ResourceBundle rb = ResourceBundle.getBundle(PluginManager.PLUGIN_I18N_RESOURCE, locale); 098 return rb.getString(this.getClass().getSimpleName()); 099 } 100 101 @Override 102 public String getSnipExample() { 103 return "Image src='{image.jpg}'"; 104 } 105 106 private boolean needsSanitization(String link) { 107 String testVal = link.toLowerCase().replaceAll("\\s+", "").trim(); 108 if (testVal.startsWith("data") 109 || testVal.startsWith("javascript") 110 || testVal.startsWith("vbscript")) { 111 return true; 112 } 113 return false; 114 } 115 116 /** 117 * {@inheritDoc} 118 */ 119 @Override 120 public String execute( final Context context, final Map<String, String> params ) throws PluginException { 121 final Engine engine = context.getEngine(); 122 String src = getCleanParameter( params, PARAM_SRC ); 123 final String align = getCleanParameter( params, PARAM_ALIGN ); 124 final String ht = getCleanParameter( params, PARAM_HEIGHT ); 125 final String wt = getCleanParameter( params, PARAM_WIDTH ); 126 final String alt = getCleanParameter( params, PARAM_ALT ); 127 final String caption = getCleanParameter( params, PARAM_CAPTION ); 128 String link = getCleanParameter( params, PARAM_LINK ); 129 String target = getCleanParameter( params, PARAM_TARGET ); 130 final String style = getCleanParameter( params, PARAM_STYLE ); 131 final String cssclass= getCleanParameter( params, PARAM_CLASS ); 132 final String border = getCleanParameter( params, PARAM_BORDER ); 133 final String title = getCleanParameter( params, PARAM_TITLE ); 134 135 if( src == null ) { 136 throw new PluginException("Parameter 'src' is required for Image plugin"); 137 } 138 139 //if( cssclass == null ) cssclass = "imageplugin"; 140 141 if( target != null && !validTargetValue(target) ) { 142 target = null; // not a valid value so ignore 143 } 144 145 try { 146 final AttachmentManager mgr = engine.getManager( AttachmentManager.class ); 147 final Attachment att = mgr.getAttachmentInfo( context, src ); 148 149 if( att != null ) { 150 src = context.getURL( ContextEnum.PAGE_ATTACH.getRequestContext(), att.getName() ); 151 } 152 } catch( final ProviderException e ) { 153 throw new PluginException( "Attachment info failed: " + e.getMessage() ); 154 } 155 156 final StringBuilder result = new StringBuilder(); 157 158 result.append( "<table border=\"0\" class=\"imageplugin\"" ); 159 160 if( title != null ) { 161 result.append( " title=\"" ).append( title ).append( "\"" ); 162 } 163 164 if( align != null ) { 165 if( align.equals( "center" ) ) { 166 result.append( " style=\"margin-left: auto; margin-right: auto; text-align:center; vertical-align:middle;\"" ); 167 } else { 168 result.append( " style=\"float:" ).append( align ).append( ";\"" ); 169 } 170 } 171 172 result.append( ">\n" ); 173 174 if( caption != null ) { 175 result.append( "<caption>" ).append( caption ).append( "</caption>\n" ); 176 } 177 178 // move css class and style to the container of the image, so it doesn't affect the caption 179 result.append( "<tr><td" ); 180 181 if( cssclass != null ) { 182 result.append( " class=\"" ).append( cssclass ).append( "\"" ); 183 } 184 185 if( style != null ) { 186 result.append( " style=\"" ).append( style ); 187 188 // Make sure that we add a ";" to the end of the style string 189 if( result.charAt( result.length()-1 ) != ';' ) { 190 result.append( ";" ); 191 } 192 193 result.append("\""); 194 } 195 196 result.append( ">" ); 197 198 if( link != null ) { 199 if( !context.getBooleanWikiProperty( MarkupParser.PROP_ALLOWHTML, false ) ) { 200 if (needsSanitization(link)) { 201 link = "http://invalid_url" + link; 202 } 203 } 204 result.append( "<a href=\"" ).append( link ).append( "\"" ); 205 if( target != null ) { 206 result.append( " target=\"" ).append( target ).append( "\"" ); 207 } 208 result.append(">"); 209 } 210 211 if(!context.getBooleanWikiProperty(MarkupParser.PROP_ALLOWHTML, false)) { 212 if (needsSanitization(src)) { 213 src = "http://invalid_url" + src; 214 } 215 } 216 result.append( "<img src=\"" ).append( src ).append( "\"" ); 217 218 if( ht != null ) { 219 result.append( " height=\"" ).append( ht ).append( "\"" ); 220 } 221 if( wt != null ) { 222 result.append( " width=\"" ).append( wt ).append( "\"" ); 223 } 224 if( alt != null ) { 225 result.append( " alt=\"" ).append( alt ).append( "\"" ); 226 } 227 if( border != null ) { 228 result.append( " border=\"" ).append( border ).append( "\"" ); 229 } 230 // if( map != null ) result.append(" map=\""+map+"\""); 231 232 result.append(" />"); 233 if( link != null ) { 234 result.append("</a>"); 235 } 236 result.append("</td></tr>\n"); 237 result.append("</table>\n"); 238 239 return result.toString(); 240 } 241 242 private boolean validTargetValue( final String s ) { 243 if( s.equals("_blank") 244 || s.equals("_self") 245 || s.equals("_parent") 246 || s.equals("_top") ) { 247 return true; 248 } else if( !s.isEmpty() ) { // check [a-zA-z] 249 final char c = s.charAt(0); 250 return Character.isLowerCase(c) || Character.isUpperCase(c); 251 } 252 return false; 253 } 254 255}