﻿<?xml version="1.0" encoding="UTF-8"?>
<!--
	This file defines regular expressions for XML Forms URL validation.
	A <pattern> tag defines a valid pattern. If the given pattern matches the input string, the input is
	considered as valid.
	An <invalidpattern> tag defines an invalid pattern. If that pattern matches the input string, the
	input is considered as invalid.
	Multiple patterns can be defined in a <sequence> tag. All contained <pattern> and <invalidpattern>
	are subsequently tested, until the first one matches.
	A combination of <choose>, <choice> and <default> makes it possible to handle several cases.
	The first <choice> tag with a matching pattern will be handled, as if it were a sequence. If no
	pattern in a <choice> matches, the sequence in <default> is used, if a default is available.
	If no <choice> matches, and no <default> is provided, the input string is invalid.

	The <pattern> tag can provide an additional attribute "format"
		format - if a matching pattern has a format attribute, the input string is reformatted according
			to that attribute. The input string is referenced with {0}. For example: the format
			string "http://{0}" will prepend a http:// prefix, if the pattern matched.
			Whe a format attribute is used, the order of <pattern> tags is important.
	
	An <invalidpattern> tag can have an "errorKey" attribute
		errorKey - key for lookup in resource file. If the key is not available, it is ignored
		
	A pattern string can reference any pattern part, which was defined in a <patternpart> tag.
	Pattern parts are referenced by putting	the part name in % signs, e.g. %domain%.
	Pattern parts can also reference previously defined pattern parts.
	A pattern part must be defined before it is referenced.,
	
	The root element should be left as a <sequence>, all pattern parts should be defined at root level.
-->

<sequence>
	<patternpart name="user">([^\.\/\:\?=;@&amp;]*)</patternpart>
	<patternpart name="password">([^\.\/\:\?=;@&amp;]*)</patternpart>
	<patternpart name="logininfo">(%user%(\:%password%)?)</patternpart>
	<patternpart name="domainpart">([^\.\/\:\?=;@&amp;]{2,})</patternpart>
	<patternpart name="domain">(%domainpart%(\.%domainpart%)+)</patternpart>
	<patternpart name="hostname">([^\/\:\?=;@&amp;]{2,})</patternpart>
	<patternpart name="ipaddress">(([0-9]{1,3}\.){3}[0-9]{1,3})</patternpart>
	<!--<patternpart name="host">(%hostname%|%hostname%\.%domain%|([0-9]{1,3}\.){3}[0-9]{1,3})</patternpart>-->
	<patternpart name="port">([0-9]{1,5})</patternpart>
	<patternpart name="path">([^\?;]+?)</patternpart>
	<patternpart name="searchpart">(.*?)</patternpart>
	<patternpart name="typeinfo">(type=[aid])</patternpart>
	<patternpart name="scheme">(([A-Za-z0-9\+\-\.]+)|(&amp;lt;PORTAL_NAVIGATION&amp;gt;[^\:]*))</patternpart>
	<patternpart name="xchar">([A-Za-z0-9_$\-\.\+!\*'\(\),;\/\?\:@&amp;=]|(%[a-fA-F0-9]{2}))</patternpart>
	<patternpart name="http">((h|H)(t|T)(t|T)(p|P))</patternpart>
	<patternpart name="ftp">(f|F)(t|T)(p|P)</patternpart>
	<patternpart name="mailto">(m|M)(a|A)(i|I)(l|L)(t|T)(o|O)</patternpart>
	<patternpart name="telnet">(t|T)(e|E)(l|L)(n|N)(e|E)(t|T)</patternpart>
	<patternpart name="file">(f|F)(i|I)(l|L)(e|E)</patternpart>

	<!-- empty URL -->
	<choose>
		<choice pattern="^%http%:">
			<!--
				http URL
				host is required; port, path and query string are optional
				login information is not allowed
			-->
			
			<!-- with trailing /, optional path and optional query string -->
			<pattern>^%http%://%hostname%(:%port%)?\/%path%?(\?%searchpart%)?$</pattern>

			<!-- without trailing /, append it -->
			<pattern format="{0}/">^%http%://%hostname%(:%port%)?$</pattern>
			
			<!-- port more than 5 chars -->
			<invalidpattern errorKey="xmsg_invalid_port">^%http%://%hostname%:([0-9]{6,})(\/|$)</invalidpattern>
			
			<!-- empty port -->
			<invalidpattern errorKey="xmsg_invalid_port">^%http%://%hostname%:(\/|$)</invalidpattern>
			
			<!-- port contains non-digits -->
			<invalidpattern errorKey="xmsg_invalid_port">^%http%://%hostname%:([0-9]*[^0-9]+[0-9]*)(\/|$)</invalidpattern>
		</choice>
		<choice pattern="^%ftp%:">
			<!--
				ftp URL
				host is required; port, path, type info and login info are optional
			-->
			
			<!-- with trailing slash, optional path and type info -->
			<pattern>^%ftp%://(%logininfo%@)?%hostname%(:%port%)?\/%path%?(;%typeinfo%)?$</pattern>
			
			<!-- without trailing slash and path, optional type info -->
			<pattern>^%ftp%://(%logininfo%@)?%hostname%(:%port%)?(;%typeinfo%)?$</pattern>
			
			<!-- port more than 5 chars -->
			<invalidpattern errorKey="xmsg_invalid_port">^%ftp%://%logininfo%%hostname%:[0-9]{6,}(\/|$)</invalidpattern>

			<!-- empty port -->
			<invalidpattern errorKey="xmsg_invalid_port">^%ftp%://%logininfo%%hostname%:(\/|$)</invalidpattern>
		</choice>
		<choice pattern="^%mailto%:">
			<!--
				mailto URL
				must contain a valid email address
			-->
			<pattern>^%mailto%:%user%@%domain%$</pattern>
			
			<!-- @ sign is missing -->
			<invalidpattern errorKey="xmsg_mailto_wo_at">^[^@]+$</invalidpattern>
		</choice>
		<choice pattern="^%telnet%:">
			<!--
				telnet URL
				host is required; port and login info are optional
				path is not allowed
			-->			
			<pattern>^%telnet%://(%logininfo%@)?%hostname%(:%port%)?\/?$</pattern>
		</choice>
		<choice pattern="^%file%:">
			<!--
				file 'URL'
				host can be omitted, path is required
				port and login info are not allowed
			-->
			<pattern>^%file%://(\/)?%path%$</pattern>
			<pattern>^%file%://%hostname%\/%path%$</pattern>
		</choice>
		<default>
			<!--
				non of the above matched
				first check for empty URL
				then test, if it could be a http URL without protocol definition
				then test, if it is a URL without protocol
				otherwise, it is a generic URL
			-->
			<pattern>^$</pattern>
			<pattern format="http://{0}">^%hostname%(:%port%)?\/%path%?(\?%searchpart%)?$</pattern>
			<pattern format="http://{0}/">^%hostname%(:%port%)?$</pattern>
			<pattern>^%path%(\?%searchpart%)?$</pattern>
			<pattern>^%scheme%:%xchar%*$</pattern>
			<pattern>^%scheme%:(%logininfo%@)?%hostname%\/(%path%?)$</pattern>
			<pattern>^%scheme%:(%logininfo%@)?%hostname%$</pattern>
			<invalidpattern errorKey="xmsg_invalid_protocol">^[A-Za-z0-9\+\-\.]*[^A-Za-z0-9\+\-\.]+[A-Za-z0-9\+\-\.]*:</invalidpattern>
			<invalidpattern errorKey="xmsg_empty_protocol">^\:</invalidpattern>
		</default>
	</choose>
</sequence>
