mournmail 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/push_gem.yml +48 -0
- data/README.md +61 -0
- data/lib/mournmail/config.rb +13 -1
- data/lib/mournmail/draft_mode.rb +7 -3
- data/lib/mournmail/message_mode.rb +6 -4
- data/lib/mournmail/message_rendering.rb +8 -2
- data/lib/mournmail/summary.rb +3 -1
- data/lib/mournmail/summary_mode.rb +10 -5
- data/lib/mournmail/utils.rb +23 -10
- data/lib/mournmail/version.rb +1 -1
- data/mournmail.gemspec +1 -1
- metadata +8 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ebc2414b32ab7005cc39801155dcfe26eb1381026a7750b80c28ae84db63dae0
|
4
|
+
data.tar.gz: 464beaa7109d55c1730baad310ac064974cf902fd43281c936721587edd175fc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 13eebd0a106ac2494793d379ab682091e2dcc6aff0cf5fe6c5c7eebb712c7ba0ddeb0f14d9e16278bebae72ee8a18747024bc64f5c9d42772ea50ec5a649f666
|
7
|
+
data.tar.gz: 1d6a84e080f9612c41201c6fa59856fee33e2a9c0a20159185ceef8e36f8b575ecd98762d77ea19a3de00e760925262e10ad5ec7630920fef9e6edbf4b83b2fb
|
@@ -0,0 +1,48 @@
|
|
1
|
+
name: Publish gem to rubygems.org
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
tags:
|
6
|
+
- 'v*'
|
7
|
+
|
8
|
+
permissions:
|
9
|
+
contents: read
|
10
|
+
|
11
|
+
jobs:
|
12
|
+
push:
|
13
|
+
if: github.repository == 'shugo/mournmail'
|
14
|
+
runs-on: ubuntu-latest
|
15
|
+
|
16
|
+
environment:
|
17
|
+
name: rubygems.org
|
18
|
+
url: https://rubygems.org/gems/mournmail
|
19
|
+
|
20
|
+
permissions:
|
21
|
+
contents: write
|
22
|
+
id-token: write
|
23
|
+
|
24
|
+
steps:
|
25
|
+
# Set up
|
26
|
+
- name: Harden Runner
|
27
|
+
uses: step-security/harden-runner@f086349bfa2bd1361f7909c78558e816508cdc10 # v2.8.0
|
28
|
+
with:
|
29
|
+
egress-policy: audit
|
30
|
+
|
31
|
+
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
32
|
+
|
33
|
+
- name: Set up Ruby
|
34
|
+
uses: ruby/setup-ruby@cacc9f1c0b3f4eb8a16a6bb0ed10897b43b9de49 # v1.176.0
|
35
|
+
with:
|
36
|
+
bundler-cache: true
|
37
|
+
ruby-version: ruby
|
38
|
+
|
39
|
+
# Release
|
40
|
+
- name: Publish to RubyGems
|
41
|
+
uses: rubygems/release-gem@612653d273a73bdae1df8453e090060bb4db5f31 # v1
|
42
|
+
|
43
|
+
- name: Create GitHub release
|
44
|
+
run: |
|
45
|
+
tag_name="$(git describe --tags --abbrev=0)"
|
46
|
+
gh release create "${tag_name}" --verify-tag --draft --generate-notes
|
47
|
+
env:
|
48
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
data/README.md
CHANGED
@@ -70,6 +70,67 @@ Type `M-x mail` to send a mail.
|
|
70
70
|
|
71
71
|
Type `M-x mournmail` to visit INBOX.
|
72
72
|
|
73
|
+
## Key bindings
|
74
|
+
|
75
|
+
### Summary
|
76
|
+
|
77
|
+
|Key |Command |Description |
|
78
|
+
|---|---|---|
|
79
|
+
|s |mournmail_summary_sync |Sync summary. With C-u sync all mails |
|
80
|
+
|SPC |summary_read_command |Read a mail |
|
81
|
+
|C-h |summary_scroll_down_command |Scroll down the current message |
|
82
|
+
|n |summary_next_command |Display the next mail |
|
83
|
+
|w |summary_write_command |Write a new mail |
|
84
|
+
|a |summary_reply_command |Reply to the current message |
|
85
|
+
|A |summary_reply_command |Reply to the current message |
|
86
|
+
|f |summary_forward_command |Forward the current message |
|
87
|
+
|u |summary_toggle_seen_command |Toggle Seen |
|
88
|
+
|$ |summary_toggle_flagged_command |Toggle Flagged |
|
89
|
+
|d |summary_toggle_deleted_command |Toggle Deleted |
|
90
|
+
|x |summary_toggle_mark_command |Toggle mark |
|
91
|
+
|* a |summary_mark_all_command |Mark all mails |
|
92
|
+
|* n |summary_unmark_all_command |Unmark all mails |
|
93
|
+
|* r |summary_mark_read_command |Mark read mails |
|
94
|
+
|* u |summary_mark_unread_command |Mark unread mails |
|
95
|
+
|* s |summary_mark_flagged_command |Mark flagged mails |
|
96
|
+
|* t |summary_mark_unflagged_command |Mark unflagged mails |
|
97
|
+
|y |summary_archive_command |Archive mails. Archived mails will be deleted or refiled from the server, and only shown by summary_search_command |
|
98
|
+
|o |summary_refile_command |Refile marked mails |
|
99
|
+
|! |summary_refile_spam_command |Refile marked mails as spam |
|
100
|
+
|p |summary_prefetch_command |Prefetch mails |
|
101
|
+
|X |summary_expunge_command |Expunge deleted mails |
|
102
|
+
|v |summary_view_source_command |View source of a mail |
|
103
|
+
|M |summary_merge_partial_command |Merge marked message/partial |
|
104
|
+
|q |mournmail_quit |Quit Mournmail |
|
105
|
+
|k |previous_line |Move up |
|
106
|
+
|j |next_line |Move down |
|
107
|
+
|m |mournmail_visit_mailbox |Visit mailbox |
|
108
|
+
|S |mournmail_visit_spam_mailbox |Visit spam mailbox |
|
109
|
+
|/ |summary_search_command |Search mails |
|
110
|
+
|t |summary_show_thread_command |Show the thread of the current mail |
|
111
|
+
|@ |summary_change_account_command |Change the current account |
|
112
|
+
|
113
|
+
### Message
|
114
|
+
|
115
|
+
|Key |Command |Description |
|
116
|
+
|---|---|---|
|
117
|
+
|RET |message_open_link_or_part_command |Open link or MIME part |
|
118
|
+
|s |message_save_part_command |Save the MIME part |
|
119
|
+
|TAB |message_next_link_or_part_command| Go to the next link or MIME part |
|
120
|
+
|
121
|
+
### Draft
|
122
|
+
|
123
|
+
|Key |Command |Description |
|
124
|
+
|---|---|---|
|
125
|
+
|C-c C-c |draft_send_command |Send a mail |
|
126
|
+
|C-c C-k |draft_kill_command |Kill the draft buffer |
|
127
|
+
|C-c C-x TAB |draft_attach_file_command |Attach a file |
|
128
|
+
|C-c C-x v |draft_pgp_sign_command |PGP sign |
|
129
|
+
|C-c C-x e |draft_pgp_encrypt_command |PGP encrypt |
|
130
|
+
|C-c TAB |insert_signature_command |Insert signature |
|
131
|
+
|C-c @ |draft_change_account_command |Change account |
|
132
|
+
|TAB |draft_complete_or_insert_tab_command |Complete a mail address or insert a tab |
|
133
|
+
|
73
134
|
## Development
|
74
135
|
|
75
136
|
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/lib/mournmail/config.rb
CHANGED
@@ -9,6 +9,7 @@ module Textbringer
|
|
9
9
|
"From",
|
10
10
|
"To",
|
11
11
|
"Cc",
|
12
|
+
"Bcc",
|
12
13
|
"Reply-To",
|
13
14
|
"User-Agent",
|
14
15
|
"X-Mailer",
|
@@ -35,7 +36,7 @@ module Textbringer
|
|
35
36
|
CONFIG[:mournmail_link_open_comamnd] = "xdg-open"
|
36
37
|
end
|
37
38
|
CONFIG[:mournmail_addresses_path] = File.expand_path("~/.addresses")
|
38
|
-
CONFIG[:mournmail_signature_regexp] =
|
39
|
+
CONFIG[:mournmail_signature_regexp] = /^-- /
|
39
40
|
CONFIG[:mournmail_allowed_attachment_extensions] = [
|
40
41
|
"txt",
|
41
42
|
"md",
|
@@ -53,4 +54,15 @@ module Textbringer
|
|
53
54
|
"ppt",
|
54
55
|
"zip"
|
55
56
|
]
|
57
|
+
CONFIG[:forgotten_attachment_re] =
|
58
|
+
Regexp.new(
|
59
|
+
"^(?!>).*" +
|
60
|
+
Regexp.union(
|
61
|
+
/I('ve| have) (attached|included)/,
|
62
|
+
/See the (attached|attachment)/,
|
63
|
+
/Attached file/,
|
64
|
+
/添付(する|した|します|しました|いたします|いたしました)/,
|
65
|
+
/ファイルを参照/
|
66
|
+
).to_s
|
67
|
+
)
|
56
68
|
end
|
data/lib/mournmail/draft_mode.rb
CHANGED
@@ -21,11 +21,15 @@ module Mournmail
|
|
21
21
|
|
22
22
|
define_local_command(:draft_send,
|
23
23
|
doc: "Send a mail and exit from mail buffer.") do
|
24
|
-
|
25
|
-
|
24
|
+
s = @buffer.to_s
|
25
|
+
if s.match?(CONFIG[:forgotten_attachment_re]) &&
|
26
|
+
!s.match?(/^Attached-File:/)
|
27
|
+
msg = "It seems like you forgot to attach a file. Send anyway?"
|
28
|
+
return unless yes_or_no?(msg)
|
29
|
+
else
|
30
|
+
return unless y_or_n?("Send this mail?")
|
26
31
|
end
|
27
32
|
run_hooks(:mournmail_pre_send_hook)
|
28
|
-
s = @buffer.to_s
|
29
33
|
charset = CONFIG[:mournmail_charset]
|
30
34
|
begin
|
31
35
|
s.encode(charset)
|
@@ -11,10 +11,12 @@ module Mournmail
|
|
11
11
|
MESSAGE_MODE_MAP.define_key("\t", :message_next_link_or_part_command)
|
12
12
|
|
13
13
|
# See http://nihongo.jp/support/mail_guide/dev_guide.txt
|
14
|
-
|
15
|
-
|
14
|
+
URI_REGEXP = Regexp.union(URI.regexp("http"),
|
15
|
+
URI.regexp("https"),
|
16
|
+
URI.regexp("ftp"),
|
17
|
+
URI.regexp("mailto"))
|
16
18
|
MIME_REGEXP = /^\[(([0-9.]+) [A-Za-z._\-]+\/[A-Za-z._\-]+.*|PGP\/MIME .*)\]$/
|
17
|
-
URI_OR_MIME_REGEXP =
|
19
|
+
URI_OR_MIME_REGEXP = Regexp.union(URI_REGEXP, MIME_REGEXP)
|
18
20
|
|
19
21
|
define_syntax :field_name, /^[A-Za-z\-]+: /
|
20
22
|
define_syntax :quotation, /^>.*/
|
@@ -128,7 +130,7 @@ module Mournmail
|
|
128
130
|
if part.multipart?
|
129
131
|
raise EditorError, "Can't open a multipart entity."
|
130
132
|
end
|
131
|
-
ext = part_file_name(part).slice(/\.([^.]+)\z/, 1)
|
133
|
+
ext = part_file_name(part).slice(/\.([^.]+)\z/, 1).downcase
|
132
134
|
if part.main_type != "text" || part.sub_type == "html"
|
133
135
|
if ext.nil?
|
134
136
|
raise EditorError, "The extension of the filename is not specified"
|
@@ -1,5 +1,5 @@
|
|
1
1
|
require "mail"
|
2
|
-
require "
|
2
|
+
require "nokogiri"
|
3
3
|
|
4
4
|
module Mournmail
|
5
5
|
module MessageRendering
|
@@ -34,7 +34,9 @@ module Mournmail
|
|
34
34
|
elsif main_type.nil? || main_type == "text"
|
35
35
|
s = Mournmail.to_utf8(body.decoded, charset)
|
36
36
|
if sub_type == "html"
|
37
|
-
|
37
|
+
doc = Nokogiri::HTML(s)
|
38
|
+
doc.css("script, style, link").each { |node| node.remove }
|
39
|
+
"[0 text/html]\n" + doc.css("body").text.squeeze(" \n")
|
38
40
|
else
|
39
41
|
s
|
40
42
|
end
|
@@ -115,6 +117,10 @@ module Mournmail
|
|
115
117
|
type = Mail::Encodings.decode_encode(self["content-type"].to_s,
|
116
118
|
:decode) rescue
|
117
119
|
"broken/type; error=\"#{$!} (#{$!.class})\""
|
120
|
+
filename = self["content-disposition"]&.filename
|
121
|
+
if filename && !self["content-type"]&.filename
|
122
|
+
type += "; filename=#{filename}"
|
123
|
+
end
|
118
124
|
"[#{index} #{type}]\n" +
|
119
125
|
render_content(indices, no_content)
|
120
126
|
end
|
data/lib/mournmail/summary.rb
CHANGED
@@ -142,7 +142,8 @@ module Mournmail
|
|
142
142
|
s = data[0].attr["BODY[]"]
|
143
143
|
mail = Mournmail.parse_mail(s)
|
144
144
|
spam_mailbox = Mournmail.account_config[:spam_mailbox]
|
145
|
-
if
|
145
|
+
if spam_mailbox.nil? ||
|
146
|
+
@mailbox != Net::IMAP.encode_utf7(spam_mailbox)
|
146
147
|
item.cache_id = Mournmail.write_mail_cache(s)
|
147
148
|
Mournmail.index_mail(item.cache_id, mail)
|
148
149
|
end
|
@@ -261,6 +262,7 @@ module Mournmail
|
|
261
262
|
width = 0
|
262
263
|
str = +""
|
263
264
|
s.each_char do |c|
|
265
|
+
next if c == "\n"
|
264
266
|
w = Buffer.display_width(c)
|
265
267
|
width += w
|
266
268
|
if width > n
|
@@ -478,6 +478,11 @@ module Mournmail
|
|
478
478
|
|
479
479
|
private
|
480
480
|
|
481
|
+
def get_summary_item(uid)
|
482
|
+
summary = Mournmail.current_summary
|
483
|
+
summary && summary[uid]
|
484
|
+
end
|
485
|
+
|
481
486
|
def selected_uid
|
482
487
|
uid = @buffer.save_excursion {
|
483
488
|
@buffer.beginning_of_line
|
@@ -538,7 +543,7 @@ module Mournmail
|
|
538
543
|
end
|
539
544
|
|
540
545
|
def mark_as_seen(uid, update_server)
|
541
|
-
summary_item =
|
546
|
+
summary_item = get_summary_item(uid)
|
542
547
|
if summary_item && !summary_item.flags.include?(:Seen)
|
543
548
|
summary_item.set_flag(:Seen, update_server: update_server)
|
544
549
|
Mournmail.current_summary.save
|
@@ -547,7 +552,7 @@ module Mournmail
|
|
547
552
|
end
|
548
553
|
|
549
554
|
def toggle_flag(uid, flag)
|
550
|
-
summary_item =
|
555
|
+
summary_item = get_summary_item(uid)
|
551
556
|
if summary_item
|
552
557
|
Mournmail.background do
|
553
558
|
summary_item.toggle_flag(flag)
|
@@ -596,8 +601,8 @@ module Mournmail
|
|
596
601
|
summary_text = messages.map { |m|
|
597
602
|
format("%s [ %s ] %s\n",
|
598
603
|
m.date.strftime("%m/%d %H:%M"),
|
599
|
-
ljust(m.from.to_s, 16),
|
600
|
-
ljust(m.subject.to_s, 45))
|
604
|
+
ljust(m.from.to_s.gsub(/\n/, ""), 16),
|
605
|
+
ljust(m.subject.to_s.gsub(/\n/, ""), 45))
|
601
606
|
}.join
|
602
607
|
buffer = Buffer.find_or_new(buffer_name, undo_limit: 0,
|
603
608
|
read_only: true)
|
@@ -657,7 +662,7 @@ module Mournmail
|
|
657
662
|
|
658
663
|
def current_message
|
659
664
|
uid = selected_uid
|
660
|
-
item =
|
665
|
+
item = get_summary_item(uid)
|
661
666
|
message = Groonga["Messages"][item.cache_id]
|
662
667
|
if message.nil?
|
663
668
|
raise EditorError, "No message found"
|
data/lib/mournmail/utils.rb
CHANGED
@@ -13,15 +13,28 @@ require 'google/api_client/auth/storages/file_store'
|
|
13
13
|
require 'launchy'
|
14
14
|
require "socket"
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
16
|
+
if defined?(Net::SMTP::Authenticator)
|
17
|
+
class Net::SMTP
|
18
|
+
class AuthXOAuth2 < Net::SMTP::Authenticator
|
19
|
+
auth_type :xoauth2
|
20
|
+
|
21
|
+
def auth(user, secret)
|
22
|
+
s = Net::IMAP::XOauth2Authenticator.new(user, secret).process("")
|
23
|
+
finish('AUTH XOAUTH2 ' + base64_encode(s))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
else
|
28
|
+
class Net::SMTP
|
29
|
+
def auth_xoauth2(user, secret)
|
30
|
+
check_auth_args user, secret
|
31
|
+
res = critical {
|
32
|
+
s = Net::IMAP::XOauth2Authenticator.new(user, secret).process("")
|
33
|
+
get_response('AUTH XOAUTH2 ' + base64_encode(s))
|
34
|
+
}
|
35
|
+
check_auth_response res
|
36
|
+
res
|
37
|
+
end
|
25
38
|
end
|
26
39
|
end
|
27
40
|
|
@@ -184,7 +197,7 @@ module Mournmail
|
|
184
197
|
end
|
185
198
|
Timeout.timeout(CONFIG[:mournmail_imap_connect_timeout]) do
|
186
199
|
@imap = Net::IMAP.new(conf[:imap_host],
|
187
|
-
conf[:imap_options])
|
200
|
+
conf[:imap_options].except(:auth_type, :user_name))
|
188
201
|
@imap.authenticate(auth_type, conf[:imap_options][:user_name],
|
189
202
|
password)
|
190
203
|
@mailboxes = @imap.list("", "*").map { |mbox|
|
data/lib/mournmail/version.rb
CHANGED
data/mournmail.gemspec
CHANGED
@@ -29,7 +29,7 @@ Gem::Specification.new do |spec|
|
|
29
29
|
spec.add_runtime_dependency "rroonga"
|
30
30
|
spec.add_runtime_dependency "google-apis-core"
|
31
31
|
spec.add_runtime_dependency "launchy"
|
32
|
-
spec.add_runtime_dependency "
|
32
|
+
spec.add_runtime_dependency "nokogiri"
|
33
33
|
|
34
34
|
spec.add_development_dependency "bundler"
|
35
35
|
spec.add_development_dependency "rake", ">= 12.0"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mournmail
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shugo Maeda
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-06-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: textbringer
|
@@ -123,7 +123,7 @@ dependencies:
|
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: '0'
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
|
-
name:
|
126
|
+
name: nokogiri
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
128
128
|
requirements:
|
129
129
|
- - ">="
|
@@ -172,6 +172,7 @@ executables:
|
|
172
172
|
extensions: []
|
173
173
|
extra_rdoc_files: []
|
174
174
|
files:
|
175
|
+
- ".github/workflows/push_gem.yml"
|
175
176
|
- ".gitignore"
|
176
177
|
- Gemfile
|
177
178
|
- LICENSE.txt
|
@@ -199,7 +200,7 @@ homepage: https://github.com/shugo/mournmail
|
|
199
200
|
licenses:
|
200
201
|
- MIT
|
201
202
|
metadata: {}
|
202
|
-
post_install_message:
|
203
|
+
post_install_message:
|
203
204
|
rdoc_options: []
|
204
205
|
require_paths:
|
205
206
|
- lib
|
@@ -214,8 +215,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
214
215
|
- !ruby/object:Gem::Version
|
215
216
|
version: '0'
|
216
217
|
requirements: []
|
217
|
-
rubygems_version: 3.
|
218
|
-
signing_key:
|
218
|
+
rubygems_version: 3.5.9
|
219
|
+
signing_key:
|
219
220
|
specification_version: 4
|
220
221
|
summary: A message user agent for Textbringer.
|
221
222
|
test_files: []
|