heathrow 0.7.6 → 0.7.7
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/lib/heathrow/database.rb +2 -2
- data/lib/heathrow/ui/application.rb +102 -3
- data/lib/heathrow/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d7c8e6773f02f56ba4ac097d508bafaf526e2aed3bb327220614640d5c1bc3bd
|
|
4
|
+
data.tar.gz: 78db591713e7d944436a7c797c7099f337e5050bd4bce8689b38637330665056
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c7b866bfaaf9c2f2edd272be1950fd1730d0e40df9500779dbc51fa8f166e9a149472edd7b1099eea0ece4b713b62201e010cd165161c1a8a0f15725400a00ec
|
|
7
|
+
data.tar.gz: b1bde82078786c429268cf54cce8bef68de0ef03368612e90414c9b484e76181fe3aba59e1157daa7808c968128c750e565d273ea4c30044fa19a847314d76fb
|
data/lib/heathrow/database.rb
CHANGED
|
@@ -375,9 +375,9 @@ module Heathrow
|
|
|
375
375
|
# Handle sender pattern (supports regex via pipe separation)
|
|
376
376
|
if filters[:sender_pattern]
|
|
377
377
|
patterns = filters[:sender_pattern].split('|')
|
|
378
|
-
conditions = patterns.map { "sender LIKE ?" }.join(' OR ')
|
|
378
|
+
conditions = patterns.map { "(sender LIKE ? OR sender_name LIKE ?)" }.join(' OR ')
|
|
379
379
|
query += " AND (#{conditions})"
|
|
380
|
-
|
|
380
|
+
patterns.each { |p| params += ["%#{p}%", "%#{p}%"] }
|
|
381
381
|
end
|
|
382
382
|
|
|
383
383
|
# Handle subject pattern
|
|
@@ -835,6 +835,8 @@ module Heathrow
|
|
|
835
835
|
label_message
|
|
836
836
|
when 'v'
|
|
837
837
|
view_attachments
|
|
838
|
+
when 'Z'
|
|
839
|
+
open_in_timely
|
|
838
840
|
when 'I'
|
|
839
841
|
ai_assistant
|
|
840
842
|
when 'V'
|
|
@@ -1395,6 +1397,7 @@ module Heathrow
|
|
|
1395
1397
|
when 'latest' then 'Latest'
|
|
1396
1398
|
when 'alphabetical' then 'A-Z'
|
|
1397
1399
|
when 'sender' then 'Sender'
|
|
1400
|
+
when 'from' then 'From'
|
|
1398
1401
|
when 'unread' then 'Unread'
|
|
1399
1402
|
when 'source' then 'Source'
|
|
1400
1403
|
else @sort_order.capitalize
|
|
@@ -2997,6 +3000,83 @@ module Heathrow
|
|
|
2997
3000
|
(msg['content'] && msg['content'] =~ /\A\s*<(!DOCTYPE|html|head|body)\b/i)
|
|
2998
3001
|
end
|
|
2999
3002
|
|
|
3003
|
+
def open_in_timely
|
|
3004
|
+
msg = current_message
|
|
3005
|
+
return unless msg
|
|
3006
|
+
msg = ensure_full_message(msg)
|
|
3007
|
+
|
|
3008
|
+
# Try to find a date from calendar data or message timestamp
|
|
3009
|
+
timely_home = File.expand_path('~/.timely')
|
|
3010
|
+
return set_feedback("Timely not configured (~/.timely missing)", 196, 3) unless File.directory?(timely_home)
|
|
3011
|
+
|
|
3012
|
+
# Check for ICS attachment or inline calendar data
|
|
3013
|
+
date_str = nil
|
|
3014
|
+
meta = msg['metadata']
|
|
3015
|
+
meta = JSON.parse(meta) if meta.is_a?(String) rescue nil
|
|
3016
|
+
file = meta['maildir_file'] if meta.is_a?(Hash)
|
|
3017
|
+
|
|
3018
|
+
if file && File.exist?(file)
|
|
3019
|
+
begin
|
|
3020
|
+
require 'mail'
|
|
3021
|
+
mail = Mail.read(file)
|
|
3022
|
+
if mail.multipart?
|
|
3023
|
+
mail.parts.each do |part|
|
|
3024
|
+
ct = (part.content_type || '').downcase
|
|
3025
|
+
if ct.include?('calendar') || ct.include?('ics')
|
|
3026
|
+
ics = part.decoded
|
|
3027
|
+
vevent = ics[/BEGIN:VEVENT(.*?)END:VEVENT/m, 1]
|
|
3028
|
+
if vevent
|
|
3029
|
+
vevent = vevent.gsub(/\r?\n[ \t]/, '')
|
|
3030
|
+
if vevent =~ /^DTSTART;TZID=[^:]*:(\d{8})/i ||
|
|
3031
|
+
vevent =~ /^DTSTART:(\d{8})/i ||
|
|
3032
|
+
vevent =~ /^DTSTART;VALUE=DATE:(\d{8})/i
|
|
3033
|
+
d = $1
|
|
3034
|
+
date_str = "#{d[0,4]}-#{d[4,2]}-#{d[6,2]}"
|
|
3035
|
+
end
|
|
3036
|
+
end
|
|
3037
|
+
break
|
|
3038
|
+
end
|
|
3039
|
+
end
|
|
3040
|
+
end
|
|
3041
|
+
rescue => e
|
|
3042
|
+
# Fall through to timestamp
|
|
3043
|
+
end
|
|
3044
|
+
end
|
|
3045
|
+
|
|
3046
|
+
# Fallback: use message timestamp
|
|
3047
|
+
unless date_str
|
|
3048
|
+
ts = msg['timestamp'].to_i
|
|
3049
|
+
date_str = Time.at(ts).strftime('%Y-%m-%d') if ts > 0
|
|
3050
|
+
end
|
|
3051
|
+
|
|
3052
|
+
return set_feedback("Could not determine date for Timely", 245, 2) unless date_str
|
|
3053
|
+
|
|
3054
|
+
# Write goto file for Timely
|
|
3055
|
+
File.write(File.join(timely_home, 'goto'), date_str)
|
|
3056
|
+
|
|
3057
|
+
# Also copy ICS to incoming if it has calendar data
|
|
3058
|
+
if file && File.exist?(file)
|
|
3059
|
+
begin
|
|
3060
|
+
incoming = File.join(timely_home, 'incoming')
|
|
3061
|
+
FileUtils.mkdir_p(incoming)
|
|
3062
|
+
require 'mail'
|
|
3063
|
+
mail = Mail.read(file)
|
|
3064
|
+
mail.parts.each do |part|
|
|
3065
|
+
ct = (part.content_type || '').downcase
|
|
3066
|
+
if ct.include?('calendar') || ct.include?('ics')
|
|
3067
|
+
ics_file = File.join(incoming, "heathrow_#{msg['id']}.ics")
|
|
3068
|
+
File.write(ics_file, part.decoded) unless File.exist?(ics_file)
|
|
3069
|
+
break
|
|
3070
|
+
end
|
|
3071
|
+
end
|
|
3072
|
+
rescue => e
|
|
3073
|
+
# Non-fatal
|
|
3074
|
+
end
|
|
3075
|
+
end
|
|
3076
|
+
|
|
3077
|
+
set_feedback("Sent to Timely: #{date_str}", 156, 0)
|
|
3078
|
+
end
|
|
3079
|
+
|
|
3000
3080
|
def open_message_external
|
|
3001
3081
|
msg = current_message
|
|
3002
3082
|
return unless msg
|
|
@@ -5819,7 +5899,7 @@ module Heathrow
|
|
|
5819
5899
|
['%d %b %H:%M', 'DD Mon HH:MM'],
|
|
5820
5900
|
['%b %d %H:%M', 'Mon DD HH:MM']
|
|
5821
5901
|
]
|
|
5822
|
-
sort_orders = ['latest', 'alphabetical', 'sender', 'conversation', 'unread', 'source']
|
|
5902
|
+
sort_orders = ['latest', 'alphabetical', 'sender', 'from', 'conversation', 'unread', 'source']
|
|
5823
5903
|
border_labels = ['none', 'right', 'both', 'left']
|
|
5824
5904
|
# Build view choices: A, N, plus any user-defined views
|
|
5825
5905
|
view_choices = [['A', 'All'], ['N', 'New/Unread']]
|
|
@@ -6249,11 +6329,12 @@ module Heathrow
|
|
|
6249
6329
|
end
|
|
6250
6330
|
|
|
6251
6331
|
def cycle_sort_order
|
|
6252
|
-
# Cycle through: latest -> alphabetical -> sender -> conversation -> unread -> source -> latest
|
|
6332
|
+
# Cycle through: latest -> alphabetical -> sender -> from -> conversation -> unread -> source -> latest
|
|
6253
6333
|
@sort_order = case @sort_order
|
|
6254
6334
|
when 'latest' then 'alphabetical'
|
|
6255
6335
|
when 'alphabetical' then 'sender'
|
|
6256
|
-
when 'sender' then '
|
|
6336
|
+
when 'sender' then 'from'
|
|
6337
|
+
when 'from' then 'conversation'
|
|
6257
6338
|
when 'conversation' then 'unread'
|
|
6258
6339
|
when 'unread' then 'source'
|
|
6259
6340
|
else 'latest' # This handles 'source' and any other value
|
|
@@ -6391,6 +6472,24 @@ module Heathrow
|
|
|
6391
6472
|
end
|
|
6392
6473
|
end
|
|
6393
6474
|
end
|
|
6475
|
+
when 'from'
|
|
6476
|
+
# Group by sender, most recently active sender first
|
|
6477
|
+
# Within each sender group, newest message first
|
|
6478
|
+
latest_per_sender = {}
|
|
6479
|
+
@filtered_messages.each do |m|
|
|
6480
|
+
s = display_sender(m).downcase
|
|
6481
|
+
t = ts_cache[m.object_id] || Time.at(0)
|
|
6482
|
+
latest_per_sender[s] = t if !latest_per_sender[s] || t > latest_per_sender[s]
|
|
6483
|
+
end
|
|
6484
|
+
@filtered_messages.sort! do |a, b|
|
|
6485
|
+
sa = display_sender(a).downcase
|
|
6486
|
+
sb = display_sender(b).downcase
|
|
6487
|
+
if sa == sb
|
|
6488
|
+
(ts_cache[b.object_id] || Time.at(0)) <=> (ts_cache[a.object_id] || Time.at(0))
|
|
6489
|
+
else
|
|
6490
|
+
(latest_per_sender[sb] || Time.at(0)) <=> (latest_per_sender[sa] || Time.at(0))
|
|
6491
|
+
end
|
|
6492
|
+
end
|
|
6394
6493
|
when 'unread'
|
|
6395
6494
|
# Sort by unread first, then by timestamp
|
|
6396
6495
|
@filtered_messages.sort! do |a, b|
|
data/lib/heathrow/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: heathrow
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.7.
|
|
4
|
+
version: 0.7.7
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Geir Isene
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2026-03-
|
|
12
|
+
date: 2026-03-24 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: rcurses
|