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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7b758be18cec7a7b8e51d1d1a02cdc8652200800d3c96cd54b471f360e139310
4
- data.tar.gz: d201ace873c79702fec68815cda4276f4d78d8dcb60e982b2d24c43efd014778
3
+ metadata.gz: ebc2414b32ab7005cc39801155dcfe26eb1381026a7750b80c28ae84db63dae0
4
+ data.tar.gz: 464beaa7109d55c1730baad310ac064974cf902fd43281c936721587edd175fc
5
5
  SHA512:
6
- metadata.gz: d972e8d6410736c90eb8074f723a96bed957ca7cdd7c74350261c47cce57c3527a692ea422375e08a5f892ee08fbcfcb7d88edbb0b83e9c6ab1adf6f0616383b
7
- data.tar.gz: fa3659729fc83d4373896511009080e36297c1382e857e25ef2c7dfa1421d78ef506bafd23d81e00f504972116a0a281843359b22b4446b2031791e6b115450c
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.
@@ -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] = /^\n-- /
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
@@ -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
- unless y_or_n?("Send this mail?")
25
- return
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
- MAILTO_REGEXP = URI.regexp("mailto")
15
- URI_REGEXP = /(https?|ftp):\/\/[^  \t\n>)"]*[^\]  \t\n>.,:)"]+|#{MAILTO_REGEXP}/
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 = /#{URI_REGEXP}|#{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 "html2text"
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
- "[0 text/html]\n" + Html2Text.convert(s)
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
@@ -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 @mailbox != Net::IMAP.encode_utf7(spam_mailbox)
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 = Mournmail.current_summary[uid]
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 = Mournmail.current_summary[uid]
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 = Mournmail.current_summary[uid]
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"
@@ -13,15 +13,28 @@ require 'google/api_client/auth/storages/file_store'
13
13
  require 'launchy'
14
14
  require "socket"
15
15
 
16
- class Net::SMTP
17
- def auth_xoauth2(user, secret)
18
- check_auth_args user, secret
19
- res = critical {
20
- s = Net::IMAP::XOauth2Authenticator.new(user, secret).process("")
21
- get_response('AUTH XOAUTH2 ' + base64_encode(s))
22
- }
23
- check_auth_response res
24
- res
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|
@@ -1,3 +1,3 @@
1
1
  module Mournmail
2
- VERSION = "1.0.3"
2
+ VERSION = "1.0.5"
3
3
  end
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 "html2text"
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.3
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: 2022-09-29 00:00:00.000000000 Z
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: html2text
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.4.0.dev
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: []