Module: Mailmate::CLI::Modify Private
Overview
This module is part of a private API. You should avoid using this module if possible, as it may be removed or be changed in the future.
‘mm-modify` — apply AppleScript-driven actions (read, flag, tag, archive, move, …) to a MailMate message by its eml-id.
Ports mailmate-modify. Multiple actions in one invocation share a single open+wait cycle so chained operations are batched.
Constant Summary collapse
- ACTIONS =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
action → [selector] or [selector, arg-count]. arg-count default 0.
{ "read" => ["markAsRead:"], "unread" => ["markAsUnread:"], "flag" => [:ensure_flagged], "unflag" => [:ensure_not_flagged], "tag" => ["setTag:", 1], "untag" => ["removeTag:", 1], "clear-tags" => ["clearTags:"], "archive" => ["archive:"], "junk" => ["markAsJunk:"], "not-junk" => ["markAsNotJunk:"], "mute" => ["toggleMuteState:"], "delete" => ["deleteMessage:"], "move" => ["moveToMailbox:", 1], }.freeze
Instance Method Summary collapse
- #current_flags(eml_id) ⇒ Object private
- #drive(eml_id, message_id, actions, opts) ⇒ Object private
- #parse_actions(argv, parser) ⇒ Object private
- #parse_options(argv) ⇒ Object private
- #run(argv) ⇒ Object private
- #usage_error(parser, msg) ⇒ Object private
- #warn_on_duplicates(message_id, eml_id) ⇒ Object private
Instance Method Details
#current_flags(eml_id) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
174 175 176 177 178 179 180 181 |
# File 'lib/mailmate/cli/modify.rb', line 174 def current_flags(eml_id) # AppleScript actions write the index asynchronously — bust just the # #flags cache to pick up the latest values without throwing away # other warmed indexes (#message-id, #source) that this same # invocation may still need. Mailmate::IndexReader.reset!("#flags") Mailmate::IndexReader.for("#flags").flags_for(eml_id.to_i) end |
#drive(eml_id, message_id, actions, opts) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
# File 'lib/mailmate/cli/modify.rb', line 137 def drive(eml_id, , actions, opts) driver = Mailmate::AppleScriptDriver.new(dry_run: opts[:dry_run]) mid_url = Mailmate::MidUrl.for() windows_before = driver.window_ids driver.open_url(mid_url) sleep(opts[:settle]) unless opts[:dry_run] new_windows = driver.window_ids - windows_before actions.each do |name, selector, args| case selector when :ensure_flagged, :ensure_not_flagged want = selector == :ensure_flagged flags = opts[:dry_run] ? [] : current_flags(eml_id) has = flags.include?("\\Flagged") if has == want $stdout.puts "#{name}: already #{want ? "flagged" : "not flagged"} — no-op" else driver.perform("toggleFlag:") sleep(opts[:settle]) unless opts[:dry_run] end else driver.perform(selector, *args) sleep(opts[:settle]) unless opts[:dry_run] end end if opts[:verify] && !opts[:dry_run] sleep(opts[:settle]) $stdout.puts "Flags now: #{current_flags(eml_id).inspect}" end unless opts[:keep_window] || opts[:dry_run] || new_windows.empty? driver.close_windows(new_windows) end end |
#parse_actions(argv, parser) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
# File 'lib/mailmate/cli/modify.rb', line 103 def parse_actions(argv, parser) actions = [] i = 0 while i < argv.length name = argv[i] spec = ACTIONS[name] unless spec warn "mm-modify: unknown action #{name.inspect}" warn parser.help return nil end arg_count = spec.is_a?(Symbol) ? 0 : (spec[1] || 0) args = argv[(i + 1)...(i + 1 + arg_count)] || [] if args.length < arg_count warn "mm-modify: action '#{name}' needs #{arg_count} arg(s); got #{args.length}" return nil end actions << [name, spec.first, args] i += 1 + arg_count end actions end |
#parse_options(argv) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/mailmate/cli/modify.rb', line 66 def (argv) opts = { verify: false, dry_run: false, settle: 3.5, keep_window: false } parser = OptionParser.new do |o| o. = <<~BANNER Usage: mm-modify <id> <action> [args...] [<action> [args...]]... <id> can be either a local eml-id (e.g. 183715) or an RFC Message-ID (with or without angle brackets, e.g. <abc@example.com>). Quote the Message-ID in your shell so the < > aren't interpreted as redirection. Selects the message in MailMate (via the `mid:` URL) and runs one or more AppleScript key-binding selectors against the now-selected message. Multiple actions share one open+wait cycle. ACTIONS read Mark seen (\\Seen) unread Mark unseen flag Ensure \\Flagged is set (no-op if already) unflag Ensure \\Flagged is cleared (no-op if already) tag <name> Set IMAP keyword <name> (e.g. urgent, $Followup) untag <name> Remove IMAP keyword <name> clear-tags Remove all keywords archive Move to the archive mailbox move <mailbox-uuid> Move to a specific mailbox (use UUID from MailMate) junk / not-junk Mark as junk / not junk mute Toggle mute state delete Delete (move to trash) BANNER o.on("--verify", "After running, print the message's current flags") { opts[:verify] = true } o.on("--dry-run", "Print the actions; don't run") { opts[:dry_run] = true } o.on("--settle SECONDS", Float, "Sleep between operations (default 3.5)") { |s| opts[:settle] = s } o.on("--keep-window", "Don't close the spawned message-viewer window") { opts[:keep_window] = true } end parser.parse!(argv) [opts, parser] end |
#run(argv) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/mailmate/cli/modify.rb', line 33 def run(argv) opts, parser = (argv) input = argv.shift return usage_error(parser, "missing <id>") if input.nil? || input.empty? return usage_error(parser, "no actions given") if argv.empty? actions = parse_actions(argv, parser) return 2 if actions.nil? eml_id = Mailmate::EmlLookup.resolve_id(input) if eml_id.nil? || eml_id.zero? warn "Not found: #{input.inspect} (couldn't resolve as eml-id or Message-ID)" return 1 end path = Mailmate::EmlLookup.path_for(eml_id) unless path warn "Not found: #{eml_id}.eml" return 1 end = Mailmate::HeaderReader.(path) unless warn "Could not find Message-ID in #{path}" return 1 end warn_on_duplicates(, eml_id) drive(eml_id, , actions, opts) 0 end |
#usage_error(parser, msg) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
183 184 185 186 187 |
# File 'lib/mailmate/cli/modify.rb', line 183 def usage_error(parser, msg) warn "mm-modify: #{msg}" warn parser.help 2 end |
#warn_on_duplicates(message_id, eml_id) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
126 127 128 129 130 131 132 133 134 135 |
# File 'lib/mailmate/cli/modify.rb', line 126 def warn_on_duplicates(, eml_id) dup_ids = Mailmate::DuplicateScanner.eml_ids_for() return unless dup_ids.size > 1 others = dup_ids.reject { |id| id == eml_id.to_i } warn "WARNING: Message-ID has #{dup_ids.size} copies in MailMate's tree." warn " You targeted #{eml_id}.eml but the action may land on:" warn " #{others.join(", ")}" warn " (MailMate picks one candidate when resolving `mid:` URLs;" warn " the choice is not deterministic by .eml id.)" end |