1 /**
2 * @file
3 * Data shared between Index, Pager and Sidebar
4 *
5 * @authors
6 * Copyright (C) 2021 Richard Russon <rich@flatcap.org>
7 *
8 * @copyright
9 * This program is free software: you can redistribute it and/or modify it under
10 * the terms of the GNU General Public License as published by the Free Software
11 * Foundation, either version 2 of the License, or (at your option) any later
12 * version.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 /**
24 * @page index_shared_data Shared data
25 *
26 * Data shared between Index, Pager and Sidebar
27 */
28
29 #include "config.h"
30 #include <stdbool.h>
31 #include "mutt/lib.h"
32 #include "email/lib.h"
33 #include "core/lib.h"
34 #include "shared_data.h"
35 #include "lib.h"
36 #include "context.h"
37 #include "mutt_globals.h"
38
39 /**
40 * index_shared_context_observer - Notification that the Context has changed - Implements ::observer_t - @ingroup observer_api
41 */
index_shared_context_observer(struct NotifyCallback * nc)42 static int index_shared_context_observer(struct NotifyCallback *nc)
43 {
44 if ((nc->event_type != NT_CONTEXT) || !nc->global_data || !nc->event_data)
45 return -1;
46
47 struct EventContext *ev_c = nc->event_data;
48 if (nc->event_subtype == NT_CONTEXT_ADD)
49 return 0;
50
51 struct IndexSharedData *shared = nc->global_data;
52 if (ev_c->ctx != shared->ctx)
53 return 0;
54
55 if (nc->event_subtype == NT_CONTEXT_DELETE)
56 shared->ctx = NULL;
57
58 // Relay the message
59 mutt_debug(LL_NOTIFY, "NT_INDEX_CONTEXT\n");
60 notify_send(shared->notify, NT_INDEX, NT_INDEX_CONTEXT, shared);
61 return 0;
62 }
63
64 /**
65 * index_shared_account_observer - Notification that an Account has changed - Implements ::observer_t - @ingroup observer_api
66 */
index_shared_account_observer(struct NotifyCallback * nc)67 static int index_shared_account_observer(struct NotifyCallback *nc)
68 {
69 if ((nc->event_type != NT_ACCOUNT) || !nc->global_data || !nc->event_data)
70 return -1;
71
72 struct EventAccount *ev_a = nc->event_data;
73 if (nc->event_subtype == NT_ACCOUNT_ADD)
74 return 0;
75
76 struct IndexSharedData *shared = nc->global_data;
77 if (ev_a->account != shared->account)
78 return 0;
79
80 if (nc->event_subtype == NT_ACCOUNT_DELETE)
81 shared->account = NULL;
82
83 // Relay the message
84 mutt_debug(LL_NOTIFY, "NT_INDEX_ACCOUNT\n");
85 notify_send(shared->notify, NT_INDEX, NT_INDEX_ACCOUNT, shared);
86 return 0;
87 }
88
89 /**
90 * index_shared_mailbox_observer - Notification that a Mailbox has changed - Implements ::observer_t - @ingroup observer_api
91 */
index_shared_mailbox_observer(struct NotifyCallback * nc)92 static int index_shared_mailbox_observer(struct NotifyCallback *nc)
93 {
94 if ((nc->event_type != NT_MAILBOX) || !nc->global_data || !nc->event_data)
95 return -1;
96
97 struct EventMailbox *ev_m = nc->event_data;
98 if (nc->event_subtype == NT_MAILBOX_ADD)
99 return 0;
100
101 struct IndexSharedData *shared = nc->global_data;
102 if (ev_m->mailbox != shared->mailbox)
103 return 0;
104
105 if (nc->event_subtype == NT_MAILBOX_DELETE)
106 shared->mailbox = NULL;
107
108 // Relay the message
109 mutt_debug(LL_NOTIFY, "NT_INDEX_MAILBOX\n");
110 notify_send(shared->notify, NT_INDEX, NT_INDEX_MAILBOX, shared);
111 return 0;
112 }
113
114 /**
115 * index_shared_email_observer - Notification that an Email has changed - Implements ::observer_t - @ingroup observer_api
116 */
index_shared_email_observer(struct NotifyCallback * nc)117 static int index_shared_email_observer(struct NotifyCallback *nc)
118 {
119 if ((nc->event_type != NT_EMAIL) || !nc->global_data || !nc->event_data)
120 return -1;
121
122 struct EventEmail *ev_e = nc->event_data;
123 if (nc->event_subtype == NT_EMAIL_ADD)
124 return 0;
125
126 struct IndexSharedData *shared = nc->global_data;
127 bool match = false;
128 for (int i = 0; i < ev_e->num_emails; i++)
129 {
130 if (ev_e->emails[i] == shared->email)
131 {
132 match = true;
133 break;
134 }
135 }
136
137 if (!match)
138 return 0;
139
140 if (nc->event_subtype == NT_EMAIL_DELETE)
141 shared->email = NULL;
142
143 // Relay the message
144 mutt_debug(LL_NOTIFY, "NT_INDEX_EMAIL: %p\n", shared->email);
145 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, shared);
146 return 0;
147 }
148
149 /**
150 * index_shared_data_set_context - Set the Context for the Index and friends
151 * @param shared Shared Index data
152 * @param ctx New Context, may be NULL
153 */
index_shared_data_set_context(struct IndexSharedData * shared,struct Context * ctx)154 void index_shared_data_set_context(struct IndexSharedData *shared, struct Context *ctx)
155 {
156 if (!shared)
157 return;
158
159 NotifyIndex subtype = NT_INDEX_NO_FLAGS;
160
161 if (shared->ctx != ctx)
162 {
163 if (shared->ctx)
164 notify_observer_remove(shared->ctx->notify, index_shared_context_observer, shared);
165
166 shared->ctx = ctx;
167 subtype |= NT_INDEX_CONTEXT;
168
169 if (ctx)
170 notify_observer_add(ctx->notify, NT_CONTEXT, index_shared_context_observer, shared);
171
172 Context = ctx;
173 }
174
175 struct Mailbox *m = ctx_mailbox(ctx);
176 if (shared->mailbox != m)
177 {
178 if (shared->mailbox)
179 notify_observer_remove(shared->mailbox->notify, index_shared_mailbox_observer, shared);
180
181 shared->mailbox = m;
182 shared->email = NULL;
183 shared->email_seq = 0;
184 subtype |= NT_INDEX_MAILBOX | NT_INDEX_EMAIL;
185
186 if (m)
187 notify_observer_add(m->notify, NT_MAILBOX, index_shared_mailbox_observer, shared);
188 }
189
190 struct Account *a = m ? m->account : NULL;
191 if (shared->account != a)
192 {
193 if (shared->account)
194 notify_observer_remove(shared->account->notify, index_shared_account_observer, shared);
195
196 shared->account = a;
197 subtype |= NT_INDEX_ACCOUNT;
198
199 if (a)
200 notify_observer_add(a->notify, NT_ACCOUNT, index_shared_account_observer, shared);
201 }
202
203 struct ConfigSubset *sub = NeoMutt->sub;
204 #if 0
205 if (m)
206 sub = m->sub;
207 else if (a)
208 sub = a->sub;
209 #endif
210 if (shared->sub != sub)
211 {
212 shared->sub = sub;
213 subtype |= NT_INDEX_SUBSET;
214 }
215
216 if (subtype != NT_INDEX_NO_FLAGS)
217 {
218 mutt_debug(LL_NOTIFY, "NT_INDEX: %p\n", shared);
219 notify_send(shared->notify, NT_INDEX, subtype, shared);
220 }
221 }
222
223 /**
224 * index_shared_data_set_email - Set the current Email for the Index and friends
225 * @param shared Shared Index data
226 * @param e Current Email, may be NULL
227 */
index_shared_data_set_email(struct IndexSharedData * shared,struct Email * e)228 void index_shared_data_set_email(struct IndexSharedData *shared, struct Email *e)
229 {
230 if (!shared)
231 return;
232
233 size_t seq = e ? e->sequence : 0;
234 if ((shared->email != e) || (shared->email_seq != seq))
235 {
236 if (shared->email)
237 notify_observer_remove(shared->email->notify, index_shared_email_observer, shared);
238
239 shared->email = e;
240 shared->email_seq = seq;
241
242 if (e)
243 notify_observer_add(e->notify, NT_EMAIL, index_shared_email_observer, shared);
244
245 mutt_debug(LL_NOTIFY, "NT_INDEX_EMAIL: %p\n", shared->email);
246 notify_send(shared->notify, NT_INDEX, NT_INDEX_EMAIL, shared);
247 }
248 }
249
250 /**
251 * index_shared_data_is_cur_email - Check whether an email is the currently selected Email
252 * @param shared Shared Index data
253 * @param e Email to check
254 * @retval true e is current
255 * @retval false e is not current
256 */
index_shared_data_is_cur_email(const struct IndexSharedData * shared,const struct Email * e)257 bool index_shared_data_is_cur_email(const struct IndexSharedData *shared,
258 const struct Email *e)
259 {
260 if (!shared)
261 return false;
262
263 return shared->email_seq == e->sequence;
264 }
265
266 /**
267 * index_shared_data_free - Free Shared Index Data - Implements MuttWindow::wdata_free() - @ingroup window_wdata_free
268 *
269 * Only `notify` is owned by IndexSharedData and should be freed.
270 */
index_shared_data_free(struct MuttWindow * win,void ** ptr)271 void index_shared_data_free(struct MuttWindow *win, void **ptr)
272 {
273 if (!ptr || !*ptr)
274 return;
275
276 struct IndexSharedData *shared = *ptr;
277
278 mutt_debug(LL_NOTIFY, "NT_INDEX_DELETE: %p\n", shared);
279 notify_send(shared->notify, NT_INDEX, NT_INDEX_DELETE, shared);
280 notify_free(&shared->notify);
281
282 if (shared->account)
283 notify_observer_remove(shared->account->notify, index_shared_account_observer, shared);
284 if (shared->ctx)
285 notify_observer_remove(shared->ctx->notify, index_shared_context_observer, shared);
286 if (shared->mailbox)
287 notify_observer_remove(shared->mailbox->notify, index_shared_mailbox_observer, shared);
288 if (shared->email)
289 notify_observer_remove(shared->email->notify, index_shared_email_observer, shared);
290
291 FREE(ptr);
292 }
293
294 /**
295 * index_shared_data_new - Create new Index Data
296 * @retval ptr New IndexSharedData
297 */
index_shared_data_new(void)298 struct IndexSharedData *index_shared_data_new(void)
299 {
300 struct IndexSharedData *shared = mutt_mem_calloc(1, sizeof(struct IndexSharedData));
301
302 shared->notify = notify_new();
303 shared->sub = NeoMutt->sub;
304
305 mutt_debug(LL_NOTIFY, "NT_INDEX_ADD: %p\n", shared);
306 notify_send(shared->notify, NT_INDEX, NT_INDEX_ADD, shared);
307
308 return shared;
309 }
310