Commit Graph

528 Commits

Author SHA1 Message Date
Reto Brunner a755608ef9 Abort if accounts.conf is world readable
Fixes #32
2019-05-16 15:02:13 -04:00
Drew DeVault ce0d0e887c Improve reply-all recipient enumeration strategy 2019-05-16 14:16:45 -04:00
Drew DeVault 5701b6e949 Decode email when reading it for quoting 2019-05-16 14:09:57 -04:00
Drew DeVault 08855f23ec Change default bindings for replies 2019-05-16 14:06:33 -04:00
Drew DeVault 7f97e0b605 Don't prefix Re: if prefix already present 2019-05-16 12:42:46 -04:00
Drew DeVault e367469e1a Change default reply keybindings 2019-05-16 12:42:25 -04:00
Drew DeVault 8be59cae6c Implement :reply -q and :reply -a 2019-05-16 12:39:22 -04:00
Drew DeVault 475b697bdf Implement (basic form) of :reply 2019-05-16 12:15:34 -04:00
Drew DeVault 2b3e123cb8 Let caller pass in custom headers to compose 2019-05-16 10:49:50 -04:00
Drew DeVault b0bf09b98f Copy sent emails to the Sent folder
Or rather, to a user-specified folder
2019-05-15 19:41:21 -04:00
Drew DeVault 52b318127f Fix default bindings for quit and edit 2019-05-14 19:18:33 -04:00
Drew DeVault 67ddaea1b2 Move ! bind to [messages] 2019-05-14 17:06:31 -04:00
Drew DeVault 6c0359670c Add (non-functional) reply commands to bindings 2019-05-14 17:04:21 -04:00
Drew DeVault d3fe60a0fa Add ! to default keybindings 2019-05-14 16:57:10 -04:00
Drew DeVault 2e5ae1946b Implement move, mv commands 2019-05-14 16:55:50 -04:00
Drew DeVault 07138146a0 Force INBOX to be included in dirlist 2019-05-14 16:53:47 -04:00
Drew DeVault db213fd0ae Implement :copy (aka :cp) 2019-05-14 16:44:59 -04:00
Cole Helbling b0b3287bbd Implement abort command
This allows the user to close the compose tab without sending their
current composition.
2019-05-14 16:21:45 -04:00
Drew DeVault 2c486cb7f5 Update tab name as subject changes
Also moves truncation to the tab widget
2019-05-14 16:18:59 -04:00
Drew DeVault 065da5e372 Add $EDITOR, internal config for compose 2019-05-14 15:25:30 -04:00
Drew DeVault 9b2612eaf2 Add IRC link to README.md 2019-05-14 14:47:46 -04:00
Drew DeVault 254e6fe73f Remove tab before going async
To prevent repeated attempts to send
2019-05-14 14:29:50 -04:00
Drew DeVault f77d7c2c3d Add distinct keybindings for each compose view 2019-05-14 14:27:28 -04:00
Drew DeVault 928ac1bcd9 Send emails asyncronously 2019-05-14 14:18:01 -04:00
Drew DeVault 29de3297a1 Implement sending emails /o/ 2019-05-14 14:07:27 -04:00
Drew DeVault 6c36e04c1f Add :send-message, prepares & writes email to /tmp 2019-05-14 13:07:48 -04:00
Drew DeVault d5e82ecfe0 Remove leftover debug logging 2019-05-13 20:24:04 -04:00
Drew DeVault 3ace4ef732 Handle external message deletions 2019-05-13 20:23:23 -04:00
Drew DeVault 026e8a17ca Handle incoming emails gracefully 2019-05-13 20:16:55 -04:00
Drew DeVault bb46b2b7e1 Spec out review message screen 2019-05-13 16:53:02 -04:00
Drew DeVault 17bd2dc4db Populate "From" header from config for new emails 2019-05-13 16:04:01 -04:00
Drew DeVault bda74452a8 Add outgoing account configuration 2019-05-12 23:35:36 -04:00
Drew DeVault f37508a539 Implement :{next,prev}-field in compose view 2019-05-12 11:21:28 -04:00
Drew DeVault 2a4dd5cb87 Expand compose focus handling a bit 2019-05-12 00:38:48 -04:00
Drew DeVault 577248f5e1 Add initial compose widget 2019-05-12 00:06:09 -04:00
Drew DeVault c05e5f73f2 Move aerc to dedicated mailing list 2019-05-11 14:31:11 -04:00
Drew DeVault 71c13c9078 "Press any key to close" for completed processes 2019-05-11 14:15:29 -04:00
Drew DeVault 72e4b5e2b2 Refactor ctx stashing out of exline 2019-05-11 13:20:29 -04:00
Drew DeVault 8fa4583230 Split ex line text handling into dedicated widget 2019-05-11 13:12:44 -04:00
Simon Ser de122b16ee lib/ui: fix UI.Exit race condition
UI.Exit can be accessed from goroutines drawing, goroutines executing
commands and goroutines waiting for events.

    Write at 0x00c0002b2040 by main goroutine:
      main.main.func1()
          /home/simon/src/aerc2/aerc.go:76 +0x33d
      git.sr.ht/~sircmpwn/aerc2/widgets.(*Aerc).BeginExCommand.func1()
          /home/simon/src/aerc2/widgets/aerc.go:245 +0x89
      git.sr.ht/~sircmpwn/aerc2/widgets.(*ExLine).Event()
          /home/simon/src/aerc2/widgets/exline.go:131 +0x442
      git.sr.ht/~sircmpwn/aerc2/widgets.(*Aerc).Event()
          /home/simon/src/aerc2/widgets/aerc.go:116 +0x83c
      git.sr.ht/~sircmpwn/aerc2/widgets.(*Aerc).simulate()
          /home/simon/src/aerc2/widgets/aerc.go:109 +0x12a
      git.sr.ht/~sircmpwn/aerc2/widgets.(*Aerc).Event()
          /home/simon/src/aerc2/widgets/aerc.go:142 +0x722
      git.sr.ht/~sircmpwn/aerc2/lib/ui.(*UI).Tick()
          /home/simon/src/aerc2/lib/ui/ui.go:75 +0x33f
      main.main()
          /home/simon/src/aerc2/aerc.go:94 +0x497

    Previous read at 0x00c0002b2040 by goroutine 19:
      git.sr.ht/~sircmpwn/aerc2/lib/ui.Initialize.func1()
          /home/simon/src/aerc2/lib/ui/ui.go:45 +0x97

    Goroutine 19 (running) created at:
      git.sr.ht/~sircmpwn/aerc2/lib/ui.Initialize()
          /home/simon/src/aerc2/lib/ui/ui.go:44 +0x372
      main.main()
          /home/simon/src/aerc2/aerc.go:87 +0x3a9
2019-05-05 01:07:44 -04:00
Simon Ser 5feb7dede9 lib/ui: fix Grid race condition
This was is more complicated than others. The cells list is accessed by
multiple goroutines:

- Some change the Grid's contents via AddChild/RemoveChild
- Some call Draw
- Some invalidate the grid via Invalidate

Invalidate calls are tricky to handle because they will also invalidate all
child cells. This will inturn trigger the cellInvalidated callback, which needs
to read the list of cells.

For this reason, we use a sync.RWLock which allows multiple concurrent reads.

Below is the race fixed by this commit.

    Read at 0x00c0000bc3d0 by goroutine 7:
      git.sr.ht/~sircmpwn/aerc2/lib/ui.(*Grid).cellInvalidated()
          /home/simon/src/aerc2/lib/ui/grid.go:181 +0x45
      git.sr.ht/~sircmpwn/aerc2/lib/ui.(*Grid).cellInvalidated-fm()
          /home/simon/src/aerc2/lib/ui/grid.go:179 +0x55
      git.sr.ht/~sircmpwn/aerc2/lib/ui.(*Invalidatable).DoInvalidate()
          /home/simon/src/aerc2/lib/ui/invalidatable.go:22 +0x85
      git.sr.ht/~sircmpwn/aerc2/lib/ui.(*Bordered).contentInvalidated-fm()
          /home/simon/src/aerc2/lib/ui/borders.go:39 +0x56
      git.sr.ht/~sircmpwn/aerc2/lib/ui.(*Invalidatable).DoInvalidate()
          /home/simon/src/aerc2/lib/ui/invalidatable.go:22 +0x85
      git.sr.ht/~sircmpwn/aerc2/widgets.NewDirectoryList.func1()
          /home/simon/src/aerc2/widgets/dirlist.go:81 +0x55
      git.sr.ht/~sircmpwn/aerc2/lib/ui.(*Invalidatable).DoInvalidate()
          /home/simon/src/aerc2/lib/ui/invalidatable.go:22 +0x85
      git.sr.ht/~sircmpwn/aerc2/widgets.(*Spinner).Start.func1()
          /home/simon/src/aerc2/widgets/spinner.go:88 +0x82

    Previous write at 0x00c0000bc3d0 by main goroutine:
      [failed to restore the stack]

    Goroutine 7 (running) created at:
      git.sr.ht/~sircmpwn/aerc2/widgets.(*Spinner).Start()
          /home/simon/src/aerc2/widgets/spinner.go:46 +0x98
      git.sr.ht/~sircmpwn/aerc2/widgets.NewDirectoryList()
          /home/simon/src/aerc2/widgets/dirlist.go:37 +0x28b
      git.sr.ht/~sircmpwn/aerc2/widgets.NewAccountView()
          /home/simon/src/aerc2/widgets/account.go:49 +0x5ca
      git.sr.ht/~sircmpwn/aerc2/widgets.NewAerc()
          /home/simon/src/aerc2/widgets/aerc.go:60 +0x807
      main.main()
          /home/simon/src/aerc2/aerc.go:65 +0x33e
2019-05-05 01:06:39 -04:00
Simon Ser a275f65848 lib/msgstore: protect with a mutex
MessageStore has a lot of exported fields that can be read from the outside.
Each read must be protected, because a call from Update could happen at any
time.
2019-04-29 09:49:48 -04:00
Simon Ser f1698a337e widgets/msglist: fix MessageList.store race
This field could be written to in the middle of a Draw call, which reads it
multiple times. Use an atomic variable instead.
2019-04-29 09:49:39 -04:00
Simon Ser 089740758c worker/imap: use the IMAP connection from a single goroutine
Unfortunately, the IMAP protocol hasn't been designed to be used from multiple
goroutines at the same time. For instance, if you fetch twice the same message
from two different goroutines, it's not possible to tell whether the response
is for one receiver or the other. For this reason, go-imap clients aren't safe
to use from multiple goroutines.

This commit changes the IMAP workers to be synchronous again (a command is
executed only after the previous one has completed). To use IMAP from different
threads, popular clients (e.g. Thunderbird) typically open multiple
connections.
2019-04-29 09:49:22 -04:00
Simon Ser 072bc26872 Update go-imap to 1.0.0-beta.4
This release contains race conditions fixes.
2019-04-29 09:29:41 -04:00
Simon Ser 335db0402d lib/ui: fix GridCell.invalid race
This is read/written from different goroutines.

    Write at 0x00c00009c6f0 by goroutine 7:
      git.sr.ht/~sircmpwn/aerc2/lib/ui.(*Grid).cellInvalidated()
          /home/simon/src/aerc2/lib/ui/grid.go:189 +0x122
      git.sr.ht/~sircmpwn/aerc2/lib/ui.(*Grid).cellInvalidated-fm()
          /home/simon/src/aerc2/lib/ui/grid.go:178 +0x55
      git.sr.ht/~sircmpwn/aerc2/lib/ui.(*Invalidatable).DoInvalidate()
          /home/simon/src/aerc2/lib/ui/invalidatable.go:22 +0x85
      git.sr.ht/~sircmpwn/aerc2/lib/ui.(*Bordered).contentInvalidated-fm()
          /home/simon/src/aerc2/lib/ui/borders.go:39 +0x56
      git.sr.ht/~sircmpwn/aerc2/lib/ui.(*Invalidatable).DoInvalidate()
          /home/simon/src/aerc2/lib/ui/invalidatable.go:22 +0x85
      git.sr.ht/~sircmpwn/aerc2/widgets.NewDirectoryList.func1()
          /home/simon/src/aerc2/widgets/dirlist.go:81 +0x55
      git.sr.ht/~sircmpwn/aerc2/lib/ui.(*Invalidatable).DoInvalidate()
          /home/simon/src/aerc2/lib/ui/invalidatable.go:22 +0x85
      git.sr.ht/~sircmpwn/aerc2/widgets.(*Spinner).Start.func1()
          /home/simon/src/aerc2/widgets/spinner.go:88 +0x82

    Previous write at 0x00c00009c6f0 by main goroutine:
      [failed to restore the stack]

    Goroutine 7 (running) created at:
      git.sr.ht/~sircmpwn/aerc2/widgets.(*Spinner).Start()
          /home/simon/src/aerc2/widgets/spinner.go:46 +0x98
      git.sr.ht/~sircmpwn/aerc2/widgets.NewDirectoryList()
          /home/simon/src/aerc2/widgets/dirlist.go:37 +0x28b
      git.sr.ht/~sircmpwn/aerc2/widgets.NewAccountView()
          /home/simon/src/aerc2/widgets/account.go:49 +0x5ca
      git.sr.ht/~sircmpwn/aerc2/widgets.NewAerc()
          /home/simon/src/aerc2/widgets/aerc.go:60 +0x807
      main.main()
          /home/simon/src/aerc2/aerc.go:65 +0x33e
2019-04-29 09:29:37 -04:00
Simon Ser 5685a17674 lib/ui: introduce Invalidatable
Many Drawable implementations have their own Invalidate and OnInvalidate
functions, with an unexported onInvalidate field. However OnInvalidate and
Invalidate are usually not called in the same goroutine. This results in a race
on this field, e.g.:

    Read at 0x00c000094748 by goroutine 7:
      git.sr.ht/~sircmpwn/aerc2/widgets.NewDirectoryList.func1()
          /home/simon/src/aerc2/widgets/dirlist.go:85 +0x56
      git.sr.ht/~sircmpwn/aerc2/widgets.(*Spinner).Start.func1()
          /home/simon/src/aerc2/widgets/spinner.go:93 +0x1bb

    Previous write at 0x00c000094748 by main goroutine:
      [failed to restore the stack]

    Goroutine 7 (running) created at:
      git.sr.ht/~sircmpwn/aerc2/widgets.(*Spinner).Start()
          /home/simon/src/aerc2/widgets/spinner.go:46 +0x8f
      git.sr.ht/~sircmpwn/aerc2/widgets.NewDirectoryList()
          /home/simon/src/aerc2/widgets/dirlist.go:37 +0x286
      git.sr.ht/~sircmpwn/aerc2/widgets.NewAccountView()
          /home/simon/src/aerc2/widgets/account.go:50 +0x5ca
      git.sr.ht/~sircmpwn/aerc2/widgets.NewAerc()
          /home/simon/src/aerc2/widgets/aerc.go:60 +0x800
      main.main()
          /home/simon/src/aerc2/aerc.go:65 +0x33e

To fix this, introduce a new type, Invalidatable, which protects the field.
Unfortunately the Drawable must be passed to the callback function in
Invalidate, so we still need to re-implement this in each Invalidatable user.
2019-04-27 14:30:28 -04:00
Simon Ser 9ef2a57b51 worker/types: fix Worker.Callbacks race condition
Worker.Process* functions were called in different goroutines than
Worker.Post*. Protect the map with a mutex. Also make the map unexported to
prevent external unprotected accesses.

Worker.Process* functions used to delete items from the map. However they
didn't delete the element they retrieved: callbacks[msg.InResponseTo()] was
read while callbacks[msg] was deleted. I'm not sure I understand why. I tried
to delete the element that was accessed - but this broke everything (UI froze
at "Connecting..."). I don't believe any elements were actually removed from
the map, so the new code just doesn't remove anything.
2019-04-27 14:28:26 -04:00
Simon Ser 2159eb876e widgets/spinner: fix Spinner.frame race
It's accessed by the goroutine which increments it and the goroutine that draws
the widget at the same time. Use atomic instead.

    Write at 0x00c00000ebc0 by goroutine 7:
      git.sr.ht/~sircmpwn/aerc2/widgets.(*Spinner).Start.func1()
          /home/simon/src/aerc2/widgets/spinner.go:50 +0x169

    Previous read at 0x00c00000ebc0 by main goroutine:
      [failed to restore the stack]

    Goroutine 7 (running) created at:
      git.sr.ht/~sircmpwn/aerc2/widgets.(*Spinner).Start()
          /home/simon/src/aerc2/widgets/spinner.go:44 +0x8b
      git.sr.ht/~sircmpwn/aerc2/widgets.NewDirectoryList()
          /home/simon/src/aerc2/widgets/dirlist.go:37 +0x286
      git.sr.ht/~sircmpwn/aerc2/widgets.NewAccountView()
          /home/simon/src/aerc2/widgets/account.go:50 +0x5ca
      git.sr.ht/~sircmpwn/aerc2/widgets.NewAerc()
          /home/simon/src/aerc2/widgets/aerc.go:60 +0x800
      main.main()
          /home/simon/src/aerc2/aerc.go:65 +0x33e
2019-04-27 11:42:12 -04:00
Elias Naur e72574c308 go get git.sr.ht/~sircmpwn/go-libvterm
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2019-04-21 16:17:40 -04:00