1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
|
calcurse-caldav
===============
calcurse-caldav is a simple Python script that can be used to synchronize
calcurse with a CalDAV server. Please note that the script is alpha software!
This means that:
* We are eagerly looking for testers to run the script and give feedback! If
you find any bugs, please report them to the calcurse mailing lists or to the
GitHub bug tracker. If the script works fine for you, please report back as
well!
* The script might still have bugs. MAKE BACKUPS, especially before running
calcurse-caldav for the first time!
Usage
-----
calcurse-caldav requires an up-to-date version of calcurse and a configuration
file located at ~/.calcurse/caldav/config. An example configuration file can be
found under contrib/caldav/config.sample in the calcurse source tree. You will
also need to install *httplib2* for Python 3 using *pip* (e.g. `pip3 install
--user httplib2`) or your distribution's package manager.
If you run calcurse-caldav for the first time, you need to provide the `--init`
argument. You can choose between the following initialization modes:
--init=keep-remote Remove all local calcurse items and import remote objects
--init=keep-local Remove all remote objects and push local calcurse items
--init=two-way Copy local objects to the CalDAV server and vice versa
For subsequent calcurse-caldav invocations, you don't need to specify any
additional parameters.
You can specify a username and password for basic authentication in the
config file. Alternatively, the password can be passed securely from another
program (such as *pass*) via the `CALCURSE_CALDAV_PASSWORD` environment variable like
so:
```
CALCURSE_CALDAV_PASSWORD=$(pass show calcurse) calcurse-caldav
```
Hooks
-----
You can place scripts in `$HOME/.calcurse/caldav/hooks/` to trigger actions at
certain events. To enable a hook, add a script with one of the following names
to this directory. Also make sure the scripts are executable.
*pre-sync*::
Executed before the data files are synchronized.
*post-sync*::
Executed after the data files are synchronized.
Some examples can be found in the `contrib/caldav/hooks/` directory of the
calcurse source tree.
How It Works
------------
calcurse-caldav creates a so-called synchronization database at
`~/.calcurse/caldav/sync.db` that always keeps a snapshot of the last time the
script was executed. When running the script, it compares the objects on the
server and the local objects with that snapshot to identify items that were
added or deleted. It then
* downloads new objects from the server and imports them into calcurse,
* deletes local objects that no longer exist on the server,
* uploads objects to the server that were added locally,
* deleted objects from the server that were deleted locally,
* updates the synchronization database with a new snapshot.
Note: Since calcurse does not use unique identifiers for items, it cannot keep
track of moved/edited items. Thus, modifying an item is equivalent to deleting
the old item and creating a new one.
OAuth2 Authentication
---------------------
calcurse-caldav also has support for services requiring OAuth2 authentication
such as Google Calendar. Note that you can only have a single calendar synced
at any given time, regardless of authentication method. To enable OAuth2 you
will need to:
* Change *AuthMethod* from "*basic*" to "*oauth2*" in your config file
* Fill in the appropriate settings in your config file: "*ClientID*",
"*ClientSecret*", "*Scope*", and "*RedirectURI*". These can be obtained from
the API provider. (See below for Google Calendar)
* Install *oauth2client* for Python 3 using *pip* (e.g. `pip3 install --user
oauth2client`) or your distribution's package manager
Synchronization With Google Calendar
-------------------------------------
You will need to use your Google account to create a Google API project and
enable both the CalDAV API and the Google Calendar API. We will be doing this to
receive a Client ID and Client Secret. The hostname, path, scope and redirect
URI are listed below.
First, you will need to go to the [Google Developers Console](https://console.developers.google.com/project) and click *Create
Project*. After doing that, you can go to the [API Library](https://console.developers.google.com/project/_/apiui/apis/library) and
search for the CalDAV API and enable it for your project. You will then need to
do the same for the Google Calendar API.
Next, go to the [Credentials page](https://console.developers.google.com/project/_/apiui/credential)
, click on *Create credentials*, and choose *OAuth client ID*. If it asks you
to "set a product name on the consent screen", click on *Configure consent
screen* to do so. Any product name will do. Upon saving and returning to the
"Create client ID" screen, choose *Other* as the Application type and click
*Create*. You now have your Client ID and Client Secret to put into your
calcurse-caldav config file!
The following options should also be changed in your config file:
```
Hostname = apidata.googleusercontent.com
Path = /caldav/v2/*your_calendar_id_here*/events/
Scope = https://www.googleapis.com/auth/calendar
SyncFilter = cal
```
Your Calendar ID for "*Path*" should be your email for the default calendar.
If you have multiple calendars, you can get the Calendar ID by going under
Calendar Details at [calendar.google.com](https://calendar.google.com).
The default Redirect URI in the config file is http://127.0.0.1; this should
work fine, but can be changed to http://localhost, a local web server, or
another device if you encounter errors related to it.
A complete config file for example@gmail.com would have the following options:
```
[General]
...
Hostname = apidata.googleusercontent.com
Path = /caldav/v2/example@gmail.com/events/
AuthMethod = oauth2
SyncFilter = cal
...
[OAuth2]
ClientID = 22802342jlkjlksjdlfkjq1htpvbcn.apps.googleusercontent.com
ClientSecret = XPYGqHFsfF343GwJeOGiUi
Scope = https://www.googleapis.com/auth/calendar
RedirectURI = http://127.0.0.1
```
[The full guide from Google can be found here.](https://developers.google.com/google-apps/calendar/caldav/v2/guide)
Upon your first run with the `--init` flag, you will be asked to go to a URL to
log in and authorize synchronization with your Google account. You can access
this URL on any other device if you cannot open a browser locally (e.g., on
a headless server). Once you authorize synchronization, you will be redirected
to your Redirect URI with a code embedded in it, e.g.,
`http://127.0.0.1/?code=4/Ok6mBNW2nppfIwyL-Q1ZPVkEk3zZdZN3mHcY#&scope=https://www.googleapis.com/auth/calendar`.
You will need to copy the code after `http://127.0.0.1/?code=` and before `&scope=https://www.googleapis.com/auth/calendar`. In this case,
it would be `4/Ok6mBNW2nppfIwyL-Q1ZPVkEk3zZdZN3mHcY#`.
Finally pass this authorization code to calcurse-caldav with the `--authcode`
flag and initialize the synchronization database like so (note that the quotes
around the authorization code might be necessary or not, depending on your shell):
```
calcurse-caldav --init keep-remote --authcode '4/Ok6mBNW2nppfIwyL-Q1ZPVkEk3zZdZN3mHcY#'
```
Troubleshooting
---------------
### 403 (Forbidden) When Submitting Auth Code for Google Calendar
- Ensure that both the CalDAV API and the Google Calendar API are enabled for
your Google Developer project
- Ensure that your authcode consists of only the `code` parameter's value when
extracting from the returned URL
|