Commit graph

1409 commits

Author SHA1 Message Date
Tim Culverhouse
fb5558da81 seqmap: sync seqNum to uid after expunge
This patch updates the seqNums after an Expunge operation. When an
expunge operation occurs, the seqNum of the deleted message is reported.
The Imap spec [0] states that an immediate decrement of all seqnums greater
than the deleted occurs, even before the next reporting of an expunge
update.

[0]: https://datatracker.ietf.org/doc/html/rfc3501#section-7.4.1

Fixes: https://todo.sr.ht/~rjarry/aerc/61
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Signed-off-by: Robin Jarry <robin@jarry.cc>
2022-07-24 23:06:10 +02:00
Tim Culverhouse
9bfcec5660 delete: select new last message if last message was deleted
If the last message is deleted, the new selection should be the last
message instead of the first message.

Fixes: https://todo.sr.ht/~rjarry/aerc/59
Reported-by: Sebastien Binet <s@sbinet.org>
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-07-24 23:05:53 +02:00
Tim Culverhouse
80f8bab6cf delete: move tab replace logic into Done callback
Move tab replacement logic for next-message-on-delete into the
callback. This also moves the Invalidate() call into the callback, and
should make imap deletion UI work more reliably - there is a race
condition between the worker and the UI in displaying deleted messages.
This should resolve the race condition, and also only remove the MsgView
tab if the message is actually deleted.

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-07-24 23:05:11 +02:00
akspecs
0f86666f52 msgstore: check if message index < 0, select 0 if so
Calling :prev without this check can cause the index to go below 0 if
the current index is smaller than the value being scrolled / incremented
by. This results in the email selector wrapping around from the top to
the bottom most email in the mailbox folder due to changes in ec150f0
'store: fix Select behaviour'.

Signed-off-by: akspecs <akspecs@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-07-24 23:05:07 +02:00
Tim Culverhouse
4036f696ad msgstore: refactor NextPrev
Refactor NextPrev to use already existing selection methods and bounds
checking

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-07-24 23:05:00 +02:00
Tim Culverhouse
f8e6478d46 store: fix Select behavior
Fix the behavior of the Select(index int) method to select the last
message if an index > len(list) or select from bottom of list for
negative indexes.

Thanks: akspecs <akspecs@gmail.com>
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-07-24 23:04:52 +02:00
Robin Jarry
9203c4b6ef logging: print init procedure and config contents
This may help debugging issues.

Signed-off-by: Robin Jarry <robin@jarry.cc>
Acked-by: Moritz Poldrack <moritz@poldrack.dev>
2022-07-23 22:52:20 +02:00
Robin Jarry
cd19995557 logging: use level-based logger functions
Do not pass logger objects around anymore. Shuffle some messages to make
them consistent with the new logging API. Avoid using %v when a more
specific verb exists for the argument types.

The loggers are completely disabled (i.e. Sprintf is not even called)
by default. They are only enabled when redirecting stdout to a file.

Signed-off-by: Robin Jarry <robin@jarry.cc>
Acked-by: Moritz Poldrack <moritz@poldrack.dev>
2022-07-23 22:52:15 +02:00
Robin Jarry
a1f779ccc9 logging: add logger system with levels
The built-in logging system is rather basic. Implement a multi-level
logger to ease interpreting the logs. Configure the loggers with
prefixes and microsecond precision for timestamps.

Also, prefix the messages with the source file name and line number.
Because of this, enabling the logs has a performance cost. They will
only be enabled when redirecting aerc stdout to a file.

Here is an example output:

DEBUG 2022/07/20 12:52:34.536190 worker.go:45: PostAction *types.FetchDirectoryContents
DEBUG 2022/07/20 12:52:34.536329 worker.go:92: ProcessAction *types.FetchDirectoryContents(2417)
DEBUG 2022/07/20 12:52:34.536407 idler.go:159: idler (0xc00017c000) [idle:false,wait:false] =>(idle) [debounce]
INFO  2022/07/20 12:52:34.536432 threadbuilder.go:59: 130 threads created in 220.796µs
DEBUG 2022/07/20 12:52:34.536449 worker.go:75: ProcessMessage *types.DirectoryInfo(2416)
DEBUG 2022/07/20 12:52:34.536453 idler.go:159: idler (0xc00017c000) [idle:false,wait:false] <=(idle)
DEBUG 2022/07/20 12:52:34.536459 worker.go:45: PostAction *types.FetchDirectoryContents
INFO  2022/07/20 12:52:34.536470 open.go:30: Fetching UID list
INFO  2022/07/20 12:52:34.536689 threadbuilder.go:59: 130 threads created in 201.635µs

Signed-off-by: Robin Jarry <robin@jarry.cc>
Acked-by: Moritz Poldrack <moritz@poldrack.dev>
2022-07-23 22:52:10 +02:00
Robin Jarry
b188f19131 imap: disable debug logger
This causes all raw email bodies to be dumped along with actual
debugging messages. I don't believe we neither need nor want such
a thing.

Signed-off-by: Robin Jarry <robin@jarry.cc>
Acked-by: Moritz Poldrack <moritz@poldrack.dev>
2022-07-23 22:37:08 +02:00
Robin Jarry
b8bb2a6ac1 Add git mailmap
Some contributors use multiple email addresses and/or invalid email
addresses. Add a .mailmap file to de-duplicate and fix contributors
names with git shortlog.

Signed-off-by: Robin Jarry <robin@jarry.cc>
2022-07-23 22:07:04 +02:00
Robin Jarry
6504faa88c release.sh: fine tuning
Shuffle the To/Cc/Bcc headers to avoid people from doing reply all to
~sircmpwn/aerc@lists.sr.ht. Also add Cc: aerc-devel so that the lists
archives all have the base message. Unfortunately, there is no way to
prevent people from doing reply all and trying to send emails to
aerc-announce. Putting aerc-announce in Bcc sounds very ugly.

Include the person doing the release as Bcc. sendmail -t does not have
a copy-to=Sent option.

Use base32 and a shorter suffix for Message-ID. base64 is ugly.

Use 'vi' if $EDITOR is unset.

Signed-off-by: Robin Jarry <robin@jarry.cc>
Acked-by: Moritz Poldrack <moritz@poldrack.dev>
2022-07-23 22:06:44 +02:00
Robin Jarry
050d54a822 tabs: make it more thread safe
Protect the access to the tabs array and current index with a mutex.

Signed-off-by: Robin Jarry <robin@jarry.cc>
Acked-by: Koni Marti <koni.marti@gmail.com>
2022-07-23 22:00:29 +02:00
Robin Jarry
171fefd209 tabs: make fields private
The Tabs object exposes an array of Tab objects and the current selected
index in that array. The these two fields are sometimes modified in
goroutines, which can lead to data races causing fatal out of bounds
accesses on the tab array.

Hide these fields as private API. Expose only what needs to be seen from
the outside. This will prepare for protecting concurrent access with
a lock in the next commit.

Signed-off-by: Robin Jarry <robin@jarry.cc>
Acked-by: Koni Marti <koni.marti@gmail.com>
2022-07-23 22:00:25 +02:00
Robin Jarry
c841f36513 tabs: rename SelectedTab to SelectedTabContent
This function returns an ui.Drawable. Use a more explicit name. This
prepares for adding a new SelectedTab function which will return
an ui.Tab.

Signed-off-by: Robin Jarry <robin@jarry.cc>
Acked-by: Koni Marti <koni.marti@gmail.com>
2022-07-23 22:00:21 +02:00
Jose Lombera
c49a065496 msgviewer: cleanup PartSwitcher on :toggle-headers
Cleanup existing PartSwitcher before recreating a new one when command
:toggle-headers is executed, ensuring existing part pagers are cleaned
up.  This fixes a leak in pager processes when :toggle-headers is
executed repeatedly without closing the message.

Signed-off-by: Jose Lombera <jose@lombera.dev>
Acked-by: Koni Marti <koni.marti@gmail.com>
2022-07-23 21:51:52 +02:00
Robin Jarry
5dec1f09b1 imap: fix error when server returns a message without body section
When opening unread emails from certain people (I won't name any names,
sorry), an annoying error message is displayed on the status line:

 could not get section &imap.BodySectionName{BodyPartName:
 imap.BodyPartName{Specifier:"", Path:[]int(nil), Fields:[]string(nil),
 NotFields:false}, Peek:false, Partial:[]int(nil), value}

This does not occur for already read messages. This issue is similar to
the one that was fixed in commit 8ed95b0d2a ("imap: avoid crash when
replying to unread message").

This happens because the flags are updated in the callback that receives
the message itself. It causes the flag update to arrive in the same
channel/request. Ignore the messages that have an empty body (i.e. only
containing flag updates). This is inherently racy but there seems no way
to get rid of these extra messages.

Signed-off-by: Robin Jarry <robin@jarry.cc>
Acked-by: Koni Marti <koni.marti@gmail.com>
2022-07-23 21:51:47 +02:00
Robin Jarry
52f7d3f900 gpg: set a name for the attached pgp signature part
This makes it more explicit for non pgp compatible clients. Without
this, they may show "unnamed part" or "noname".

Signed-off-by: Robin Jarry <robin@jarry.cc>
Acked-by: Moritz Poldrack <moritz@poldrack.dev>
2022-07-18 21:12:46 +02:00
Robin Jarry
011d41de7e doc: fix typos
These were reported by lintian when packaging aerc 0.11.0. There are
probably others.

Signed-off-by: Robin Jarry <robin@jarry.cc>
Acked-by: Moritz Poldrack <moritz@poldrack.dev>
2022-07-18 13:58:27 +02:00
Robin Jarry
3ef4a3ca05 filters: try and make awk scripts posix compliant
\x escape sequences are GNU specific. Use the octal escape code instead.

filters/calendar is beyond help. It would need a complete rewrite to
make it work with POSIX awk.

Signed-off-by: Robin Jarry <robin@jarry.cc>
Acked-by: Moritz Poldrack <moritz@poldrack.dev>
2022-07-18 13:58:21 +02:00
Moritz Poldrack
f642fc9038 Revert "fix panic on closing a tab"
This reverts commit d7feb56cbe.

This commit introduced a regression in which upon closing any but the
last tab caused an out of range panic would occur.

Steps to reproduce
- open a tab
- open another tab
- close the first tab

Fixes: https://todo.sr.ht/~rjarry/aerc/58
Reported-by: akspecs <akspecs@gmail.com>
Signed-off-by: Moritz Poldrack <git@moritz.sh>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-07-18 13:06:59 +02:00
Robin Jarry
5e600d7ab4 binds: fix ctrl-i and ctrl-m key definitions
On all terminals, ctrl-i sends a tab character (0x09). For some reason,
tcell.ModCtrl+tcell.KeyCtrlI is interpreted as ctrl-tab.

Similarly, ctrl-m sends a new line (0x0a) and
tcell.ModCtrl+tcell.KeyCtrlM is interpreted as ctrl-enter.

Remove control modifier for these two key definitions only. All others
do not work without them.

Fixes: 7a6c808c04 ("bindings: prepare for more modifers")
Fixes: https://todo.sr.ht/~rjarry/aerc/56
Signed-off-by: Robin Jarry <robin@jarry.cc>
Acked-by: Moritz Poldrack <moritz@poldrack.dev>
2022-07-17 19:00:47 +02:00
Robin Jarry
db00accb57 config: allow per-account address-book-cmd
When using multiple accounts, the contacts may be different. Allow using
specific address book commands per account.

Signed-off-by: Robin Jarry <robin@jarry.cc>
Acked-by: Moritz Poldrack <moritz@poldrack.dev>
2022-07-17 19:00:44 +02:00
Robin Jarry
f2dac06029 completer: remove useless logger parameter
Report the error to the user directly.

Signed-off-by: Robin Jarry <robin@jarry.cc>
Acked-by: Moritz Poldrack <moritz@poldrack.dev>
2022-07-17 19:00:35 +02:00
Jose Lombera
f5e886406b mk: compute version deterministically
Ensure abbreviated commit id of fixed length in computed version
regardless of user's configuration.  Choose length 12 as safe value.

Link: https://github.com/git/git/commit/dce96489162b
Signed-off-by: Jose Lombera <jose@lombera.dev>
Acked-by: Moritz Poldrack <moritz@poldrack.dev>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-07-17 18:38:40 +02:00
Tim Culverhouse
04097e8743 msgstore: do not build threads when threaded view is off
Commit 3a614e45fc ("threading: enable toggle-threads for server-side
threads") changed the behavior of the msgstore.buildThreads variable to
reflect whether the client needs to build threads or the server will.
However, a call to runThreadbuilder was not updated with an extra
conditional. As a result, threads were built regardless of the state of
the threadedView resulting in a large performance penalty for
non-threaded views with client side threading.

Only run thread builder if threaded view is enabled.

Fixes: 3a614e45fc ("threading: enable toggle-threads for server-side threads")
Reported-by: akspecs <akspecs@gmail.com>
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Akspecs <akspecs@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-07-17 18:35:21 +02:00
Koni Marti
e92573c5d7 lib: fix tests for 386 platforms
Tests in lib/structure_helpers_test.go pass on amd64 platforms but fail
on 386 platforms. This can be reproduced with the following steps:

1. Create a Dockerfile in aerc's source folder:

	FROM i386/alpine:edge

	RUN apk update && apk upgrade
	RUN apk add --no-cache go make scdoc

	WORKDIR aerc

	COPY . .

	RUN make

	CMD make tests

2. Build the image:
	$ docker buildx build --platform=linux/386 -t test .

3. Run the image:
	$ docker run --rm --platform=linux/386 -it test

The test in lib/structure_helpers_test.go will fail.

If the same above steps are done with this patch applied, all tests pass.

Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-07-14 23:15:26 +02:00
Koni Marti
76b39311dc send: enter no-quit mode until message is sent
Protect the sending of a message by entering the no-quit mode. This
prevents aerc from exiting with the :quit command until the operation is
done or the exit is forced.

Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-07-14 23:15:13 +02:00
Koni Marti
e200cd56bf commands: implement a no-quit mode
Add a mode that prevents aerc from quitting normally when an important
task is performed, i.e. when sending a message. The no-quit mode will be
ignored when quit is used with the -f option to force an exit.

Suggested-by: ph14nix[m]
Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-07-14 23:15:02 +02:00
Koni Marti
5102d32cea pipe: use go-mbox for writing multiple messages
Use go-mbox for piping out multiple messages in the mbox format.

Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-07-14 23:14:59 +02:00
Koni Marti
e572087e58 account: import mbox file to a folder
Append all messages from an mbox file to the selected folder with the
import-mbox command.

User confirmation is required when the folder already contains messages.

A failed append will be retried a few times. If a backend timeout
occurs, the entire import is stopped to prevent a hang.

Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-07-14 23:14:56 +02:00
Koni Marti
845763cb1f account: export folder to mbox file
Export all message in the current folder to an mbox file. If an error
occurs during the export, aerc retries a few times before giving up to
prevent a hang.

Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-07-14 23:14:54 +02:00
Koni Marti
c24a576876 aerc: use aerc as an mbox viewer
Use Aerc as an mbox viewer. Open an mbox file from the command line in a
new tab with the mbox backend. Provide a convenient and quick way to
display emails from an mbox.

Usage: aerc mbox://<path>

where the path can either be a directory or an mbox file. If it is a
directory, every file with an .mbox suffix will be loaded as a folder.

The account config will be copied from the selected account. This allows
the answer emails in the mbox account.

Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-07-14 23:14:50 +02:00
Koni Marti
a1a276e002 mbox: implement an mbox backend worker
Implement an mbox backend worker. Worker can be used for testing and
development by mocking a backend for the message store. Worker does not
modify the actual mbox file on disk; all operations are performed in
memory.

To use the mbox backend, create an mbox account in the accounts.conf
where the source uses the "mbox://" scheme, such as

source = mbox://~/mbox/

or

source = mbox://~/mbox/file.mbox

If the mbox source points to a directory, all files in this directory
with the .mbox suffix will be opened as folders.

If an outgoing smtp server is defined for the mbox account, replies can
be sent to emails that are stored in the mbox file.

Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-07-14 23:14:45 +02:00
Robin Jarry
12dec19109 Release version 0.11.0
Signed-off-by: Robin Jarry <robin@jarry.cc>
2022-07-11 21:25:05 +02:00
Robin Jarry
142647d7c9 filters/colorize: use /usr/bin/awk shebang
/bin is reserved for essential commands that may be used when in single
user mode.

Link: https://refspecs.linuxfoundation.org/FHS_3.0/fhs-3.0.html#binEssentialUserCommandBinaries
Signed-off-by: Robin Jarry <robin@jarry.cc>
2022-07-11 21:15:56 +02:00
Tom Schwindl
fc4301113e filters: Add missing shebangs
The hldiff and plaintext filter scripts are missing their shebangs.
Add those to be correct and consistent.
Additionally, remove the vim comment, it's unnecessary.

Signed-off-by: Tom Schwindl <schwindl@posteo.de>
Acked-by: Moritz Poldrack <moritz@poldrack.dev>
2022-07-11 15:53:23 +02:00
Robin Jarry
2eff25e3ea ci: add missing yaml document header
Signed-off-by: Robin Jarry <robin@jarry.cc>
2022-07-11 11:31:33 +02:00
Tim Culverhouse
a953e4dbe9 threading: refactor reselect logic
This patch refactors reselection of a message during certain operations
(searching, filtering, clearing, deleting, moving, new message arrival).
The addition of server-side filtering for threaded views broke the
existing reselection logic.

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-07-10 21:15:12 +02:00
Tim Culverhouse
c2f4404fca threading: enable filtering of server-side threads
This patch enables the filtering of a threaded view which uses
server-built threads. Filtering is done server-side, in order to
preserve the use of server-built threads.

In adding this feature, the filtering of notmuch folders was brought up
to feature parity with the other workers. The filters function the same
(ie: they can be stacked). The notmuch filters, however, still use
notmuch syntax for the filtering.

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-07-10 21:15:12 +02:00
Tim Culverhouse
ccd042889f threading: add force-client-threads option
This patch adds a config option to force the use of client side threads.
This option will override a servers Thread capability, and only build
threads on the client. It can be enabled contextually. For example:

	[ui]
	threading-enabled = true

	[ui:folder~^Archive]
	force-client-threads = true

This config would enable threads for all views, and use client threads
for folders that start with Archive. This can be advantageous if, for
example, the folder is very large and the server has a slow response due
to building threads for the entire mailbox

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-07-10 21:15:12 +02:00
Tim Culverhouse
3a614e45fc threading: enable toggle-threads for server-side threads
Enable the :toggle-threads command to work for workers which have Thread
capability. The implementation of that feature has the side effect that
the threading-enabled config option now sets the default view (threaded
or not threaded) for any worker, not just IMAP or notmuch.

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-07-10 21:15:12 +02:00
Tim Culverhouse
f0c76fad72 threading: add backend capabilities to workers
This patch provides a method to report backend capabilities to the UI.
The intial capabilities included in the report are Sort and Thread.
Having these available to the UI enables the client to better handle
server side threading.

Signed-off-by: Koni Marti <koni.marti@gmail.com>
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-07-10 21:15:12 +02:00
Tim Culverhouse
a8879d79c6 msgstore: remove duplicate calls to store.update
Move and Delete commands perform a store.update() when their worker is
completed and also when the method is called. This patch removes the
call performed in the store.Move and store.Delete methods.

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-07-10 21:15:12 +02:00
Tim Culverhouse
399854c103 statusline: show threading status if threading-enabled=true
Update statusline to display threading status at startup. Previously,
the threading status would only display from a :toggle-threads command.
Users who had the config option threading-enabled would not see the
status, as a result.

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-07-10 21:15:12 +02:00
Moritz Poldrack
d7feb56cbe fix panic on closing a tab
This change fixes a panic caused by the selected tab being out of sync
when selecting a new one in widgets.(*Aerc).SelectedTab(). This happens
if the tab is already removed from the list of tabs, but the selection
not yet being updated.
This was achieved by moving the tabs behind updating the selection.

Signed-off-by: Moritz Poldrack <git@moritz.sh>
Acked-by: Tim Culverhouse <tim@timculverhouse.com>
2022-07-10 21:15:05 +02:00
Koni Marti
aae46c7afd composer: remove header if empty
Remove a header when it is empty.

Commit a253e89bda ("compose: prevent sending empty address list
headers") tried to avoid sending empty headers; but instead of deleting
the header, the empty string value was just ignored.

Fixes: https://todo.sr.ht/~rjarry/aerc/55
Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Tim Culverhouse <tim@timculverhouse.com>
2022-07-10 20:40:39 +02:00
Tim Culverhouse
635530b12d msglist: fix panic for index-out-of-range
I didn't save the stack trace, but msglist.Selected() can create a panic
for index out of range due to the math operations in the map. My stack
trace resulted in a [-9]. This patch reuses the msgstore.Selected()
method, which already has bounds checking.

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-07-10 20:40:22 +02:00
Koni Marti
e19b411e52 recall: support pgp/mime messages
PGP/MIME messages are stored encrypted and/or signed in the draft folder
for security reasons. Recall will open them through the lib.MessageView
interface in order to display the message content properly in the
composer tab. If the stored message was encrypted or signed, the
recalled message in the composer will also be encrypted or signed.

Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-07-10 20:39:53 +02:00
Koni Marti
a293a39454 recall: append attachments
Append attachments to the composer when a message with attachments is
recalled. Before the attachement refactoring in the composer, the
recalled attachments were ignored.

Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-07-10 20:39:46 +02:00