Class: Imapcli::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/imapcli/client.rb

Overview

Wrapper for Net::IMAP

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(server_with_optional_port, user, pass) ⇒ Client

Initializs the Client class.

server_with_optional_port is the server’s domain name; the port may be added following a colon. Default port is 993. user is the user (account) name to log into the server. pass is the password to log into the server.



15
16
17
18
19
20
21
# File 'lib/imapcli/client.rb', line 15

def initialize(server_with_optional_port, user, pass)
  @port = 993 # default
  self.server = server_with_optional_port
  @user = user
  @pass = pass
  clear_log
end

Instance Attribute Details

#passObject

rubocop:disable Metrics/ClassLength



6
7
8
# File 'lib/imapcli/client.rb', line 6

def pass
  @pass
end

#portObject

rubocop:disable Metrics/ClassLength



6
7
8
# File 'lib/imapcli/client.rb', line 6

def port
  @port
end

#responsesObject (readonly)

Returns the value of attribute responses.



7
8
9
# File 'lib/imapcli/client.rb', line 7

def responses
  @responses
end

#serverObject

Attribute reader for the server domain name



24
25
26
# File 'lib/imapcli/client.rb', line 24

def server
  @server
end

#userObject

rubocop:disable Metrics/ClassLength



6
7
8
# File 'lib/imapcli/client.rb', line 6

def user
  @user
end

Instance Method Details

#capabilityObject

Returns the server’s capabilities.



103
104
105
# File 'lib/imapcli/client.rb', line 103

def capability
  @capability ||= query_server { connection.capability }
end

#clear_logObject

Clears the server response log



60
61
62
# File 'lib/imapcli/client.rb', line 60

def clear_log
  @log = []
end

#collect_statsObject

Collects stats for all mailboxes recursively.



163
164
165
# File 'lib/imapcli/client.rb', line 163

def collect_stats
  mailbox_root.collect_stats(self)
end

#connectionObject

Returns a connection to the server.

The value is cached.



72
73
74
# File 'lib/imapcli/client.rb', line 72

def connection
  @connection ||= Net::IMAP.new(@server, @port, true)
end

#find_mailbox(mailbox) ⇒ Object

Attempts to locate a given mailbox in the mailbox_root.

Returns nil if the mailbox is not found.



184
185
186
# File 'lib/imapcli/client.rb', line 184

def find_mailbox(mailbox)
  mailbox_root.find_sub_mailbox(mailbox, separator)
end

#greetingObject

Returns the server’s greeting (which may reveal the server software name such as ‘Dovecot’).



98
99
100
# File 'lib/imapcli/client.rb', line 98

def greeting
  query_server { connection.greeting.data.text.strip }
end

#last_responseObject

Returns the last response from the server



65
66
67
# File 'lib/imapcli/client.rb', line 65

def last_response
  @log.last
end

#loginObject

Logs in to the server.

Returns true if login was successful, false if not (e..g, invalid credentials).



80
81
82
83
84
85
86
87
88
# File 'lib/imapcli/client.rb', line 80

def 
  raise('no connection to a server') unless connection

  begin
    response_ok? connection.(@user, @pass)
  rescue Net::IMAP::NoResponseError => e
    log_error e
  end
end

#logoutObject

Logs out of the server.



91
92
93
94
# File 'lib/imapcli/client.rb', line 91

def logout
  # access instance variable to avoid creating a new connection
  @connection&.logout
end

#mailbox_rootObject

Returns a tree of Imapcli::Mailbox objects.

The value is cached.



177
178
179
# File 'lib/imapcli/client.rb', line 177

def mailbox_root
  @mailbox_root ||= Mailbox.new(mailboxes)
end

#mailboxesObject

Gets a list of Net::IMAP::MailboxList items, one for each mailbox.

The value is cached.



170
171
172
# File 'lib/imapcli/client.rb', line 170

def mailboxes
  @mailboxes ||= query_server { @connection.list('', '*') }
end

#message_sizes(mailbox) ⇒ Object

Examines a mailbox and returns statistics about the messages in it.

Returns an array with the following keys:

  • :count: Total count of messages.

  • :size: Total size of all messages in bytes.

  • :min: Size of the smallest message.

  • :q1: First quartile of message sizes.

  • :median: Median of message sizes.

  • :q3: Third quartile of messages sizes.

  • :max: Size of largest message.



147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/imapcli/client.rb', line 147

def message_sizes(mailbox)
  messages = messages(mailbox)
  if messages.empty?
    []
  else
    query_server do
      messages.each_slice(1000).map do |some_messages|
        connection.fetch(some_messages, 'RFC822.SIZE').map do |f|
          f.attr['RFC822.SIZE']
        end
      end.flatten
    end
  end
end

#messages(mailbox) ⇒ Object

Returns an array of message indexes for a mailbox.

The value is currently NOT cached.



132
133
134
135
# File 'lib/imapcli/client.rb', line 132

def messages(mailbox)
  query_server { connection.examine(mailbox) }
  query_server { connection.search('ALL') }
end

#quotaObject

If the server supports_quota, returns an array containing the current usage (in kiB), the total quota (in kiB), and the percent usage.



119
120
121
122
123
124
125
126
127
# File 'lib/imapcli/client.rb', line 119

def quota
  return unless supports_quota

  @quota ||= begin
    info = query_server { @connection.getquotaroot('INBOX')[1] }
    percent = info.quota.to_i.positive? ? info.usage.to_i.fdiv(info.quota.to_i) * 100 : nil
    [info.usage, info.quota, percent]
  end
end

#separatorObject

Returns the character that is used to separate nested mailbox names.



108
109
110
# File 'lib/imapcli/client.rb', line 108

def separator
  @separator ||= query_server { connection.list('', '')[0].delim }
end

#server_valid?Boolean

Perform basic sanity check on server name

Note that a propery regex for an FQDN is hard to achieve. See stackoverflow.com/a/106223/270712 and elsewhere.

Returns:

  • (Boolean)


44
45
46
# File 'lib/imapcli/client.rb', line 44

def server_valid?
  @server.match? '^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$' # rubocop:disable Layout/LineLength
end

#supports_quotaObject

Returns true if the server supports the IMAP QUOTA extension.



113
114
115
# File 'lib/imapcli/client.rb', line 113

def supports_quota
  capability.include? 'QUOTA'
end

#user_valid?Boolean

Perform very basic sanity check on user name

Returns:

  • (Boolean)


50
51
52
# File 'lib/imapcli/client.rb', line 50

def user_valid?
  @user&.length&.> 0
end

#valid?Boolean

Returns true if both server and user name are valid.

Returns:

  • (Boolean)


55
56
57
# File 'lib/imapcli/client.rb', line 55

def valid?
  server_valid? && user_valid?
end