lib/uri/mailto.rb


DEFINITIONS

This source file includes following functions.


   1  #
   2  # $Id: mailto.rb,v 1.1 2002/01/10 08:00:51 akira Exp $
   3  #
   4  # Copyright (c) 2001 akira yamada <akira@ruby-lang.org>
   5  # You can redistribute it and/or modify it under the same term as Ruby.
   6  #
   7  
   8  require 'uri/generic'
   9  
  10  module URI
  11  
  12  =begin
  13  
  14  == URI::MailTo
  15  
  16  === Super Class
  17  
  18  ((<URI::Generic>))
  19  
  20  =end
  21  
  22    # RFC2368, The mailto URL scheme
  23    class MailTo < Generic
  24      include REGEXP
  25  
  26      DEFAULT_PORT = nil
  27  
  28      COMPONENT = [
  29        :scheme,
  30        :to, :headers
  31      ].freeze
  32  
  33      #  "hname" and "hvalue" are encodings of an RFC 822 header name and
  34      #  value, respectively. As with "to", all URL reserved characters must
  35      #  be encoded.
  36      #
  37      #  "#mailbox" is as specified in RFC 822 [RFC822]. This means that it
  38      #  consists of zero or more comma-separated mail addresses, possibly
  39      #  including "phrase" and "comment" components. Note that all URL
  40      #  reserved characters in "to" must be encoded: in particular,
  41      #  parentheses, commas, and the percent sign ("%"), which commonly occur
  42      #  in the "mailbox" syntax.
  43      #
  44      #  Within mailto URLs, the characters "?", "=", "&" are reserved.
  45  
  46      # hname      =  *urlc
  47      # hvalue     =  *urlc
  48      # header     =  hname "=" hvalue
  49      HEADER_REGEXP = "(?:[^?=&]*=[^?=&]*)".freeze
  50      # headers    =  "?" header *( "&" header )
  51      # to         =  #mailbox
  52      # mailtoURL  =  "mailto:" [ to ] [ headers ]
  53      MAILBOX_REGEXP = "(?:[^(),%?=&]|#{PATTERN::ESCAPED})".freeze
  54      MAILTO_REGEXP = Regexp.new("
  55        \\A
  56        (#{MAILBOX_REGEXP}*?)                         (?# 1: to)
  57        (?:
  58          \\?
  59          (#{HEADER_REGEXP}(?:\\&#{HEADER_REGEXP})*)  (?# 2: headers)
  60        )?
  61        \\z
  62      ", Regexp::EXTENDED, 'N').freeze
  63  
  64  =begin
  65  
  66  === Class Methods
  67  
  68  --- URI::MailTo::build
  69      Create a new URI::MailTo object from components of URI::MailTo
  70      with check.  It is to and headers. It provided by an Array of a
  71      Hash. You can provide headers as an String like
  72      "subject=subscribe&cc=addr" or an Array like [["subject",
  73      "subscribe"], ["cc", "addr"]]
  74  
  75  --- URI::MailTo::new
  76      Create a new URI::MailTo object from ``generic'' components with
  77      no check. Because, this method is usually called from URI::parse
  78      and the method checks validity of each components.
  79  
  80  =end
  81  
  82      def self.build(args)
  83        tmp = Util::make_components_hash(self, args)
  84  
  85        if tmp[:to]
  86          tmp[:opaque] = tmp[:to]
  87        else
  88          tmp[:opaque] = ''
  89        end
  90  
  91        if tmp[:headers]
  92          tmp[:opaque] << '?'
  93  
  94          if tmp[:headers].kind_of?(Array)
  95            tmp[:opaque] << tmp[:headers].collect { |x|
  96              if x.kind_of?(Array)
  97                x[0] + '=' + x[1..-1].to_s
  98              else
  99                x.to_s
 100              end
 101            }.join('&')
 102  
 103          elsif tmp[:headers].kind_of?(Hash)
 104            tmp[:opaque] << tmp[:headers].collect { |h,v|
 105              h + '=' + v
 106            }.join('&')
 107  
 108          else
 109            tmp[:opaque] << tmp[:headers].to_s
 110          end
 111        end
 112  
 113        return super(tmp)
 114      end
 115  
 116      def initialize(*arg)
 117        super(*arg)
 118  
 119        @to = nil
 120        @headers = []
 121  
 122        if MAILTO_REGEXP =~ @opaque
 123          if arg[-1]
 124            self.to = $1
 125            self.headers = $2
 126          else
 127            set_to($1)
 128            set_headers($2)
 129          end
 130        elsif arg[-1]
 131          raise InvalidComponentError,
 132            "unrecognised opaque part for mailtoURL: #{@opaque}"
 133        end
 134      end
 135      attr_reader :to
 136      attr_reader :headers
 137  
 138  =begin
 139  
 140  === Instance Methods
 141  
 142  --- URI::MailTo#to
 143  
 144  --- URI::MailTo#to=(v)
 145  
 146  =end
 147  
 148      #
 149      # methods for to
 150      #
 151  
 152      def check_to(v)
 153        return true unless v
 154        return true if v.size == 0
 155  
 156        if OPAQUE !~ v || /\A#{MAILBOX_REGEXP}*\z/o !~ v
 157          raise InvalidComponentError,
 158            "bad component(expected opaque component): #{v}"
 159        end
 160  
 161        return true
 162      end
 163      private :check_to
 164  
 165      def set_to(v)
 166        @to = v
 167      end
 168      protected :set_to
 169  
 170      def to=(v)
 171        check_to(v)
 172        set_to(v)
 173      end
 174  
 175  =begin
 176  
 177  --- URI::MailTo#headers
 178  
 179  --- URI::MailTo#headers=(v)
 180  
 181  =end
 182  
 183      #
 184      # methods for headers
 185      #
 186  
 187      def check_headers(v)
 188        return true unless v
 189        return true if v.size == 0
 190  
 191        if OPAQUE !~ v || 
 192            /\A(#{HEADER_REGEXP}(?:\&#{HEADER_REGEXP})*)\z/o !~ v
 193          raise InvalidComponentError,
 194            "bad component(expected opaque component): #{v}"
 195        end
 196  
 197        return true
 198      end
 199      private :check_headers
 200  
 201      def set_headers(v)
 202        @headers = []
 203        if v
 204          v.scan(HEADER_REGEXP) do |x|
 205            @headers << x.split(/=/o, 2)
 206          end
 207        end
 208      end
 209      protected :set_headers
 210  
 211      def headers=(v)
 212        check_headers(v)
 213        set_headers(v)
 214      end
 215  
 216      def to_str
 217        @scheme + ':' + 
 218          if @to 
 219            @to
 220          else
 221            ''
 222          end + 
 223          if @headers.size > 0
 224            '?' + @headers.collect{|x| x.join('=')}.join('&')
 225          else
 226            ''
 227          end
 228      end
 229  
 230  =begin
 231  
 232  --- URI::MailTo#to_mailtext
 233  
 234  =end
 235      def to_mailtext
 236        to = URI::unescape(@to)
 237        head = ''
 238        body = ''
 239        @headers.each do |x|
 240          case x[0]
 241          when 'body'
 242            body = URI::unescape(x[1])
 243          when 'to'
 244            to << ', ' + URI::unescape(x[1])
 245          else
 246            head << URI::unescape(x[0]).capitalize + ': ' +
 247              URI::unescape(x[1])  + "\n"
 248          end
 249        end
 250  
 251        return "To: #{to}
 252  #{head}
 253  #{body}
 254  "
 255      end
 256      alias to_rfc822text to_mailtext
 257    end # MailTo
 258  
 259    @@schemes['MAILTO'] = MailTo
 260  end # URI