Class: URI::IMAP

Inherits:
Generic
  • Object
show all
Defined in:
lib/uri/imap.rb,
lib/uri/imap/version.rb

Overview

Class that adds imap(s)-scheme to the standard URI-module.

Defined Under Namespace

Classes: Error

Constant Summary collapse

VERSION =
"0.2.0"

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.parse(uri) ⇒ URI::imap

Parse uri and instantiate instance of URI::imap.

Examples:

URI::imap.parse("imaps+plain://user:pw@foo.org#sender.org")
#=> #<URI::imap imaps+plain://user:pw@foo.org#sender.org>

Returns:

  • (URI::imap)

    URI::imap instance from uri.



224
225
226
# File 'lib/uri/imap.rb', line 224

def self.parse(uri)
  new(*URI.split(uri))
end

Instance Method Details

#authString?

Return mechanism of authentication (default "plain").

Only returns value when imap#userinfo is provided and authentication is not "none".

Authentication can be provided via scheme (e.g. "imap+login://...") or via query-params (e.g. "imap://foo.org?auth=cram-md5"). The latter takes precedence when both are provided. A provided value of "none" results in nil. Other values are returned as is.

Examples:

# no userinfo
URI("imap://foo.org").auth #=> nil

# "none"
URI("imap+none://user@foo.org").auth #=> nil

# default value
URI("imap://user@foo.org").auth #=> "plain"

# query takes precedence
URI("imap+login://user@foo.org?auth=cram-md5").auth #=> "cram-md5"

Returns:

  • (String, nil)

    mechanism of authentication or nil:

  • (nil)

    when there's no userinfo.

  • (nil)

    if 'auth via query' is "none", e.g. "imap://foo.org?auth=none".

  • (String)

    'auth via query' when present.

  • (nil)

    if 'auth via scheme' is "none", e.g. "imap+none://foo.org".

  • (String)

    'auth via scheme' when present, e.g. "imap+login://foo.org".

  • (String)

    else "plain"



46
47
48
49
50
51
52
53
54
55
# File 'lib/uri/imap.rb', line 46

def auth
  # net-imap: passing authtype without user/pw raises error
  return nil unless userinfo
  return nil if parsed_query["auth"] == "none"
  return parsed_query["auth"] if parsed_query.has_key?("auth")
  return nil if scheme_auth == "none"
  return scheme_auth if scheme_auth

  "plain"
end

#decoded_userinfo(format: :string) ⇒ String, ...

Decoded userinfo formatted as String, Array or Hash.

NOTE not provided user or password result in nil (format: :array) or absent keys (format: :hash).

Examples:

no userinfo => nil

URI("imap://foo.org").decoded_userinfo #=> nil
URI("imap://foo.org").decoded_userinfo(format: :array) #=> nil
URI("imap://foo.org").decoded_userinfo(format: :hash) #=> nil

format :array

# absent user/password is `nil`
URI("imap://user@foo.org").decoded_userinfo(format: :array) #=> ["user", nil]
URI("imap://:pw@foo.org").decoded_userinfo(format: :array) #=> [nil, "pw"]
# decoded values
URI("imap://user%40gmail.com:p%40ss@foo.org").decoded_userinfo(format: :array) #=> ["user@gmail.com", "p@ss"]

format :hash

# absent user/password is left out
URI("imap://user%40gmail.com@foo.org").decoded_userinfo(format: :hash) #=> {user: "user@gmail.com"}
URI("imap://:p%40ss@foo.org").decoded_userinfo(format: :hash) #=> {password: "p@ss"}

Parameters:

  • format (Symbol) (defaults to: :string)

    the format type, :string (default), :array or :hash.

Returns:

  • (String, Array, Hash)

    Decoded userinfo formatted as String, Array or Hash.



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/uri/imap.rb', line 80

def decoded_userinfo(format: :string)
  return if userinfo.nil?

  case format
  when :string
    [decoded_user, decoded_password].join(":")
  when :array
    [string_presence(decoded_user), string_presence(decoded_password)]
  when :hash
    {
      user: string_presence(decoded_user),
      password: string_presence(decoded_password)
    }.delete_if { |_k, v| v.nil? }
  else
    raise ArgumentError,
      "Unknown format #{format.inspect}. Should be one of #{%i[string array hash].inspect}."
  end
end

#host_local?Boolean

Whether or not host is considered local.

Hostnames that are considered local have certain defaults (i.e. port 25 and no STARTTLS).

Examples:

# Point to mailcatcher (https://github.com/sj26/mailcatcher)
URI("imap://127.0.0.1:1025").host_local? #=> true

URI("imap://localhost").host_local? #=> true

Returns:

  • (Boolean)

    whether or not host is considered local.



161
162
163
# File 'lib/uri/imap.rb', line 161

def host_local?
  %w[127.0.0.1 localhost].include?(host)
end

#idle_timeoutInteger

Returns:

  • (Integer)


100
101
102
# File 'lib/uri/imap.rb', line 100

def idle_timeout
  parsed_query["idle_timeout"]
end

#insecure?Boolean

Whether or not the scheme indicates to skip STARTTLS.

Examples:

URI("imap+insecure://foo.org").insecure? #=> true
# This is equivalent (though shorter and more descriptive) to
URI("imap://foo.org?starttls=false")

# combine with authentication
URI("imap+insecure+login://user:pw@foo.org").insecure? #=> true

Returns:

  • (Boolean)

    whether scheme starts with "imap+insecure".

See Also:



148
149
150
# File 'lib/uri/imap.rb', line 148

def insecure?
  scheme.start_with?("imap+insecure")
end

#open_timeoutInteger

Returns:

  • (Integer)


105
106
107
# File 'lib/uri/imap.rb', line 105

def open_timeout
  parsed_query["open_timeout"]
end

#parsed_queryHash

query as Hash with values starttls, idle_timeout and open_timeout coerced.

Returns:

  • (Hash)

    query parsed.



167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/uri/imap.rb', line 167

def parsed_query
  @parsed_query ||= URI.decode_www_form(query.to_s).to_h
    .delete_if { |_k, v| !string_presence(v) }
    .tap do
    _1["idle_timeout"] &&= _1["idle_timeout"].to_i
    _1["open_timeout"] &&= _1["open_timeout"].to_i
    _1["starttls"] &&= case _1["starttls"]
    when "always", "auto" then _1["starttls"].to_sym
    when "false" then false
    else
      :always
    end
  end
end

#portInteger

Returns:

  • (Integer)


13
14
15
16
17
18
# File 'lib/uri/imap.rb', line 13

def port
  return @port if @port
  return 993 if tls?

  143
end

#starttlsfalse, ...

Whether or not to use STARTTLS.

The possible return values (i.e. :always, :auto and false) map to what net-imap uses:

  • :always use STARTTLS or disconnect when server does not support it.
  • :auto use STARTTLS when supported, otherwise continue unencrypted.
  • false don't use STARTTLS.

Returns:

  • (false)

    when tls?.

  • (:always, :auto, false)

    when query-key starttls is present, e.g. "imap://foo.org?starttls=auto".

  • (false)

    when host_local? (the host is considered one for local development).

  • (false)

    when insecure? (i.e. scheme starts with "imap+insecure").

  • (:always)

    otherwise.



121
122
123
124
125
126
127
128
# File 'lib/uri/imap.rb', line 121

def starttls
  return false if tls?
  return parsed_query["starttls"] if parsed_query.has_key?("starttls")
  return false if host_local?
  return false if insecure?

  :always
end

#tlsBoolean Also known as: tls?

Returns whether or not scheme starts with "imaps".

Returns:

  • (Boolean)

    whether or not scheme starts with "imaps".



131
132
133
# File 'lib/uri/imap.rb', line 131

def tls
  !!scheme[/^imaps/]
end

#to_hHash

Return Hash representing the URI.

format should be one of: nil or :action_mailer (or :am).

Format :action_mailer matches how ActionMailer should be configured and works around some quirks in Mail v2.8.1.

NOTE keys with nil-values are stripped.

Examples:

default format

URI("imaps+login://user%40gmail.com:p%40ss@imap.gmail.com#sender.org").to_h
# =>
# {auth: "login",
#  host: "imap.gmail.com",
#  port: 465,
#  scheme: "imaps+login",
#  starttls: false,
#  tls: true,
#  user: "user@gmail.com",
#  password: "p@ss"}

Returns:

  • (Hash)


201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/uri/imap.rb', line 201

def to_h
  {
    auth:,
    host:,
    idle_timeout:,
    open_timeout:,
    port:,
    scheme:,
    starttls:,
    tls:
  }.tap do
    unless _1[:auth].nil?
      _1[:user] = decoded_user
      _1[:password] = decoded_password
    end
  end.delete_if { |_k, v| v.nil? }
end