NeoMutt  2025-12-11-236-g400a5f
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
neomutt.c
Go to the documentation of this file.
1
23
29
30#include "config.h"
31#include <errno.h>
32#include <locale.h>
33#include <stdio.h>
34#include <string.h>
35#include <sys/stat.h>
36#include <unistd.h>
37#include "mutt/lib.h"
38#include "address/lib.h"
39#include "config/lib.h"
40#include "neomutt.h"
41#include "account.h"
42#include "mailbox.h"
43#include "muttlib.h"
44
45struct NeoMutt *NeoMutt = NULL;
46
48#define CONFIG_INIT_TYPE(CS, NAME) \
49 extern const struct ConfigSetType Cst##NAME; \
50 cs_register_type(CS, &Cst##NAME)
51
53#define CONFIG_INIT_VARS(CS, NAME) \
54 bool config_init_##NAME(struct ConfigSet *cs); \
55 config_init_##NAME(CS)
56
63static bool init_env(struct NeoMutt *n, char **envp)
64{
65 if (!n)
66 return false;
67
70
71 envlist_free(&n->env);
72 n->env = envlist_init(envp);
73
74 return true;
75}
76
82static bool init_locale(struct NeoMutt *n)
83{
84 if (!n)
85 return false;
86
87 setlocale(LC_ALL, "");
88
89#ifdef ENABLE_NLS
90 const char *domdir = mutt_str_getenv("TEXTDOMAINDIR");
91 if (domdir)
92 bindtextdomain(PACKAGE, domdir);
93 else
94 bindtextdomain(PACKAGE, MUTTLOCALEDIR);
95 textdomain(PACKAGE);
96#endif
97
98 n->time_c_locale = duplocale(LC_GLOBAL_LOCALE);
99 if (n->time_c_locale)
100 n->time_c_locale = newlocale(LC_TIME_MASK, "C", n->time_c_locale);
101
102 if (!n->time_c_locale)
103 {
104 mutt_error("%s", strerror(errno)); // LCOV_EXCL_LINE
105 return false; // LCOV_EXCL_LINE
106 }
107
108#ifndef LOCALES_HACK
109 /* Do we have a locale definition? */
110 if (mutt_str_getenv("LC_ALL") || mutt_str_getenv("LANG") || mutt_str_getenv("LC_CTYPE"))
111 {
112 OptLocales = true;
113 }
114#endif
115
116 return true;
117}
118
119#ifdef ENABLE_NLS
124static void localise_config(struct ConfigSet *cs)
125{
126 struct Buffer *value = buf_pool_get();
127 struct HashElemArray hea = get_elem_list(cs, GEL_ALL_CONFIG);
128 struct HashElem **hep = NULL;
129
130 ARRAY_FOREACH(hep, &hea)
131 {
132 struct HashElem *he = *hep;
133 if (!(he->type & D_L10N_STRING))
134 continue;
135
136 buf_reset(value);
137 cs_he_initial_get(cs, he, value);
138
139 // Lookup the translation
140 const char *l10n = gettext(buf_string(value));
141 config_he_set_initial(cs, he, l10n);
142 }
143
144 ARRAY_FREE(&hea);
145 buf_pool_release(&value);
146}
147#endif
148
153static void reset_tilde(struct ConfigSet *cs)
154{
155 static const char *names[] = { "folder", "mbox", "postponed", "record" };
156
157 struct Buffer *value = buf_pool_get();
158 for (size_t i = 0; i < countof(names); i++)
159 {
160 struct HashElem *he = cs_get_elem(cs, names[i]);
161 if (!he)
162 continue;
163 buf_reset(value);
164 cs_he_initial_get(cs, he, value);
165 expand_path(value, false);
166 config_he_set_initial(cs, he, value->data);
167 }
168 buf_pool_release(&value);
169}
170
181static bool init_config(struct NeoMutt *n)
182{
183 if (!n)
184 return false;
185
186 n->cs = cs_new(500);
187
188 n->sub = cs_subset_new(NULL, NULL, n->notify);
190 n->sub->cs = n->cs;
191
192 bool rc = true;
193
194 // Set up the Config Types
195 for (int i = 0; n->modules[i]; i++)
196 {
197 const struct Module *mod = n->modules[i];
198
199 if (mod->config_define_types)
200 {
201 mutt_debug(LL_DEBUG3, "%s:config_define_types()\n", mod->name);
202 rc &= mod->config_define_types(n, n->sub->cs);
203 }
204 }
205
206 if (!rc)
207 return false;
208
209 // Define the Config Variables
210 for (int i = 0; n->modules[i]; i++)
211 {
212 const struct Module *mod = n->modules[i];
213
215 {
216 mutt_debug(LL_DEBUG3, "%s:config_define_variables()\n", mod->name);
217 rc &= mod->config_define_variables(n, n->sub->cs);
218 }
219 }
220
221 if (!rc)
222 return false;
223
224 // Post-processing
225#ifdef ENABLE_NLS
227#endif
228 reset_tilde(n->sub->cs);
229
230 /* Unset suspend by default if we're the session leader */
231 if (getsid(0) == getpid())
232 config_str_set_initial(n->sub->cs, "suspend", "no");
233
234 return rc;
235}
236
242static bool init_commands(struct NeoMutt *n)
243{
244 if (!n)
245 return false;
246
247 if (!n->modules)
248 return true;
249
250 struct CommandArray *ca = &n->commands;
251
252 bool rc = true;
253
254 // Set up the Config Types
255 for (int i = 0; n->modules[i]; i++)
256 {
257 const struct Module *mod = n->modules[i];
258
259 if (mod->commands_register)
260 {
261 mutt_debug(LL_DEBUG3, "%s:commands_register()\n", mod->name);
262 rc &= mod->commands_register(n, ca);
263 }
264 }
265
266 return rc;
267}
268
274static bool init_modules(struct NeoMutt *n)
275{
276 if (!n)
277 return false;
278
279 if (!n->modules)
280 return true;
281
282 bool rc = true;
283
284 // Initialise the Modules
285 for (int i = 0; n->modules[i]; i++)
286 {
287 const struct Module *mod = n->modules[i];
288
289 if (mod->init)
290 {
291 mutt_debug(LL_DEBUG3, "%s:init()\n", mod->name);
292 rc &= mod->init(n);
293 }
294 }
295
296 return rc;
297}
298
303struct NeoMutt *neomutt_new(void)
304{
305 return MUTT_MEM_CALLOC(1, struct NeoMutt);
306}
307
315bool neomutt_init(struct NeoMutt *n, char **envp, const struct Module **modules)
316{
317 if (!n)
318 return false;
319
320 n->modules = modules;
321
322 if (!init_env(n, envp))
323 return false;
324
325 if (!init_locale(n))
326 return false;
327
328 if (!init_config(n))
329 return false;
330
331 if (!init_commands(n))
332 return false;
333
334 if (!init_modules(n))
335 return false;
336
337 ARRAY_INIT(&n->accounts);
338 n->notify = notify_new();
339
342
345
346 n->groups = groups_new();
347
348 // Change the current umask, and save the original one
349 n->user_default_umask = umask(077);
350 mutt_debug(LL_DEBUG1, "user's umask %03o\n", n->user_default_umask);
351 mutt_debug(LL_DEBUG3, "umask set to 077\n");
352
353 return true;
354}
355
360static void cleanup_modules(struct NeoMutt *n)
361{
362 if (!n || !n->modules)
363 return;
364}
365
371{
372 if (!n)
373 return;
374
376}
377
382void neomutt_free(struct NeoMutt **ptr)
383{
384 if (!ptr || !*ptr)
385 return;
386
387 struct NeoMutt *n = *ptr;
388
392 notify_free(&n->notify);
393 if (n->time_c_locale)
394 freelocale(n->time_c_locale);
395
396 groups_free(&n->groups);
397
398 FREE(&n->home_dir);
399 FREE(&n->username);
400
401 envlist_free(&n->env);
402 if (n->sub)
403 {
404 struct ConfigSet *cs = n->sub->cs;
405 cs_subset_free(&n->sub);
406 cs_free(&cs);
407 }
408
409 FREE(ptr);
410}
411
418bool neomutt_account_add(struct NeoMutt *n, struct Account *a)
419{
420 if (!n || !a)
421 return false;
422
423 ARRAY_ADD(&n->accounts, a);
425
426 mutt_debug(LL_NOTIFY, "NT_ACCOUNT_ADD: %s %p\n",
427 mailbox_get_type_name(a->type), (void *) a);
428 struct EventAccount ev_a = { a };
430 return true;
431}
432
438void neomutt_account_remove(struct NeoMutt *n, struct Account *a)
439{
440 if (!n || !a || ARRAY_EMPTY(&n->accounts))
441 return;
442
443 struct Account **ap = NULL;
444 ARRAY_FOREACH(ap, &n->accounts)
445 {
446 if ((*ap) != a)
447 continue;
448
449 ARRAY_REMOVE(&n->accounts, ap);
450 account_free(&a);
451 break;
452 }
453}
454
460{
461 if (!n)
462 return;
463
464 if (!ARRAY_EMPTY(&n->accounts))
465 {
466 mutt_debug(LL_NOTIFY, "NT_ACCOUNT_DELETE_ALL\n");
467 struct EventAccount ev_a = { NULL };
469
470 struct Account **ap = NULL;
471 ARRAY_FOREACH(ap, &n->accounts)
472 {
473 account_free(ap);
474 }
475 }
476
477 ARRAY_FREE(&n->accounts);
478}
479
488struct MailboxArray neomutt_mailboxes_get(struct NeoMutt *n, enum MailboxType type)
489{
490 struct MailboxArray ma = ARRAY_HEAD_INITIALIZER;
491
492 if (!n)
493 return ma;
494
495 struct Account **ap = NULL;
496 struct Mailbox **mp = NULL;
497
498 ARRAY_FOREACH(ap, &n->accounts)
499 {
500 struct Account *a = *ap;
501 if ((type > MUTT_UNKNOWN) && (a->type != type))
502 continue;
503
504 ARRAY_FOREACH(mp, &a->mailboxes)
505 {
506 ARRAY_ADD(&ma, *mp);
507 }
508 }
509
510 return ma;
511}
512
525FILE *mutt_file_fopen_masked_full(const char *path, const char *mode,
526 const char *file, int line, const char *func)
527{
528 // Set the user's umask (saved on startup)
529 mode_t old_umask = umask(NeoMutt->user_default_umask);
530 mutt_debug(LL_DEBUG3, "umask set to %03o\n", NeoMutt->user_default_umask);
531
532 // The permissions will be limited by the umask
533 FILE *fp = mutt_file_fopen_full(path, mode, 0666, file, line, func);
534
535 umask(old_umask); // Immediately restore the umask
536 mutt_debug(LL_DEBUG3, "umask set to %03o\n", old_umask);
537
538 return fp;
539}
struct HashTable * groups_new(void)
Create a HashTable for the Address Groups.
Definition group.c:267
void groups_free(struct HashTable **pptr)
Free Address Groups HashTable.
Definition group.c:280
Email Address Handling.
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition array.h:157
#define ARRAY_REMOVE(head, elem)
Remove an entry from the array, shifting down the subsequent entries.
Definition array.h:355
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition array.h:223
#define ARRAY_EMPTY(head)
Check if an array is empty.
Definition array.h:74
#define ARRAY_FREE(head)
Release all memory.
Definition array.h:209
#define ARRAY_INIT(head)
Initialize an array.
Definition array.h:65
#define ARRAY_HEAD_INITIALIZER
Static initializer for arrays.
Definition array.h:58
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition buffer.c:76
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
bool config_str_set_initial(struct ConfigSet *cs, const char *name, const char *value)
Set the initial value of a Config Option.
Definition helpers.c:332
bool config_he_set_initial(struct ConfigSet *cs, struct HashElem *he, const char *value)
Set the initial value of a Config Option.
Definition helpers.c:312
Convenience wrapper for the config headers.
struct HashElem * cs_get_elem(const struct ConfigSet *cs, const char *name)
Get the HashElem representing a config item.
Definition set.c:176
void cs_free(struct ConfigSet **ptr)
Free a Config Set.
Definition set.c:142
struct ConfigSet * cs_new(size_t size)
Create a new Config Set.
Definition set.c:128
int cs_he_initial_get(const struct ConfigSet *cs, struct HashElem *he, struct Buffer *result)
Get the initial, or parent, value of a config item.
Definition set.c:558
void account_free(struct Account **ptr)
Free an Account.
Definition account.c:148
A group of associated Mailboxes.
@ NT_ACCOUNT_ADD
Account has been added.
Definition account.h:67
@ NT_ACCOUNT_DELETE_ALL
All Accounts are about to be deleted.
Definition account.h:69
const char * mailbox_get_type_name(enum MailboxType type)
Get the type of a Mailbox.
Definition mailbox.c:325
Representation of a mailbox.
MailboxType
Supported mailbox formats.
Definition mailbox.h:40
@ MUTT_UNKNOWN
Mailbox wasn't recognised.
Definition mailbox.h:43
void envlist_free(char ***envp)
Free the private copy of the environment.
Definition envlist.c:42
char ** envlist_init(char **envp)
Create a copy of the environment.
Definition envlist.c:58
FILE * mutt_file_fopen_full(const char *path, const char *mode, const mode_t perms, const char *file, int line, const char *func)
Call fopen() safely.
Definition file.c:560
#define mutt_error(...)
Definition logging2.h:94
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
@ LL_DEBUG3
Log at debug level 3.
Definition logging2.h:47
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:45
@ LL_NOTIFY
Log of notifications.
Definition logging2.h:50
bool OptLocales
(pseudo) set if user has valid locale definition
Definition mbyte.c:45
#define countof(x)
Definition memory.h:49
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
#define MUTT_MEM_CALLOC(n, type)
Definition memory.h:52
Convenience wrapper for the library headers.
struct Notify * notify_new(void)
Create a new notifications handler.
Definition notify.c:62
bool notify_send(struct Notify *notify, enum NotifyType event_type, int event_subtype, void *event_data)
Send out a notification message.
Definition notify.c:173
void notify_set_parent(struct Notify *notify, struct Notify *parent)
Set the parent notification handler.
Definition notify.c:95
void notify_free(struct Notify **ptr)
Free a notification handler.
Definition notify.c:75
const char * mutt_str_getenv(const char *name)
Get an environment variable.
Definition string.c:728
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition string.c:284
void expand_path(struct Buffer *buf, bool regex)
Create the canonical path.
Definition muttlib.c:121
Some miscellaneous functions.
struct MailboxArray neomutt_mailboxes_get(struct NeoMutt *n, enum MailboxType type)
Get an Array of matching Mailboxes.
Definition neomutt.c:488
static bool init_modules(struct NeoMutt *n)
Initialise the Modules.
Definition neomutt.c:274
static bool init_locale(struct NeoMutt *n)
Initialise the Locale/NLS settings.
Definition neomutt.c:82
static void cleanup_modules(struct NeoMutt *n)
Clean up each of the Modules.
Definition neomutt.c:360
static void localise_config(struct ConfigSet *cs)
Localise some config.
Definition neomutt.c:124
void neomutt_account_remove(struct NeoMutt *n, struct Account *a)
Remove an Account from the global list.
Definition neomutt.c:438
static void reset_tilde(struct ConfigSet *cs)
Temporary measure.
Definition neomutt.c:153
bool neomutt_account_add(struct NeoMutt *n, struct Account *a)
Add an Account to the global list.
Definition neomutt.c:418
void neomutt_cleanup(struct NeoMutt *n)
Clean up NeoMutt and Modules.
Definition neomutt.c:370
bool neomutt_init(struct NeoMutt *n, char **envp, const struct Module **modules)
Initialise NeoMutt.
Definition neomutt.c:315
void neomutt_accounts_free(struct NeoMutt *n)
Definition neomutt.c:459
FILE * mutt_file_fopen_masked_full(const char *path, const char *mode, const char *file, int line, const char *func)
Wrapper around mutt_file_fopen_full()
Definition neomutt.c:525
struct NeoMutt * neomutt_new(void)
Create the main NeoMutt object.
Definition neomutt.c:303
static bool init_config(struct NeoMutt *n)
Initialise the config system.
Definition neomutt.c:181
static bool init_env(struct NeoMutt *n, char **envp)
Initialise the Environment.
Definition neomutt.c:63
void neomutt_free(struct NeoMutt **ptr)
Free a NeoMutt.
Definition neomutt.c:382
static bool init_commands(struct NeoMutt *n)
Initialise the NeoMutt commands.
Definition neomutt.c:242
Container for Accounts, Notifications.
@ NT_ACCOUNT
Account has changed, NotifyAccount, EventAccount.
Definition notify_type.h:36
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
A group of associated Mailboxes.
Definition account.h:36
enum MailboxType type
Type of Mailboxes this Account contains.
Definition account.h:37
struct Notify * notify
Notifications: NotifyAccount, EventAccount.
Definition account.h:41
struct MailboxArray mailboxes
All Mailboxes.
Definition account.h:40
String manipulation buffer.
Definition buffer.h:36
char * data
Pointer to data.
Definition buffer.h:37
Container for lots of config items.
Definition set.h:250
struct ConfigSet * cs
Parent ConfigSet.
Definition subset.h:50
enum ConfigScope scope
Scope of Subset, e.g. SET_SCOPE_ACCOUNT.
Definition subset.h:48
An Event that happened to an Account.
Definition account.h:77
The item stored in a Hash Table.
Definition hash.h:44
int type
Type of data stored in Hash Table, e.g. DT_STRING.
Definition hash.h:45
A mailbox.
Definition mailbox.h:78
const char * name
Name of the library module.
Definition neomutt.h:46
bool(* init)(struct NeoMutt *n)
Definition neomutt.h:55
bool(* config_define_types)(struct NeoMutt *n, struct ConfigSet *cs)
Definition neomutt.h:67
bool(* commands_register)(struct NeoMutt *n, struct CommandArray *ca)
Definition neomutt.h:91
bool(* config_define_variables)(struct NeoMutt *n, struct ConfigSet *cs)
Definition neomutt.h:79
Container for Accounts, Notifications.
Definition neomutt.h:128
struct Notify * notify_timeout
Timeout notifications handler.
Definition neomutt.h:132
struct AccountArray accounts
All Accounts.
Definition neomutt.h:135
struct CommandArray commands
NeoMutt commands.
Definition neomutt.h:138
struct Notify * notify_resize
Window resize notifications handler.
Definition neomutt.h:131
char ** env
Private copy of the environment variables.
Definition neomutt.h:143
char * username
User's login name.
Definition neomutt.h:142
mode_t user_default_umask
User's default file writing permissions (inferred from umask)
Definition neomutt.h:137
const struct Module ** modules
Library modules.
Definition neomutt.h:129
char * home_dir
User's home directory.
Definition neomutt.h:141
struct ConfigSet * cs
Config set.
Definition neomutt.h:133
struct Notify * notify
Notifications handler.
Definition neomutt.h:130
struct HashTable * groups
Hash Table: "group-name" -> Group.
Definition neomutt.h:139
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:134
locale_t time_c_locale
Current locale but LC_TIME=C.
Definition neomutt.h:136
struct HashElemArray get_elem_list(struct ConfigSet *cs, enum GetElemListFlags flags)
Create a sorted list of all config items.
Definition subset.c:81
struct ConfigSubset * cs_subset_new(const char *name, struct ConfigSubset *sub_parent, struct Notify *not_parent)
Create a new Config Subset.
Definition subset.c:158
void cs_subset_free(struct ConfigSubset **ptr)
Free a Config Subset.
Definition subset.c:112
@ GEL_ALL_CONFIG
All the normal config (no synonyms or deprecated)
Definition subset.h:81
@ SET_SCOPE_NEOMUTT
This Config is NeoMutt-specific (global)
Definition subset.h:37
#define D_L10N_STRING
String can be localised.
Definition types.h:82