2002-01-10 11:00:51 +03:00
|
|
|
#
|
2004-03-24 14:53:31 +03:00
|
|
|
# = uri/mailto.rb
|
2002-01-10 11:00:51 +03:00
|
|
|
#
|
2004-03-24 14:53:31 +03:00
|
|
|
# Author:: Akira Yamada <akira@ruby-lang.org>
|
|
|
|
# License:: You can redistribute it and/or modify it under the same term as Ruby.
|
|
|
|
# Revision:: $Id$
|
2002-01-10 11:00:51 +03:00
|
|
|
#
|
|
|
|
|
|
|
|
require 'uri/generic'
|
|
|
|
|
|
|
|
module URI
|
|
|
|
|
2004-03-24 14:53:31 +03:00
|
|
|
#
|
2002-01-10 11:00:51 +03:00
|
|
|
# RFC2368, The mailto URL scheme
|
2004-03-24 14:53:31 +03:00
|
|
|
#
|
2002-01-10 11:00:51 +03:00
|
|
|
class MailTo < Generic
|
|
|
|
include REGEXP
|
|
|
|
|
|
|
|
DEFAULT_PORT = nil
|
|
|
|
|
2004-03-24 14:53:31 +03:00
|
|
|
COMPONENT = [ :scheme, :to, :headers ].freeze
|
2002-01-10 11:00:51 +03:00
|
|
|
|
2004-03-24 14:53:31 +03:00
|
|
|
# :stopdoc:
|
2002-01-10 11:00:51 +03:00
|
|
|
# "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.
|
|
|
|
|
|
|
|
# hname = *urlc
|
|
|
|
# hvalue = *urlc
|
|
|
|
# header = hname "=" hvalue
|
2002-10-04 10:26:45 +04:00
|
|
|
HEADER_PATTERN = "(?:[^?=&]*=[^?=&]*)".freeze
|
|
|
|
HEADER_REGEXP = Regexp.new(HEADER_PATTERN, 'N').freeze
|
2002-01-10 11:00:51 +03:00
|
|
|
# headers = "?" header *( "&" header )
|
|
|
|
# to = #mailbox
|
|
|
|
# mailtoURL = "mailto:" [ to ] [ headers ]
|
2002-10-20 14:54:19 +04:00
|
|
|
MAILBOX_PATTERN = "(?:#{PATTERN::ESCAPED}|[^(),%?=&])".freeze
|
2004-03-24 14:53:31 +03:00
|
|
|
MAILTO_REGEXP = Regexp.new(" # :nodoc:
|
2002-01-10 11:00:51 +03:00
|
|
|
\\A
|
2002-10-04 10:26:45 +04:00
|
|
|
(#{MAILBOX_PATTERN}*?) (?# 1: to)
|
2002-01-10 11:00:51 +03:00
|
|
|
(?:
|
|
|
|
\\?
|
2002-10-04 10:26:45 +04:00
|
|
|
(#{HEADER_PATTERN}(?:\\&#{HEADER_PATTERN})*) (?# 2: headers)
|
2002-01-10 11:00:51 +03:00
|
|
|
)?
|
2004-02-22 07:06:09 +03:00
|
|
|
(?:
|
|
|
|
\\#
|
2004-03-24 14:53:31 +03:00
|
|
|
(#{PATTERN::FRAGMENT}) (?# 3: fragment)
|
2004-02-22 07:06:09 +03:00
|
|
|
)?
|
2002-01-10 11:00:51 +03:00
|
|
|
\\z
|
2002-10-04 10:26:45 +04:00
|
|
|
", Regexp::EXTENDED, 'N').freeze
|
2004-03-24 14:53:31 +03:00
|
|
|
# :startdoc:
|
2002-01-10 11:00:51 +03:00
|
|
|
|
2004-03-24 14:53:31 +03:00
|
|
|
#
|
|
|
|
# == Description
|
|
|
|
#
|
|
|
|
# Creates a new URI::MailTo object from components of URI::MailTo
|
|
|
|
# with check. It is to and headers. It provided by an Array of a
|
|
|
|
# Hash. You can provide headers as String like
|
|
|
|
# "subject=subscribe&cc=addr" or Array like [["subject",
|
|
|
|
# "subscribe"], ["cc", "addr"]]
|
|
|
|
#
|
2002-01-10 11:00:51 +03:00
|
|
|
def self.build(args)
|
|
|
|
tmp = Util::make_components_hash(self, args)
|
|
|
|
|
|
|
|
if tmp[:to]
|
2004-03-24 14:53:31 +03:00
|
|
|
tmp[:opaque] = tmp[:to]
|
2002-01-10 11:00:51 +03:00
|
|
|
else
|
2004-03-24 14:53:31 +03:00
|
|
|
tmp[:opaque] = ''
|
2002-01-10 11:00:51 +03:00
|
|
|
end
|
|
|
|
|
|
|
|
if tmp[:headers]
|
2004-03-24 14:53:31 +03:00
|
|
|
tmp[:opaque] << '?'
|
|
|
|
|
|
|
|
if tmp[:headers].kind_of?(Array)
|
|
|
|
tmp[:opaque] << tmp[:headers].collect { |x|
|
|
|
|
if x.kind_of?(Array)
|
|
|
|
x[0] + '=' + x[1..-1].to_s
|
|
|
|
else
|
|
|
|
x.to_s
|
|
|
|
end
|
|
|
|
}.join('&')
|
|
|
|
|
|
|
|
elsif tmp[:headers].kind_of?(Hash)
|
|
|
|
tmp[:opaque] << tmp[:headers].collect { |h,v|
|
|
|
|
h + '=' + v
|
|
|
|
}.join('&')
|
|
|
|
|
|
|
|
else
|
|
|
|
tmp[:opaque] << tmp[:headers].to_s
|
|
|
|
end
|
2002-01-10 11:00:51 +03:00
|
|
|
end
|
|
|
|
|
|
|
|
return super(tmp)
|
|
|
|
end
|
|
|
|
|
2004-03-24 14:53:31 +03:00
|
|
|
#
|
|
|
|
# == Description
|
|
|
|
#
|
|
|
|
# Creates a new URI::MailTo object from ``generic'' components with
|
|
|
|
# no check. Because, this method is usually called from URI::parse
|
|
|
|
# and the method checks validity of each components.
|
|
|
|
#
|
2002-01-10 11:00:51 +03:00
|
|
|
def initialize(*arg)
|
|
|
|
super(*arg)
|
|
|
|
|
|
|
|
@to = nil
|
|
|
|
@headers = []
|
|
|
|
|
|
|
|
if MAILTO_REGEXP =~ @opaque
|
2004-03-24 14:53:31 +03:00
|
|
|
if arg[-1]
|
|
|
|
self.to = $1
|
|
|
|
self.headers = $2
|
|
|
|
else
|
|
|
|
set_to($1)
|
|
|
|
set_headers($2)
|
|
|
|
end
|
2002-10-20 14:54:19 +04:00
|
|
|
|
|
|
|
else
|
2004-03-24 14:53:31 +03:00
|
|
|
raise InvalidComponentError,
|
|
|
|
"unrecognised opaque part for mailtoURL: #{@opaque}"
|
2002-01-10 11:00:51 +03:00
|
|
|
end
|
|
|
|
end
|
|
|
|
attr_reader :to
|
|
|
|
attr_reader :headers
|
|
|
|
|
|
|
|
def check_to(v)
|
|
|
|
return true unless v
|
|
|
|
return true if v.size == 0
|
|
|
|
|
2002-10-04 10:26:45 +04:00
|
|
|
if OPAQUE !~ v || /\A#{MAILBOX_PATTERN}*\z/o !~ v
|
2004-03-24 14:53:31 +03:00
|
|
|
raise InvalidComponentError,
|
|
|
|
"bad component(expected opaque component): #{v}"
|
2002-01-10 11:00:51 +03:00
|
|
|
end
|
|
|
|
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
private :check_to
|
|
|
|
|
|
|
|
def set_to(v)
|
|
|
|
@to = v
|
|
|
|
end
|
|
|
|
protected :set_to
|
|
|
|
|
|
|
|
def to=(v)
|
|
|
|
check_to(v)
|
|
|
|
set_to(v)
|
2003-02-14 08:32:48 +03:00
|
|
|
v
|
2002-01-10 11:00:51 +03:00
|
|
|
end
|
|
|
|
|
|
|
|
def check_headers(v)
|
|
|
|
return true unless v
|
|
|
|
return true if v.size == 0
|
|
|
|
|
|
|
|
if OPAQUE !~ v ||
|
2004-03-24 14:53:31 +03:00
|
|
|
/\A(#{HEADER_PATTERN}(?:\&#{HEADER_PATTERN})*)\z/o !~ v
|
|
|
|
raise InvalidComponentError,
|
|
|
|
"bad component(expected opaque component): #{v}"
|
2002-01-10 11:00:51 +03:00
|
|
|
end
|
|
|
|
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
private :check_headers
|
|
|
|
|
|
|
|
def set_headers(v)
|
|
|
|
@headers = []
|
|
|
|
if v
|
2004-03-24 14:53:31 +03:00
|
|
|
v.scan(HEADER_REGEXP) do |x|
|
|
|
|
@headers << x.split(/=/o, 2)
|
|
|
|
end
|
2002-01-10 11:00:51 +03:00
|
|
|
end
|
|
|
|
end
|
|
|
|
protected :set_headers
|
|
|
|
|
|
|
|
def headers=(v)
|
|
|
|
check_headers(v)
|
|
|
|
set_headers(v)
|
2003-02-14 08:32:48 +03:00
|
|
|
v
|
2002-01-10 11:00:51 +03:00
|
|
|
end
|
|
|
|
|
2003-10-04 07:49:01 +04:00
|
|
|
def to_s
|
2002-01-10 11:00:51 +03:00
|
|
|
@scheme + ':' +
|
2004-03-24 14:53:31 +03:00
|
|
|
if @to
|
|
|
|
@to
|
|
|
|
else
|
|
|
|
''
|
|
|
|
end +
|
|
|
|
if @headers.size > 0
|
|
|
|
'?' + @headers.collect{|x| x.join('=')}.join('&')
|
|
|
|
else
|
|
|
|
''
|
|
|
|
end +
|
|
|
|
if @fragment
|
|
|
|
'#' + @fragment
|
|
|
|
else
|
|
|
|
''
|
|
|
|
end
|
2002-01-10 11:00:51 +03:00
|
|
|
end
|
2004-03-24 14:53:31 +03:00
|
|
|
#
|
|
|
|
# == Usage
|
|
|
|
# require 'uri'
|
|
|
|
#
|
|
|
|
# uri = 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"
|
|
|
|
#
|
2002-01-10 11:00:51 +03:00
|
|
|
def to_mailtext
|
|
|
|
to = URI::unescape(@to)
|
|
|
|
head = ''
|
|
|
|
body = ''
|
|
|
|
@headers.each do |x|
|
2004-03-24 14:53:31 +03:00
|
|
|
case x[0]
|
|
|
|
when 'body'
|
|
|
|
body = URI::unescape(x[1])
|
|
|
|
when 'to'
|
|
|
|
to << ', ' + URI::unescape(x[1])
|
|
|
|
else
|
|
|
|
head << URI::unescape(x[0]).capitalize + ': ' +
|
|
|
|
URI::unescape(x[1]) + "\n"
|
|
|
|
end
|
2002-01-10 11:00:51 +03:00
|
|
|
end
|
|
|
|
|
|
|
|
return "To: #{to}
|
|
|
|
#{head}
|
|
|
|
#{body}
|
|
|
|
"
|
|
|
|
end
|
|
|
|
alias to_rfc822text to_mailtext
|
2004-03-24 14:53:31 +03:00
|
|
|
end
|
2002-01-10 11:00:51 +03:00
|
|
|
|
|
|
|
@@schemes['MAILTO'] = MailTo
|
2004-03-24 14:53:31 +03:00
|
|
|
end
|