mournmail 1.0.4 → 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ae379bf40c63688588064eaabc9eebdbff4c393be7ecf8ece7fb882417b0497b
4
- data.tar.gz: 1264ad23254aca9c1550f2f568aac09e298867a7573ad05ddc045e324af0b48b
3
+ metadata.gz: ebc2414b32ab7005cc39801155dcfe26eb1381026a7750b80c28ae84db63dae0
4
+ data.tar.gz: 464beaa7109d55c1730baad310ac064974cf902fd43281c936721587edd175fc
5
5
  SHA512:
6
- metadata.gz: 99fe3e9ef1651a1acfb06aa2ce210e7e4342a73f51781c82ab28d8d1a1d940e4233eef8e0ae66d7663dbc14917e121a5d3c268b26ff1ff9a8372bb190c3ab19f
7
- data.tar.gz: 324f77413cf03ddbb281edfabd881dabd97134d6b01c83c81f6560c802dd1c19f66827d391c0779890cbd96d2b8682431b15070f5a2ac745712dc6027abf4f39
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.
@@ -54,4 +54,15 @@ module Textbringer
54
54
  "ppt",
55
55
  "zip"
56
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
+ )
57
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
@@ -262,6 +262,7 @@ module Mournmail
262
262
  width = 0
263
263
  str = +""
264
264
  s.each_char do |c|
265
+ next if c == "\n"
265
266
  w = Buffer.display_width(c)
266
267
  width += w
267
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.4"
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.4
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-11-18 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: []