Class: ConnectionImap

Inherits:
Object
  • Object
show all
Defined in:
lib/connection/imap.rb

Overview

Handles the Imap configuration and connection

Constant Summary collapse

STORE_PATH =
"#{ENV['HOME']}/.mailchain_connector/imap/"
STORE_FILE =
File.join(STORE_PATH, 'mailchain_connector_imap.pstore')

Instance Method Summary collapse

Constructor Details

#initialize(config, config_file) ⇒ ConnectionImap

reads the config file and sets ‘@config`



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

def initialize(config, config_file)
  get_or_create_pstore
  @config = config
  @config_file = config_file
end

Instance Method Details

#append_message(protocol, network, address, message, message_id, flags = nil, date_time = nil) ⇒ Object

Appends message to mailbox ‘date_time`: Time Connects and disconnects at the beginning and end of the method

if the connection is not defined/ connected already


153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/connection/imap.rb', line 153

def append_message(protocol, network, address, message, message_id, flags = nil, date_time = nil)
  unless msg_appended?(message_id)
    connect unless connected_and_authenticated?

    target_mailbox = get_mailbox(protocol, address, network)
    create_mailbox_path(target_mailbox)
    @connection.examine(target_mailbox)

    if @connection.search(['HEADER', 'MESSAGE-ID', message.message_id]).empty?
      @connection.append(target_mailbox, message.to_s, flags, date_time)
    end
    store_msg_appended(message_id)
  end
end

#check_passwordObject



71
72
73
74
75
76
77
78
79
# File 'lib/connection/imap.rb', line 71

def check_password
  unless @config['imap']['password']
    # Get imap password

    prompt = TTY::Prompt.new
    @config['imap']['password'] = prompt.mask(
      'Enter your imap password', required: true
    )
  end
end

#configuration_wizardObject

# Run the IMAP configuration



41
42
43
44
45
46
47
48
49
# File 'lib/connection/imap.rb', line 41

def configuration_wizard
  connection_configuration = ConnectionConfigurationImap.new(@config)
  result = connection_configuration.configuration_wizard
  if result['save']
    result['config']['imap'].delete('password')
    new_config_json = JSON.pretty_generate(result['config'])
    File.write(@config_file, new_config_json)
  end
end

#configure_and_connectObject

Configures the IMAP server settings then tests the connection



97
98
99
100
101
102
103
# File 'lib/connection/imap.rb', line 97

def configure_and_connect
  if !configuration_wizard # TODO: - wire up to connection configuration

    exit
  else
    test_connection
  end
end

#connectObject

Connect to the IMAP server, attempting ‘LOGIN’ then ‘PLAIN’



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/connection/imap.rb', line 52

def connect
  check_password
  @connection ||= Net::IMAP.new(@config['imap']['server'], @config['imap']['port'], @config['imap']['ssl'])
  res = true
  unless connected_and_authenticated?
    begin
      @connection.authenticate('LOGIN', @config['imap']['username'], @config['imap']['password'])
    rescue StandardError
      begin
        @connection.authenticate('PLAIN', @config['imap']['username'], @config['imap']['password'])
      rescue StandardError => e
        puts "IMAP failed to connect: #{e}"
        res = false
      end
    end
  end
  res
end

#connected_and_authenticated?Boolean

Attempts to list mailboxes (folders). If length > 0, then wemust be authenticated

Returns:

  • (Boolean)


175
176
177
178
179
# File 'lib/connection/imap.rb', line 175

def connected_and_authenticated?
  !@connection.disconnected? && !@connection.list('', '*').empty?
rescue StandardError => e
  false
end

#create_mailbox_path(target_mailbox) ⇒ Object

Create the folder path for the mailbox according to chosen folder format



137
138
139
140
141
142
143
144
145
146
147
# File 'lib/connection/imap.rb', line 137

def create_mailbox_path(target_mailbox)
  return if @connection.list('', target_mailbox)

  folders = target_mailbox.split(delimiter)
  mbox = []
  (0...folders.length).each_with_index do |_folder, index|
    mbox.push(folders[index])
    mbox_as_str = mbox.join(delimiter)
    @connection.create(mbox_as_str) unless @connection.list('', mbox_as_str)
  end
end

#delimiterObject

Sets the connection delimiter



82
83
84
85
86
87
88
# File 'lib/connection/imap.rb', line 82

def delimiter
  if @delimiter.nil?
    folders = list_folders
    @delimiter = folders[0][:delim]
  end
  @delimiter
end

#disconnectObject

Disconnects from the server



91
92
93
94
# File 'lib/connection/imap.rb', line 91

def disconnect
  @connection.disconnect unless @connection.nil? || @connection.disconnected?
  @connection = nil
end

#get_mailbox(protocol, address, network) ⇒ Object

Returns the target mailbox for the message according to the folder structre and Inbox preferences



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/connection/imap.rb', line 114

def get_mailbox(protocol, address, network)
  p_address = case protocol
              when 'ethereum'
                "0x#{address}"
              else
                address
              end

  if @config['mailchain']['mainnet_to_inbox'] && network.downcase == 'mainnet'
    'Inbox'
  else
    case @config['mailchain']['folders']
    when 'by_address'
      # 'Address>Protocol>Network'

      "Inbox#{delimiter}#{p_address}#{delimiter}#{protocol}#{delimiter}#{network}"
    when 'by_network'
      # 'Protocol>Network>Address'

      "Inbox#{delimiter}#{protocol}#{delimiter}#{network}#{delimiter}#{p_address}"
    end
  end
end

#get_or_create_pstoreObject

Check for pstore, and create if not exist



20
21
22
23
# File 'lib/connection/imap.rb', line 20

def get_or_create_pstore
  (FileUtils.mkdir_p(STORE_PATH) unless File.exist?(STORE_FILE))
  @pstore = PStore.new(STORE_FILE, true)
end

#list_foldersObject

Lists folders



169
170
171
172
# File 'lib/connection/imap.rb', line 169

def list_folders
  connect
  @connection.list('', '*')
end

#msg_appended?(message_id) ⇒ Boolean

Checks if MD5 hexdigest of message_id as key, with prefix ‘append_’ returns a true value from the database. Stored as md5 hash to obfuscate message ids. Returns true or false

Returns:

  • (Boolean)


35
36
37
38
# File 'lib/connection/imap.rb', line 35

def msg_appended?(message_id)
  message_id_hash = Digest::MD5.hexdigest(message_id)
  @pstore.transaction { @pstore['append_' + message_id_hash] } == true
end

#store_msg_appended(message_id) ⇒ Object

Records in pstore with the MD5 hexdigest of message_id as key, with prefix ‘append_’ and value as true. Stored as md5 hash to obfuscate message ids.



27
28
29
30
# File 'lib/connection/imap.rb', line 27

def store_msg_appended(message_id)
  message_id_hash = Digest::MD5.hexdigest(message_id)
  @pstore.transaction { @pstore['append_' + message_id_hash] = true }
end

#test_connectionObject

Tests the connection to the IMAP server



106
107
108
109
110
111
# File 'lib/connection/imap.rb', line 106

def test_connection
  puts 'Testing IMAP connection...'
  puts 'IMAP connection was successful' if connect
  disconnect unless @connection.disconnected?
  true
end