summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntonio Terceiro <terceiro@softwarelivre.org>2013-08-25 19:30:41 -0300
committerAntonio Terceiro <terceiro@softwarelivre.org>2013-08-25 19:30:41 -0300
commit64455d1615ee34e03166b106f1ac33b3179fef75 (patch)
treebd60a79482d7dd997c97ecf05cf2c93005a081c4
parent0745437cd1d3109463405f2083454a0782ff2ff4 (diff)
downloadfeed2imap-64455d1615ee34e03166b106f1ac33b3179fef75.tar.gz
feed2imap-64455d1615ee34e03166b106f1ac33b3179fef75.tar.bz2
feed2imap-64455d1615ee34e03166b106f1ac33b3179fef75.zip
Remove embedded copy of Net::IMAP
This was actually causing problems to read IMAP data back.
-rw-r--r--lib/feed2imap/imap.rb2
-rw-r--r--lib/feed2imap/rubyimap.rb3601
2 files changed, 1 insertions, 3602 deletions
diff --git a/lib/feed2imap/imap.rb b/lib/feed2imap/imap.rb
index 4c54456..2e796f6 100644
--- a/lib/feed2imap/imap.rb
+++ b/lib/feed2imap/imap.rb
@@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
=end
# Imap connection handling
-require 'feed2imap/rubyimap'
+require 'net/imap'
begin
require 'openssl'
rescue LoadError
diff --git a/lib/feed2imap/rubyimap.rb b/lib/feed2imap/rubyimap.rb
deleted file mode 100644
index 43af035..0000000
--- a/lib/feed2imap/rubyimap.rb
+++ /dev/null
@@ -1,3601 +0,0 @@
-# File fetched from
-# http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/net/imap.rb?view=log
-# Current rev: 27336
-############################################################################
-#
-# = net/imap.rb
-#
-# Copyright (C) 2000 Shugo Maeda <shugo@ruby-lang.org>
-#
-# This library is distributed under the terms of the Ruby license.
-# You can freely distribute/modify this library.
-#
-# Documentation: Shugo Maeda, with RDoc conversion and overview by William
-# Webber.
-#
-# See Net::IMAP for documentation.
-#
-
-
-require "socket"
-require "monitor"
-require "digest/md5"
-require "strscan"
-begin
- require "openssl"
-rescue LoadError
-end
-
-module Net
-
- #
- # Net::IMAP implements Internet Message Access Protocol (IMAP) client
- # functionality. The protocol is described in [IMAP].
- #
- # == IMAP Overview
- #
- # An IMAP client connects to a server, and then authenticates
- # itself using either #authenticate() or #login(). Having
- # authenticated itself, there is a range of commands
- # available to it. Most work with mailboxes, which may be
- # arranged in an hierarchical namespace, and each of which
- # contains zero or more messages. How this is implemented on
- # the server is implementation-dependent; on a UNIX server, it
- # will frequently be implemented as a files in mailbox format
- # within a hierarchy of directories.
- #
- # To work on the messages within a mailbox, the client must
- # first select that mailbox, using either #select() or (for
- # read-only access) #examine(). Once the client has successfully
- # selected a mailbox, they enter _selected_ state, and that
- # mailbox becomes the _current_ mailbox, on which mail-item
- # related commands implicitly operate.
- #
- # Messages have two sorts of identifiers: message sequence
- # numbers, and UIDs.
- #
- # Message sequence numbers number messages within a mail box
- # from 1 up to the number of items in the mail box. If new
- # message arrives during a session, it receives a sequence
- # number equal to the new size of the mail box. If messages
- # are expunged from the mailbox, remaining messages have their
- # sequence numbers "shuffled down" to fill the gaps.
- #
- # UIDs, on the other hand, are permanently guaranteed not to
- # identify another message within the same mailbox, even if
- # the existing message is deleted. UIDs are required to
- # be assigned in ascending (but not necessarily sequential)
- # order within a mailbox; this means that if a non-IMAP client
- # rearranges the order of mailitems within a mailbox, the
- # UIDs have to be reassigned. An IMAP client cannot thus
- # rearrange message orders.
- #
- # == Examples of Usage
- #
- # === List sender and subject of all recent messages in the default mailbox
- #
- # imap = Net::IMAP.new('mail.example.com')
- # imap.authenticate('LOGIN', 'joe_user', 'joes_password')
- # imap.examine('INBOX')
- # imap.search(["RECENT"]).each do |message_id|
- # envelope = imap.fetch(message_id, "ENVELOPE")[0].attr["ENVELOPE"]
- # puts "#{envelope.from[0].name}: \t#{envelope.subject}"
- # end
- #
- # === Move all messages from April 2003 from "Mail/sent-mail" to "Mail/sent-apr03"
- #
- # imap = Net::IMAP.new('mail.example.com')
- # imap.authenticate('LOGIN', 'joe_user', 'joes_password')
- # imap.select('Mail/sent-mail')
- # if not imap.list('Mail/', 'sent-apr03')
- # imap.create('Mail/sent-apr03')
- # end
- # imap.search(["BEFORE", "30-Apr-2003", "SINCE", "1-Apr-2003"]).each do |message_id|
- # imap.copy(message_id, "Mail/sent-apr03")
- # imap.store(message_id, "+FLAGS", [:Deleted])
- # end
- # imap.expunge
- #
- # == Thread Safety
- #
- # Net::IMAP supports concurrent threads. For example,
- #
- # imap = Net::IMAP.new("imap.foo.net", "imap2")
- # imap.authenticate("cram-md5", "bar", "password")
- # imap.select("inbox")
- # fetch_thread = Thread.start { imap.fetch(1..-1, "UID") }
- # search_result = imap.search(["BODY", "hello"])
- # fetch_result = fetch_thread.value
- # imap.disconnect
- #
- # This script invokes the FETCH command and the SEARCH command concurrently.
- #
- # == Errors
- #
- # An IMAP server can send three different types of responses to indicate
- # failure:
- #
- # NO:: the attempted command could not be successfully completed. For
- # instance, the username/password used for logging in are incorrect;
- # the selected mailbox does not exists; etc.
- #
- # BAD:: the request from the client does not follow the server's
- # understanding of the IMAP protocol. This includes attempting
- # commands from the wrong client state; for instance, attempting
- # to perform a SEARCH command without having SELECTed a current
- # mailbox. It can also signal an internal server
- # failure (such as a disk crash) has occurred.
- #
- # BYE:: the server is saying goodbye. This can be part of a normal
- # logout sequence, and can be used as part of a login sequence
- # to indicate that the server is (for some reason) unwilling
- # to accept our connection. As a response to any other command,
- # it indicates either that the server is shutting down, or that
- # the server is timing out the client connection due to inactivity.
- #
- # These three error response are represented by the errors
- # Net::IMAP::NoResponseError, Net::IMAP::BadResponseError, and
- # Net::IMAP::ByeResponseError, all of which are subclasses of
- # Net::IMAP::ResponseError. Essentially, all methods that involve
- # sending a request to the server can generate one of these errors.
- # Only the most pertinent instances have been documented below.
- #
- # Because the IMAP class uses Sockets for communication, its methods
- # are also susceptible to the various errors that can occur when
- # working with sockets. These are generally represented as
- # Errno errors. For instance, any method that involves sending a
- # request to the server and/or receiving a response from it could
- # raise an Errno::EPIPE error if the network connection unexpectedly
- # goes down. See the socket(7), ip(7), tcp(7), socket(2), connect(2),
- # and associated man pages.
- #
- # Finally, a Net::IMAP::DataFormatError is thrown if low-level data
- # is found to be in an incorrect format (for instance, when converting
- # between UTF-8 and UTF-16), and Net::IMAP::ResponseParseError is
- # thrown if a server response is non-parseable.
- #
- #
- # == References
- #
- # [[IMAP]]
- # M. Crispin, "INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1",
- # RFC 2060, December 1996. (Note: since obsoleted by RFC 3501)
- #
- # [[LANGUAGE-TAGS]]
- # Alvestrand, H., "Tags for the Identification of
- # Languages", RFC 1766, March 1995.
- #
- # [[MD5]]
- # Myers, J., and M. Rose, "The Content-MD5 Header Field", RFC
- # 1864, October 1995.
- #
- # [[MIME-IMB]]
- # Freed, N., and N. Borenstein, "MIME (Multipurpose Internet
- # Mail Extensions) Part One: Format of Internet Message Bodies", RFC
- # 2045, November 1996.
- #
- # [[RFC-822]]
- # Crocker, D., "Standard for the Format of ARPA Internet Text
- # Messages", STD 11, RFC 822, University of Delaware, August 1982.
- #
- # [[RFC-2087]]
- # Myers, J., "IMAP4 QUOTA extension", RFC 2087, January 1997.
- #
- # [[RFC-2086]]
- # Myers, J., "IMAP4 ACL extension", RFC 2086, January 1997.
- #
- # [[RFC-2195]]
- # Klensin, J., Catoe, R., and Krumviede, P., "IMAP/POP AUTHorize Extension
- # for Simple Challenge/Response", RFC 2195, September 1997.
- #
- # [[SORT-THREAD-EXT]]
- # Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - SORT and THREAD
- # Extensions", draft-ietf-imapext-sort, May 2003.
- #
- # [[OSSL]]
- # http://www.openssl.org
- #
- # [[RSSL]]
- # http://savannah.gnu.org/projects/rubypki
- #
- # [[UTF7]]
- # Goldsmith, D. and Davis, M., "UTF-7: A Mail-Safe Transformation Format of
- # Unicode", RFC 2152, May 1997.
- #
- class IMAP
- include MonitorMixin
- if defined?(OpenSSL)
- include OpenSSL
- include SSL
- end
-
- # Returns an initial greeting response from the server.
- attr_reader :greeting
-
- # Returns recorded untagged responses. For example:
- #
- # imap.select("inbox")
- # p imap.responses["EXISTS"][-1]
- # #=> 2
- # p imap.responses["UIDVALIDITY"][-1]
- # #=> 968263756
- attr_reader :responses
-
- # Returns all response handlers.
- attr_reader :response_handlers
-
- # The thread to receive exceptions.
- attr_accessor :client_thread
-
- # Flag indicating a message has been seen
- SEEN = :Seen
-
- # Flag indicating a message has been answered
- ANSWERED = :Answered
-
- # Flag indicating a message has been flagged for special or urgent
- # attention
- FLAGGED = :Flagged
-
- # Flag indicating a message has been marked for deletion. This
- # will occur when the mailbox is closed or expunged.
- DELETED = :Deleted
-
- # Flag indicating a message is only a draft or work-in-progress version.
- DRAFT = :Draft
-
- # Flag indicating that the message is "recent", meaning that this
- # session is the first session in which the client has been notified
- # of this message.
- RECENT = :Recent
-
- # Flag indicating that a mailbox context name cannot contain
- # children.
- NOINFERIORS = :Noinferiors
-
- # Flag indicating that a mailbox is not selected.
- NOSELECT = :Noselect
-
- # Flag indicating that a mailbox has been marked "interesting" by
- # the server; this commonly indicates that the mailbox contains
- # new messages.
- MARKED = :Marked
-
- # Flag indicating that the mailbox does not contains new messages.
- UNMARKED = :Unmarked
-
- # Returns the debug mode.
- def self.debug
- return @@debug
- end
-
- # Sets the debug mode.
- def self.debug=(val)
- return @@debug = val
- end
-
- # Returns the max number of flags interned to symbols.
- def self.max_flag_count
- return @@max_flag_count
- end
-
- # Sets the max number of flags interned to symbols.
- def self.max_flag_count=(count)
- @@max_flag_count = count
- end
-
- # Adds an authenticator for Net::IMAP#authenticate. +auth_type+
- # is the type of authentication this authenticator supports
- # (for instance, "LOGIN"). The +authenticator+ is an object
- # which defines a process() method to handle authentication with
- # the server. See Net::IMAP::LoginAuthenticator,
- # Net::IMAP::CramMD5Authenticator, and Net::IMAP::DigestMD5Authenticator
- # for examples.
- #
- #
- # If +auth_type+ refers to an existing authenticator, it will be
- # replaced by the new one.
- def self.add_authenticator(auth_type, authenticator)
- @@authenticators[auth_type] = authenticator
- end
-
- # Disconnects from the server.
- def disconnect
- begin
- begin
- # try to call SSL::SSLSocket#io.
- @sock.io.shutdown
- rescue NoMethodError
- # @sock is not an SSL::SSLSocket.
- @sock.shutdown
- end
- rescue Errno::ENOTCONN
- # ignore `Errno::ENOTCONN: Socket is not connected' on some platforms.
- end
- @receiver_thread.join
- @sock.close
- end
-
- # Returns true if disconnected from the server.
- def disconnected?
- return @sock.closed?
- end
-
- # Sends a CAPABILITY command, and returns an array of
- # capabilities that the server supports. Each capability
- # is a string. See [IMAP] for a list of possible
- # capabilities.
- #
- # Note that the Net::IMAP class does not modify its
- # behaviour according to the capabilities of the server;
- # it is up to the user of the class to ensure that
- # a certain capability is supported by a server before
- # using it.
- def capability
- synchronize do
- send_command("CAPABILITY")
- return @responses.delete("CAPABILITY")[-1]
- end
- end
-
- # Sends a NOOP command to the server. It does nothing.
- def noop
- send_command("NOOP")
- end
-
- # Sends a LOGOUT command to inform the server that the client is
- # done with the connection.
- def logout
- send_command("LOGOUT")
- end
-
- # Sends a STARTTLS command to start TLS session.
- def starttls(options = {}, verify = true)
- send_command("STARTTLS") do |resp|
- if resp.kind_of?(TaggedResponse) && resp.name == "OK"
- begin
- # for backward compatibility
- certs = options.to_str
- options = create_ssl_params(certs, verify)
- rescue NoMethodError
- end
- start_tls_session(options)
- end
- end
- end
-
- # Sends an AUTHENTICATE command to authenticate the client.
- # The +auth_type+ parameter is a string that represents
- # the authentication mechanism to be used. Currently Net::IMAP
- # supports authentication mechanisms:
- #
- # LOGIN:: login using cleartext user and password.
- # CRAM-MD5:: login with cleartext user and encrypted password
- # (see [RFC-2195] for a full description). This
- # mechanism requires that the server have the user's
- # password stored in clear-text password.
- #
- # For both these mechanisms, there should be two +args+: username
- # and (cleartext) password. A server may not support one or other
- # of these mechanisms; check #capability() for a capability of
- # the form "AUTH=LOGIN" or "AUTH=CRAM-MD5".
- #
- # Authentication is done using the appropriate authenticator object:
- # see @@authenticators for more information on plugging in your own
- # authenticator.
- #
- # For example:
- #
- # imap.authenticate('LOGIN', user, password)
- #
- # A Net::IMAP::NoResponseError is raised if authentication fails.
- def authenticate(auth_type, *args)
- auth_type = auth_type.upcase
- unless @@authenticators.has_key?(auth_type)
- raise ArgumentError,
- format('unknown auth type - "%s"', auth_type)
- end
- authenticator = @@authenticators[auth_type].new(*args)
- send_command("AUTHENTICATE", auth_type) do |resp|
- if resp.instance_of?(ContinuationRequest)
- data = authenticator.process(resp.data.text.unpack("m")[0])
- s = [data].pack("m").gsub(/\n/, "")
- send_string_data(s)
- put_string(CRLF)
- end
- end
- end
-
- # Sends a LOGIN command to identify the client and carries
- # the plaintext +password+ authenticating this +user+. Note
- # that, unlike calling #authenticate() with an +auth_type+
- # of "LOGIN", #login() does *not* use the login authenticator.
- #
- # A Net::IMAP::NoResponseError is raised if authentication fails.
- def login(user, password)
- send_command("LOGIN", user, password)
- end
-
- # Sends a SELECT command to select a +mailbox+ so that messages
- # in the +mailbox+ can be accessed.
- #
- # After you have selected a mailbox, you may retrieve the
- # number of items in that mailbox from @responses["EXISTS"][-1],
- # and the number of recent messages from @responses["RECENT"][-1].
- # Note that these values can change if new messages arrive
- # during a session; see #add_response_handler() for a way of
- # detecting this event.
- #
- # A Net::IMAP::NoResponseError is raised if the mailbox does not
- # exist or is for some reason non-selectable.
- def select(mailbox)
- synchronize do
- @responses.clear
- send_command("SELECT", mailbox)
- end
- end
-
- # Sends a EXAMINE command to select a +mailbox+ so that messages
- # in the +mailbox+ can be accessed. Behaves the same as #select(),
- # except that the selected +mailbox+ is identified as read-only.
- #
- # A Net::IMAP::NoResponseError is raised if the mailbox does not
- # exist or is for some reason non-examinable.
- def examine(mailbox)
- synchronize do
- @responses.clear
- send_command("EXAMINE", mailbox)
- end
- end
-
- # Sends a CREATE command to create a new +mailbox+.
- #
- # A Net::IMAP::NoResponseError is raised if a mailbox with that name
- # cannot be created.
- def create(mailbox)
- send_command("CREATE", mailbox)
- end
-
- # Sends a DELETE command to remove the +mailbox+.
- #
- # A Net::IMAP::NoResponseError is raised if a mailbox with that name
- # cannot be deleted, either because it does not exist or because the
- # client does not have permission to delete it.
- def delete(mailbox)
- send_command("DELETE", mailbox)
- end
-
- # Sends a RENAME command to change the name of the +mailbox+ to
- # +newname+.
- #
- # A Net::IMAP::NoResponseError is raised if a mailbox with the
- # name +mailbox+ cannot be renamed to +newname+ for whatever
- # reason; for instance, because +mailbox+ does not exist, or
- # because there is already a mailbox with the name +newname+.
- def rename(mailbox, newname)
- send_command("RENAME", mailbox, newname)
- end
-
- # Sends a SUBSCRIBE command to add the specified +mailbox+ name to
- # the server's set of "active" or "subscribed" mailboxes as returned
- # by #lsub().
- #
- # A Net::IMAP::NoResponseError is raised if +mailbox+ cannot be
- # subscribed to, for instance because it does not exist.
- def subscribe(mailbox)
- send_command("SUBSCRIBE", mailbox)
- end
-
- # Sends a UNSUBSCRIBE command to remove the specified +mailbox+ name
- # from the server's set of "active" or "subscribed" mailboxes.
- #
- # A Net::IMAP::NoResponseError is raised if +mailbox+ cannot be
- # unsubscribed from, for instance because the client is not currently
- # subscribed to it.
- def unsubscribe(mailbox)
- send_command("UNSUBSCRIBE", mailbox)
- end
-
- # Sends a LIST command, and returns a subset of names from
- # the complete set of all names available to the client.
- # +refname+ provides a context (for instance, a base directory
- # in a directory-based mailbox hierarchy). +mailbox+ specifies
- # a mailbox or (via wildcards) mailboxes under that context.
- # Two wildcards may be used in +mailbox+: '*', which matches
- # all characters *including* the hierarchy delimiter (for instance,
- # '/' on a UNIX-hosted directory-based mailbox hierarchy); and '%',
- # which matches all characters *except* the hierarchy delimiter.
- #
- # If +refname+ is empty, +mailbox+ is used directly to determine
- # which mailboxes to match. If +mailbox+ is empty, the root
- # name of +refname+ and the hierarchy delimiter are returned.
- #
- # The return value is an array of +Net::IMAP::MailboxList+. For example:
- #
- # imap.create("foo/bar")
- # imap.create("foo/baz")
- # p imap.list("", "foo/%")
- # #=> [#<Net::IMAP::MailboxList attr=[:Noselect], delim="/", name="foo/">, \\
- # #<Net::IMAP::MailboxList attr=[:Noinferiors, :Marked], delim="/", name="foo/bar">, \\
- # #<Net::IMAP::MailboxList attr=[:Noinferiors], delim="/", name="foo/baz">]
- def list(refname, mailbox)
- synchronize do
- send_command("LIST", refname, mailbox)
- return @responses.delete("LIST")
- end
- end
-
- # Sends the GETQUOTAROOT command along with specified +mailbox+.
- # This command is generally available to both admin and user.
- # If mailbox exists, returns an array containing objects of
- # Net::IMAP::MailboxQuotaRoot and Net::IMAP::MailboxQuota.
- def getquotaroot(mailbox)
- synchronize do
- send_command("GETQUOTAROOT", mailbox)
- result = []
- result.concat(@responses.delete("QUOTAROOT"))
- result.concat(@responses.delete("QUOTA"))
- return result
- end
- end
-
- # Sends the GETQUOTA command along with specified +mailbox+.
- # If this mailbox exists, then an array containing a
- # Net::IMAP::MailboxQuota object is returned. This
- # command generally is only available to server admin.
- def getquota(mailbox)
- synchronize do
- send_command("GETQUOTA", mailbox)
- return @responses.delete("QUOTA")
- end
- end
-
- # Sends a SETQUOTA command along with the specified +mailbox+ and
- # +quota+. If +quota+ is nil, then quota will be unset for that
- # mailbox. Typically one needs to be logged in as server admin
- # for this to work. The IMAP quota commands are described in
- # [RFC-2087].
- def setquota(mailbox, quota)
- if quota.nil?
- data = '()'
- else
- data = '(STORAGE ' + quota.to_s + ')'
- end
- send_command("SETQUOTA", mailbox, RawData.new(data))
- end
-
- # Sends the SETACL command along with +mailbox+, +user+ and the
- # +rights+ that user is to have on that mailbox. If +rights+ is nil,
- # then that user will be stripped of any rights to that mailbox.
- # The IMAP ACL commands are described in [RFC-2086].
- def setacl(mailbox, user, rights)
- if rights.nil?
- send_command("SETACL", mailbox, user, "")
- else
- send_command("SETACL", mailbox, user, rights)
- end
- end
-
- # Send the GETACL command along with specified +mailbox+.
- # If this mailbox exists, an array containing objects of
- # Net::IMAP::MailboxACLItem will be returned.
- def getacl(mailbox)
- synchronize do
- send_command("GETACL", mailbox)
- return @responses.delete("ACL")[-1]
- end
- end
-
- # Sends a LSUB command, and returns a subset of names from the set
- # of names that the user has declared as being "active" or
- # "subscribed". +refname+ and +mailbox+ are interpreted as
- # for #list().
- # The return value is an array of +Net::IMAP::MailboxList+.
- def lsub(refname, mailbox)
- synchronize do
- send_command("LSUB", refname, mailbox)
- return @responses.delete("LSUB")
- end
- end
-
- # Sends a STATUS command, and returns the status of the indicated
- # +mailbox+. +attr+ is a list of one or more attributes that
- # we are request the status of. Supported attributes include:
- #
- # MESSAGES:: the number of messages in the mailbox.
- # RECENT:: the number of recent messages in the mailbox.
- # UNSEEN:: the number of unseen messages in the mailbox.
- #
- # The return value is a hash of attributes. For example:
- #
- # p imap.status("inbox", ["MESSAGES", "RECENT"])
- # #=> {"RECENT"=>0, "MESSAGES"=>44}
- #
- # A Net::IMAP::NoResponseError is raised if status values
- # for +mailbox+ cannot be returned, for instance because it
- # does not exist.
- def status(mailbox, attr)
- synchronize do
- send_command("STATUS", mailbox, attr)
- return @responses.delete("STATUS")[-1].attr
- end
- end
-
- # Sends a APPEND command to append the +message+ to the end of
- # the +mailbox+. The optional +flags+ argument is an array of
- # flags to initially passing to the new message. The optional
- # +date_time+ argument specifies the creation time to assign to the
- # new message; it defaults to the current time.
- # For example:
- #
- # imap.append("inbox", <<EOF.gsub(/\n/, "\r\n"), [:Seen], Time.now)
- # Subject: hello
- # From: shugo@ruby-lang.org
- # To: shugo@ruby-lang.org
- #
- # hello world
- # EOF
- #
- # A Net::IMAP::NoResponseError is raised if the mailbox does
- # not exist (it is not created automatically), or if the flags,
- # date_time, or message arguments contain errors.
- def append(mailbox, message, flags = nil, date_time = nil)
- args = []
- if flags
- args.push(flags)
- end
- args.push(date_time) if date_time
- args.push(Literal.new(message))
- send_command("APPEND", mailbox, *args)
- end
-
- # Sends a CHECK command to request a checkpoint of the currently
- # selected mailbox. This performs implementation-specific
- # housekeeping, for instance, reconciling the mailbox's
- # in-memory and on-disk state.
- def check
- send_command("CHECK")
- end
-
- # Sends a CLOSE command to close the currently selected mailbox.
- # The CLOSE command permanently removes from the mailbox all
- # messages that have the \Deleted flag set.
- def close
- send_command("CLOSE")
- end
-
- # Sends a EXPUNGE command to permanently remove from the currently
- # selected mailbox all messages that have the \Deleted flag set.
- def expunge
- synchronize do
- send_command("EXPUNGE")
- return @responses.delete("EXPUNGE")
- end
- end
-
- # Sends a SEARCH command to search the mailbox for messages that
- # match the given searching criteria, and returns message sequence
- # numbers. +keys+ can either be a string holding the entire
- # search string, or a single-dimension array of search keywords and
- # arguments. The following are some common search criteria;
- # see [IMAP] section 6.4.4 for a full list.
- #
- # <message set>:: a set of message sequence numbers. ',' indicates
- # an interval, ':' indicates a range. For instance,
- # '2,10:12,15' means "2,10,11,12,15".
- #
- # BEFORE <date>:: messages with an internal date strictly before
- # <date>. The date argument has a format similar
- # to 8-Aug-2002.
- #
- # BODY <string>:: messages that contain <string> within their body.
- #
- # CC <string>:: messages containing <string> in their CC field.
- #
- # FROM <string>:: messages that contain <string> in their FROM field.
- #
- # NEW:: messages with the \Recent, but not the \Seen, flag set.
- #
- # NOT <search-key>:: negate the following search key.
- #
- # OR <search-key> <search-key>:: "or" two search keys together.
- #
- # ON <date>:: messages with an internal date exactly equal to <date>,
- # which has a format similar to 8-Aug-2002.
- #
- # SINCE <date>:: messages with an internal date on or after <date>.
- #
- # SUBJECT <string>:: messages with <string> in their subject.
- #
- # TO <string>:: messages with <string> in their TO field.
- #
- # For example:
- #
- # p imap.search(["SUBJECT", "hello", "NOT", "NEW"])
- # #=> [1, 6, 7, 8]
- def search(keys, charset = nil)
- return search_internal("SEARCH", keys, charset)
- end
-
- # As for #search(), but returns unique identifiers.
- def uid_search(keys, charset = nil)
- return search_internal("UID SEARCH", keys, charset)
- end
-
- # Sends a FETCH command to retrieve data associated with a message
- # in the mailbox. The +set+ parameter is a number or an array of
- # numbers or a Range object. The number is a message sequence
- # number. +attr+ is a list of attributes to fetch; see the
- # documentation for Net::IMAP::FetchData for a list of valid
- # attributes.
- # The return value is an array of Net::IMAP::FetchData. For example:
- #
- # p imap.fetch(6..8, "UID")
- # #=> [#<Net::IMAP::FetchData seqno=6, attr={"UID"=>98}>, \\
- # #<Net::IMAP::FetchData seqno=7, attr={"UID"=>99}>, \\
- # #<Net::IMAP::FetchData seqno=8, attr={"UID"=>100}>]
- # p imap.fetch(6, "BODY[HEADER.FIELDS (SUBJECT)]")
- # #=> [#<Net::IMAP::FetchData seqno=6, attr={"BODY[HEADER.FIELDS (SUBJECT)]"=>"Subject: test\r\n\r\n"}>]
- # data = imap.uid_fetch(98, ["RFC822.SIZE", "INTERNALDATE"])[0]
- # p data.seqno
- # #=> 6
- # p data.attr["RFC822.SIZE"]
- # #=> 611
- # p data.attr["INTERNALDATE"]
- # #=> "12-Oct-2000 22:40:59 +0900"
- # p data.attr["UID"]
- # #=> 98
- def fetch(set, attr)
- return fetch_internal("FETCH", set, attr)
- end
-
- # As for #fetch(), but +set+ contains unique identifiers.
- def uid_fetch(set, attr)
- return fetch_internal("UID FETCH", set, attr)
- end
-
- # Sends a STORE command to alter data associated with messages
- # in the mailbox, in particular their flags. The +set+ parameter
- # is a number or an array of numbers or a Range object. Each number
- # is a message sequence number. +attr+ is the name of a data item
- # to store: 'FLAGS' means to replace the message's flag list
- # with the provided one; '+FLAGS' means to add the provided flags;
- # and '-FLAGS' means to remove them. +flags+ is a list of flags.
- #
- # The return value is an array of Net::IMAP::FetchData. For example:
- #
- # p imap.store(6..8, "+FLAGS", [:Deleted])
- # #=> [#<Net::IMAP::FetchData seqno=6, attr={"FLAGS"=>[:Seen, :Deleted]}>, \\
- # #<Net::IMAP::FetchData seqno=7, attr={"FLAGS"=>[:Seen, :Deleted]}>, \\
- # #<Net::IMAP::FetchData seqno=8, attr={"FLAGS"=>[:Seen, :Deleted]}>]
- def store(set, attr, flags)
- return store_internal("STORE", set, attr, flags)
- end
-
- # As for #store(), but +set+ contains unique identifiers.
- def uid_store(set, attr, flags)
- return store_internal("UID STORE", set, attr, flags)
- end
-
- # Sends a COPY command to copy the specified message(s) to the end
- # of the specified destination +mailbox+. The +set+ parameter is
- # a number or an array of numbers or a Range object. The number is
- # a message sequence number.
- def copy(set, mailbox)
- copy_internal("COPY", set, mailbox)
- end
-
- # As for #copy(), but +set+ contains unique identifiers.
- def uid_copy(set, mailbox)
- copy_internal("UID COPY", set, mailbox)
- end
-
- # Sends a SORT command to sort messages in the mailbox.
- # Returns an array of message sequence numbers. For example:
- #
- # p imap.sort(["FROM"], ["ALL"], "US-ASCII")
- # #=> [1, 2, 3, 5, 6, 7, 8, 4, 9]
- # p imap.sort(["DATE"], ["SUBJECT", "hello"], "US-ASCII")
- # #=> [6, 7, 8, 1]
- #
- # See [SORT-THREAD-EXT] for more details.
- def sort(sort_keys, search_keys, charset)
- return sort_internal("SORT", sort_keys, search_keys, charset)
- end
-
- # As for #sort(), but returns an array of unique identifiers.
- def uid_sort(sort_keys, search_keys, charset)
- return sort_internal("UID SORT", sort_keys, search_keys, charset)
- end
-
- # Adds a response handler. For example, to detect when
- # the server sends us a new EXISTS response (which normally
- # indicates new messages being added to the mail box),
- # you could add the following handler after selecting the
- # mailbox.
- #
- # imap.add_response_handler { |resp|
- # if resp.kind_of?(Net::IMAP::UntaggedResponse) and resp.name == "EXISTS"
- # puts "Mailbox now has #{resp.data} messages"
- # end
- # }
- #
- def add_response_handler(handler = Proc.new)
- @response_handlers.push(handler)
- end
-
- # Removes the response handler.
- def remove_response_handler(handler)
- @response_handlers.delete(handler)
- end
-
- # As for #search(), but returns message sequence numbers in threaded
- # format, as a Net::IMAP::ThreadMember tree. The supported algorithms
- # are:
- #
- # ORDEREDSUBJECT:: split into single-level threads according to subject,
- # ordered by date.
- # REFERENCES:: split into threads by parent/child relationships determined
- # by which message is a reply to which.
- #
- # Unlike #search(), +charset+ is a required argument. US-ASCII
- # and UTF-8 are sample values.
- #
- # See [SORT-THREAD-EXT] for more details.
- def thread(algorithm, search_keys, charset)
- return thread_internal("THREAD", algorithm, search_keys, charset)
- end
-
- # As for #thread(), but returns unique identifiers instead of
- # message sequence numbers.
- def uid_thread(algorithm, search_keys, charset)
- return thread_internal("UID THREAD", algorithm, search_keys, charset)
- end
-
- # Sends an IDLE command that waits for notifications of new or expunged
- # messages. Yields responses from the server during the IDLE.
- #
- # Use #idle_done() to leave IDLE.
- def idle(&response_handler)
- raise LocalJumpError, "no block given" unless response_handler
-
- response = nil
-
- synchronize do
- tag = Thread.current[:net_imap_tag] = generate_tag
- put_string("#{tag} IDLE#{CRLF}")
-
- begin
- add_response_handler(response_handler)
- @idle_done_cond = new_cond
- @idle_done_cond.wait
- @idle_done_cond = nil
- ensure
- remove_response_handler(response_handler)
- put_string("DONE#{CRLF}")
- response = get_tagged_response(tag, "IDLE")
- end
- end
-
- return response
- end
-
- # Leaves IDLE.
- def idle_done
- synchronize do
- if @idle_done_cond.nil?
- raise Net::IMAP::Error, "not during IDLE"
- end
- @idle_done_cond.signal
- end
- end
-
- # Decode a string from modified UTF-7 format to UTF-8.
- #
- # UTF-7 is a 7-bit encoding of Unicode [UTF7]. IMAP uses a
- # slightly modified version of this to encode mailbox names
- # containing non-ASCII characters; see [IMAP] section 5.1.3.
- #
- # Net::IMAP does _not_ automatically encode and decode
- # mailbox names to and from utf7.
- def self.decode_utf7(s)
- return s.gsub(/&(.*?)-/n) {
- if $1.empty?
- "&"
- else
- base64 = $1.tr(",", "/")
- x = base64.length % 4
- if x > 0
- base64.concat("=" * (4 - x))
- end
- base64.unpack("m")[0].unpack("n*").pack("U*")
- end
- }.force_encoding("UTF-8")
- end
-
- # Encode a string from UTF-8 format to modified UTF-7.
- def self.encode_utf7(s)
- return s.gsub(/(&)|([^\x20-\x7e]+)/u) {
- if $1
- "&-"
- else
- base64 = [$&.unpack("U*").pack("n*")].pack("m")
- "&" + base64.delete("=\n").tr("/", ",") + "-"
- end
- }.force_encoding("ASCII-8BIT")
- end
-
- # Formats +time+ as an IMAP-style date.
- def self.format_date(time)
- return time.strftime('%d-%b-%Y')
- end
-
- # Formats +time+ as an IMAP-style date-time.
- def self.format_datetime(time)
- return time.strftime('%d-%b-%Y %H:%M %z')
- end
-
- private
-
- CRLF = "\r\n" # :nodoc:
- PORT = 143 # :nodoc:
- SSL_PORT = 993 # :nodoc:
-
- @@debug = false
- @@authenticators = {}
- @@max_flag_count = 10000
-
- # call-seq:
- # Net::IMAP.new(host, options = {})
- #
- # Creates a new Net::IMAP object and connects it to the specified
- # +host+.
- #
- # +options+ is an option hash, each key of which is a symbol.
- #
- # The available options are:
- #
- # port:: port number (default value is 143 for imap, or 993 for imaps)
- # ssl:: if options[:ssl] is true, then an attempt will be made
- # to use SSL (now TLS) to connect to the server. For this to work
- # OpenSSL [OSSL] and the Ruby OpenSSL [RSSL] extensions need to
- # be installed.
- # if options[:ssl] is a hash, it's passed to
- # OpenSSL::SSL::SSLContext#set_params as parameters.
- #