# frozen_string_literal: false# = uri/mailto.rb## Author:: Akira Yamada <akira@ruby-lang.org># License:: You can redistribute it and/or modify it under the same term as Ruby.# Revision:: $Id$## See Bundler::URI for general documentation#require_relative'generic'moduleBundler::URI## RFC6068, the mailto URL scheme.#classMailTo<GenericincludeREGEXP# A Default port of nil for Bundler::URI::MailTo.DEFAULT_PORT=nil# An Array of the available components for Bundler::URI::MailTo.COMPONENT=[:scheme,:to,:headers].freeze# :stopdoc:# "hname" and "hvalue" are encodings of an RFC 822 header name and# value, respectively. As with "to", all URL reserved characters must# be encoded.## "#mailbox" is as specified in RFC 822 [RFC822]. This means that it# consists of zero or more comma-separated mail addresses, possibly# including "phrase" and "comment" components. Note that all URL# reserved characters in "to" must be encoded: in particular,# parentheses, commas, and the percent sign ("%"), which commonly occur# in the "mailbox" syntax.## Within mailto URLs, the characters "?", "=", "&" are reserved.# ; RFC 6068# hfields = "?" hfield *( "&" hfield )# hfield = hfname "=" hfvalue# hfname = *qchar# hfvalue = *qchar# qchar = unreserved / pct-encoded / some-delims# some-delims = "!" / "$" / "'" / "(" / ")" / "*"# / "+" / "," / ";" / ":" / "@"## ; RFC3986# unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"# pct-encoded = "%" HEXDIG HEXDIGHEADER_REGEXP=/\A(?<hfield>(?:%\h\h|[!$'-.0-;@-Z_a-z~])*=(?:%\h\h|[!$'-.0-;@-Z_a-z~])*)(?:&\g<hfield>)*\z/# practical regexp for email address# https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-addressEMAIL_REGEXP=/\A[a-zA-Z0-9.!\#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*\z/# :startdoc:## == Description## Creates a new Bundler::URI::MailTo object from components, with syntax checking.## Components can be provided as an Array or Hash. If an Array is used,# the components must be supplied as <code>[to, headers]</code>.## If a Hash is used, the keys are the component names preceded by colons.## The headers can be supplied as a pre-encoded string, such as# <code>"subject=subscribe&cc=address"</code>, or as an Array of Arrays# like <code>[['subject', 'subscribe'], ['cc', 'address']]</code>.## Examples:## require 'bundler/vendor/uri/lib/uri'## m1 = Bundler::URI::MailTo.build(['joe@example.com', 'subject=Ruby'])# m1.to_s # => "mailto:joe@example.com?subject=Ruby"## m2 = Bundler::URI::MailTo.build(['john@example.com', [['Subject', 'Ruby'], ['Cc', 'jack@example.com']]])# m2.to_s # => "mailto:john@example.com?Subject=Ruby&Cc=jack@example.com"## m3 = Bundler::URI::MailTo.build({:to => 'listman@example.com', :headers => [['subject', 'subscribe']]})# m3.to_s # => "mailto:listman@example.com?subject=subscribe"#defself.build(args)tmp=Util.make_components_hash(self,args)casetmp[:to]whenArraytmp[:opaque]=tmp[:to].join(',')whenStringtmp[:opaque]=tmp[:to].dupelsetmp[:opaque]=''endiftmp[:headers]query=casetmp[:headers]whenArraytmp[:headers].collect{|x|ifx.kind_of?(Array)x[0]+'='+x[1..-1].joinelsex.to_send}.join('&')whenHashtmp[:headers].collect{|h,v|h+'='+v}.join('&')elsetmp[:headers].to_sendunlessquery.empty?tmp[:opaque]<<'?'<<queryendendsuper(tmp)end## == Description## Creates a new Bundler::URI::MailTo object from generic URL components with# no syntax checking.## This method is usually called from Bundler::URI::parse, which checks# the validity of each component.#definitialize(*arg)super(*arg)@to=nil@headers=[]# The RFC3986 parser does not normally populate opaque@opaque="?#{@query}"if@query&&!@opaqueunless@opaqueraiseInvalidComponentError,"missing opaque part for mailto URL"endto,header=@opaque.split('?',2)# allow semicolon as a addr-spec separator# http://support.microsoft.com/kb/820868unless/\A(?:[^@,;]+@[^@,;]+(?:\z|[,;]))*\z/=~toraiseInvalidComponentError,"unrecognised opaque part for mailtoURL: #{@opaque}"endifarg[10]# arg_checkself.to=toself.headers=headerelseset_to(to)set_headers(header)endend# The primary e-mail address of the URL, as a String.attr_reader:to# E-mail headers set by the URL, as an Array of Arrays.attr_reader:headers# Checks the to +v+ component.defcheck_to(v)returntrueunlessvreturntrueifv.size==0v.split(/[,;]/).eachdo|addr|# check url safety as path-rootlessif/\A(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*\z/!~addrraiseInvalidComponentError,"an address in 'to' is invalid as Bundler::URI #{addr.dump}"end# check addr-spec# don't s/\+/ /gaddr.gsub!(/%\h\h/,Bundler::URI::TBLDECWWWCOMP_)ifEMAIL_REGEXP!~addrraiseInvalidComponentError,"an address in 'to' is invalid as uri-escaped addr-spec #{addr.dump}"endendtrueendprivate:check_to# Private setter for to +v+.defset_to(v)@to=vendprotected:set_to# Setter for to +v+.defto=(v)check_to(v)set_to(v)vend# Checks the headers +v+ component against either# * HEADER_REGEXPdefcheck_headers(v)returntrueunlessvreturntrueifv.size==0ifHEADER_REGEXP!~vraiseInvalidComponentError,"bad component(expected opaque component): #{v}"endtrueendprivate:check_headers# Private setter for headers +v+.defset_headers(v)@headers=[]ifvv.split('&').eachdo|x|@headers<<x.split(/=/,2)endendendprotected:set_headers# Setter for headers +v+.defheaders=(v)check_headers(v)set_headers(v)vend# Constructs String from Bundler::URI.defto_s@scheme+':'+if@to@toelse''end+if@headers.size>0'?'+@headers.collect{|x|x.join('=')}.join('&')else''end+if@fragment'#'+@fragmentelse''endend# Returns the RFC822 e-mail text equivalent of the URL, as a String.## Example:## require 'bundler/vendor/uri/lib/uri'## uri = Bundler::URI.parse("mailto:ruby-list@ruby-lang.org?Subject=subscribe&cc=myaddr")# uri.to_mailtext# # => "To: ruby-list@ruby-lang.org\nSubject: subscribe\nCc: myaddr\n\n\n"#defto_mailtextto=Bundler::URI.decode_www_form_component(@to)head=''body=''@headers.eachdo|x|casex[0]when'body'body=Bundler::URI.decode_www_form_component(x[1])when'to'to<<', '+Bundler::URI.decode_www_form_component(x[1])elsehead<<Bundler::URI.decode_www_form_component(x[0]).capitalize+': '+Bundler::URI.decode_www_form_component(x[1])+"\n"endend"To: #{to}#{head}#{body}
"endaliasto_rfc822textto_mailtextend@@schemes['MAILTO']=MailToend