NeoMutt  2025-12-11-276-g10b23b
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
functions.c
Go to the documentation of this file.
1
23
29
30#include "config.h"
31#include <stdbool.h>
32#include <stdio.h>
33#include <string.h>
34#include <sys/stat.h>
35#include "mutt/lib.h"
36#include "config/lib.h"
37#include "email/lib.h"
38#include "core/lib.h"
39#include "gui/lib.h"
40#include "functions.h"
41#include "lib.h"
42#include "attach/lib.h"
43#include "editor/lib.h"
44#include "history/lib.h"
45#include "imap/lib.h"
46#include "key/lib.h"
47#include "menu/lib.h"
48#include "nntp/lib.h"
49#include "pattern/lib.h"
50#include "question/lib.h"
51#include "send/lib.h"
52#include "globals.h"
53#include "mutt_mailbox.h"
54#include "muttlib.h"
55#include "mx.h"
56#include "nntp/adata.h" // IWYU pragma: keep
57#include "nntp/mdata.h" // IWYU pragma: keep
58#include "private_data.h"
59#include "sort.h"
60
61static int op_subscribe_pattern(struct BrowserPrivateData *priv, const struct KeyEvent *event);
62
63// clang-format off
67static const struct MenuFuncOp OpBrowser[] = { /* map: browser */
68 { "catchup", OP_CATCHUP },
69 { "change-dir", OP_CHANGE_DIRECTORY },
70 { "check-new", OP_CHECK_NEW },
71 { "create-mailbox", OP_CREATE_MAILBOX },
72 { "delete-mailbox", OP_DELETE_MAILBOX },
73 { "descend-directory", OP_DESCEND_DIRECTORY },
74 { "display-filename", OP_BROWSER_TELL },
75 { "enter-mask", OP_ENTER_MASK },
76 { "exit", OP_EXIT },
77 { "goto-folder", OP_BROWSER_GOTO_FOLDER },
78 { "goto-parent", OP_GOTO_PARENT },
79 { "mailbox-list", OP_MAILBOX_LIST },
80 { "reload-active", OP_LOAD_ACTIVE },
81 { "rename-mailbox", OP_RENAME_MAILBOX },
82 { "select-new", OP_BROWSER_NEW_FILE },
83 { "sort", OP_SORT },
84 { "sort-reverse", OP_SORT_REVERSE },
85 { "subscribe", OP_BROWSER_SUBSCRIBE },
86 { "subscribe-pattern", OP_SUBSCRIBE_PATTERN },
87 { "toggle-mailboxes", OP_TOGGLE_MAILBOXES },
88 { "toggle-subscribed", OP_BROWSER_TOGGLE_LSUB },
89 { "uncatchup", OP_UNCATCHUP },
90 { "unsubscribe", OP_BROWSER_UNSUBSCRIBE },
91 { "unsubscribe-pattern", OP_UNSUBSCRIBE_PATTERN },
92 { "view-file", OP_BROWSER_VIEW_FILE },
93 // Deprecated
94 { "buffy-list", OP_MAILBOX_LIST, MFF_DEPRECATED },
95 { NULL, 0 },
96};
97
101static const struct MenuOpSeq BrowserDefaultBindings[] = { /* map: browser */
102 { OP_BROWSER_GOTO_FOLDER, "=" },
103 { OP_BROWSER_NEW_FILE, "N" },
104 { OP_BROWSER_SUBSCRIBE, "s" },
105 { OP_BROWSER_TELL, "@" },
106 { OP_BROWSER_TOGGLE_LSUB, "T" },
107 { OP_BROWSER_UNSUBSCRIBE, "u" },
108 { OP_BROWSER_VIEW_FILE, " " }, // <Space>
109 { OP_CHANGE_DIRECTORY, "c" },
110 { OP_CREATE_MAILBOX, "C" },
111 { OP_DELETE_MAILBOX, "d" },
112 { OP_ENTER_MASK, "m" },
113 { OP_EXIT, "q" },
114 { OP_GOTO_PARENT, "p" },
115 { OP_MAILBOX_LIST, "." },
116 { OP_RENAME_MAILBOX, "r" },
117 { OP_SORT, "o" },
118 { OP_SORT_REVERSE, "O" },
119 { OP_TOGGLE_MAILBOXES, "\t" }, // <Tab>
120 { 0, NULL },
121};
122// clang-format on
123
127void browser_init_keys(struct SubMenu *sm_generic)
128{
129 struct MenuDefinition *md = NULL;
130 struct SubMenu *sm = NULL;
131
133 md = km_register_menu(MENU_BROWSER, "browser");
134 km_menu_add_submenu(md, sm);
135 km_menu_add_submenu(md, sm_generic);
137}
138
145void destroy_state(struct BrowserState *state)
146{
147 struct FolderFile *ff = NULL;
148 ARRAY_FOREACH(ff, &state->entry)
149 {
150 FREE(&ff->name);
151 FREE(&ff->desc);
152 }
153 ARRAY_FREE(&state->entry);
154 FREE(&state->folder);
155}
156
157// -----------------------------------------------------------------------------
158
162static int op_browser_new_file(struct BrowserPrivateData *priv, const struct KeyEvent *event)
163{
164 struct Buffer *buf = buf_pool_get();
165 buf_printf(buf, "%s/", buf_string(&LastDir));
166
167 struct FileCompletionData cdata = { false, priv->mailbox, NULL, NULL, NULL };
168 const int rc = mw_get_field(_("New file name: "), buf, MUTT_COMP_NO_FLAGS,
169 HC_FILE, &CompleteMailboxOps, &cdata);
170 if (rc != 0)
171 {
172 buf_pool_release(&buf);
173 return FR_NO_ACTION;
174 }
175
176 buf_copy(priv->file, buf);
177 buf_pool_release(&buf);
178 priv->done = true;
179 return FR_DONE;
180}
181
189static int op_browser_subscribe(struct BrowserPrivateData *priv, const struct KeyEvent *event)
190{
191 const int op = event->op;
192
193 if (OptNews)
194 {
196 int index = menu_get_index(priv->menu);
197
198 if (ARRAY_EMPTY(&priv->state.entry))
199 {
200 mutt_error(_("No newsgroups match the mask"));
201 return FR_ERROR;
202 }
203
204 int rc = nntp_newsrc_parse(adata);
205 if (rc < 0)
206 return FR_ERROR;
207
208 struct FolderFile *ff = ARRAY_GET(&priv->state.entry, index);
209 if (op == OP_BROWSER_SUBSCRIBE)
210 mutt_newsgroup_subscribe(adata, ff->name);
211 else
213
214 menu_set_index(priv->menu, index + 1);
215
216 if (rc > 0)
218 nntp_newsrc_update(adata);
219 nntp_clear_cache(adata);
220 nntp_newsrc_close(adata);
221 }
222 else
223 {
224 if (ARRAY_EMPTY(&priv->state.entry))
225 {
226 mutt_error(_("There are no mailboxes"));
227 return FR_ERROR;
228 }
229
230 struct Buffer *buf = buf_pool_get();
231 int index = menu_get_index(priv->menu);
232 struct FolderFile *ff = ARRAY_GET(&priv->state.entry, index);
233 buf_strcpy(buf, ff->name);
234 expand_path(buf, false);
235 imap_subscribe(buf_string(buf), (op == OP_BROWSER_SUBSCRIBE));
236 buf_pool_release(&buf);
237 }
238 return FR_SUCCESS;
239}
240
244static int op_browser_tell(struct BrowserPrivateData *priv, const struct KeyEvent *event)
245{
246 int index = menu_get_index(priv->menu);
247 if (ARRAY_EMPTY(&priv->state.entry))
248 return FR_ERROR;
249
250 mutt_message("%s", ARRAY_GET(&priv->state.entry, index)->name);
251 return FR_SUCCESS;
252}
253
257static int op_browser_toggle_lsub(struct BrowserPrivateData *priv, const struct KeyEvent *event)
258{
259 bool_str_toggle(NeoMutt->sub, "imap_list_subscribed", NULL);
260
261 mutt_unget_op(OP_CHECK_NEW);
262 return FR_SUCCESS;
263}
264
268static int op_browser_view_file(struct BrowserPrivateData *priv, const struct KeyEvent *event)
269{
270 if (ARRAY_EMPTY(&priv->state.entry))
271 {
272 mutt_error(_("No files match the file mask"));
273 return FR_ERROR;
274 }
275
276 int index = menu_get_index(priv->menu);
277 struct FolderFile *ff = ARRAY_GET(&priv->state.entry, index);
278 if (ff->selectable)
279 {
280 buf_strcpy(priv->file, ff->name);
281 priv->done = true;
282 return FR_DONE;
283 }
284 else if (S_ISDIR(ff->mode) ||
285 (S_ISLNK(ff->mode) && link_is_dir(buf_string(&LastDir), ff->name)))
286 {
287 mutt_error(_("Can't view a directory"));
288 return FR_ERROR;
289 }
290 else
291 {
292 struct Buffer *path = buf_pool_get();
294 struct Body *b = mutt_make_file_attach(buf_string(path), NeoMutt->sub);
295 if (b)
296 {
297 mutt_view_attachment(NULL, b, MUTT_VA_REGULAR, NULL, NULL, priv->menu->win);
298 mutt_body_free(&b);
300 }
301 else
302 {
303 mutt_error(_("Error trying to view file"));
304 }
305 buf_pool_release(&path);
306 }
307 return FR_ERROR;
308}
309
313static int op_catchup(struct BrowserPrivateData *priv, const struct KeyEvent *event)
314{
315 if (!OptNews)
316 return FR_NOT_IMPL;
317
318 struct NntpMboxData *mdata = NULL;
319
321 if (rc < 0)
322 return FR_ERROR;
323
324 int index = menu_get_index(priv->menu);
325 struct FolderFile *ff = ARRAY_GET(&priv->state.entry, index);
326 if (event->op == OP_CATCHUP)
328 else
330
331 if (mdata)
332 {
334 index = menu_get_index(priv->menu) + 1;
335 if (index < priv->menu->max)
336 menu_set_index(priv->menu, index);
337 }
338
339 if (rc != 0)
341
343 return FR_ERROR;
344}
345
353static int op_change_directory(struct BrowserPrivateData *priv, const struct KeyEvent *event)
354{
355 if (OptNews)
356 return FR_NOT_IMPL;
357
358 struct Buffer *buf = buf_pool_get();
359 buf_copy(buf, &LastDir);
360 if (!priv->state.imap_browse)
361 {
362 /* add '/' at the end of the directory name if not already there */
363 size_t len = buf_len(buf);
364 if ((len > 0) && (buf_string(&LastDir)[len - 1] != '/'))
365 buf_addch(buf, '/');
366 }
367
368 const int op = event->op;
369 if (op == OP_CHANGE_DIRECTORY)
370 {
371 struct FileCompletionData cdata = { false, priv->mailbox, NULL, NULL, NULL };
372 int rc = mw_get_field(_("Chdir to: "), buf, MUTT_COMP_NO_FLAGS, HC_FILE,
373 &CompleteMailboxOps, &cdata);
374 if ((rc != 0) && buf_is_empty(buf))
375 {
376 buf_pool_release(&buf);
377 return FR_NO_ACTION;
378 }
379 }
380 else if (op == OP_GOTO_PARENT)
381 {
382 mutt_get_parent_path(buf_string(buf), buf->data, buf->dsize);
383 }
384
385 if (!buf_is_empty(buf))
386 {
387 priv->state.is_mailbox_list = false;
388 expand_path(buf, false);
389 if (imap_path_probe(buf_string(buf), NULL) == MUTT_IMAP)
390 {
391 buf_copy(&LastDir, buf);
392 destroy_state(&priv->state);
393 init_state(&priv->state);
394 priv->state.imap_browse = true;
396 browser_sort(&priv->state);
397 browser_highlight_default(&priv->state, priv->menu);
398 init_menu(&priv->state, priv->menu, priv->mailbox, priv->sbar);
399 }
400 else
401 {
402 if (buf_string(buf)[0] != '/')
403 {
404 /* in case dir is relative, make it relative to LastDir,
405 * not current working dir */
406 struct Buffer *tmp = buf_pool_get();
408 buf_copy(buf, tmp);
409 buf_pool_release(&tmp);
410 }
411 /* Resolve path from <chdir>
412 * Avoids buildup such as /a/b/../../c
413 * Symlinks are always unraveled to keep code simple */
414 if (mutt_path_realpath(buf) == 0)
415 {
416 buf_pool_release(&buf);
417 return FR_ERROR;
418 }
419
420 struct stat st = { 0 };
421 if (stat(buf_string(buf), &st) == 0)
422 {
423 if (S_ISDIR(st.st_mode))
424 {
425 destroy_state(&priv->state);
426 if (examine_directory(priv->mailbox, priv->menu, &priv->state,
427 buf_string(buf), buf_string(priv->prefix)) == 0)
428 {
429 buf_copy(&LastDir, buf);
430 }
431 else
432 {
433 mutt_error(_("Error scanning directory"));
434 if (examine_directory(priv->mailbox, priv->menu, &priv->state,
435 buf_string(&LastDir), buf_string(priv->prefix)) == -1)
436 {
437 priv->done = true;
438 return FR_ERROR;
439 }
440 }
441 browser_highlight_default(&priv->state, priv->menu);
442 init_menu(&priv->state, priv->menu, priv->mailbox, priv->sbar);
443 }
444 else
445 {
446 mutt_error(_("%s is not a directory"), buf_string(buf));
447 }
448 }
449 else
450 {
451 mutt_perror("%s", buf_string(buf));
452 }
453 }
454 }
455 buf_pool_release(&buf);
456 return FR_ERROR;
457}
458
462static int op_create_mailbox(struct BrowserPrivateData *priv, const struct KeyEvent *event)
463{
464 if (!priv->state.imap_browse)
465 {
466 mutt_error(_("Create is only supported for IMAP mailboxes"));
467 return FR_ERROR;
468 }
469
471 return FR_ERROR;
472
473 /* TODO: find a way to detect if the new folder would appear in
474 * this window, and insert it without starting over. */
475 destroy_state(&priv->state);
476 init_state(&priv->state);
477 priv->state.imap_browse = true;
479 browser_sort(&priv->state);
480 browser_highlight_default(&priv->state, priv->menu);
481 init_menu(&priv->state, priv->menu, priv->mailbox, priv->sbar);
482
483 return FR_SUCCESS;
484}
485
489static int op_delete_mailbox(struct BrowserPrivateData *priv, const struct KeyEvent *event)
490{
491 int index = menu_get_index(priv->menu);
492 struct FolderFile *ff = ARRAY_GET(&priv->state.entry, index);
493 if (!ff->imap)
494 {
495 mutt_error(_("Delete is only supported for IMAP mailboxes"));
496 return FR_ERROR;
497 }
498
499 char msg[128] = { 0 };
500
501 // TODO(sileht): It could be better to select INBOX instead. But I
502 // don't want to manipulate Mailboxes/mailbox->account here for now.
503 // Let's just protect neomutt against crash for now. #1417
504 if (mutt_str_equal(mailbox_path(priv->mailbox), ff->name))
505 {
506 mutt_error(_("Can't delete currently selected mailbox"));
507 return FR_ERROR;
508 }
509
510 snprintf(msg, sizeof(msg), _("Really delete mailbox \"%s\"?"), ff->name);
511 if (query_yesorno(msg, MUTT_NO) != MUTT_YES)
512 {
513 mutt_message(_("Mailbox not deleted"));
514 return FR_NO_ACTION;
515 }
516
517 if (imap_delete_mailbox(priv->mailbox, ff->name) != 0)
518 {
519 mutt_error(_("Mailbox deletion failed"));
520 return FR_ERROR;
521 }
522
523 /* free the mailbox from the browser */
524 FREE(&ff->name);
525 FREE(&ff->desc);
526 /* and move all other entries up */
527 ARRAY_REMOVE(&priv->state.entry, ff);
528 mutt_message(_("Mailbox deleted"));
529 init_menu(&priv->state, priv->menu, priv->mailbox, priv->sbar);
530
531 return FR_SUCCESS;
532}
533
537static int op_enter_mask(struct BrowserPrivateData *priv, const struct KeyEvent *event)
538{
539 const struct Regex *c_mask = cs_subset_regex(NeoMutt->sub, "mask");
540 struct Buffer *buf = buf_pool_get();
541 buf_strcpy(buf, c_mask ? c_mask->pattern : NULL);
542 if (mw_get_field(_("File Mask: "), buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0)
543 {
544 buf_pool_release(&buf);
545 return FR_NO_ACTION;
546 }
547
548 buf_fix_dptr(buf);
549
550 priv->state.is_mailbox_list = false;
551 /* assume that the user wants to see everything */
552 if (buf_is_empty(buf))
553 buf_strcpy(buf, ".");
554
555 struct Buffer *errmsg = buf_pool_get();
556 int rc = cs_subset_str_string_set(NeoMutt->sub, "mask", buf_string(buf), errmsg);
557 buf_pool_release(&buf);
558 if (CSR_RESULT(rc) != CSR_SUCCESS)
559 {
560 if (!buf_is_empty(errmsg))
561 {
562 mutt_error("%s", buf_string(errmsg));
563 buf_pool_release(&errmsg);
564 }
565 return FR_ERROR;
566 }
567 buf_pool_release(&errmsg);
568
569 destroy_state(&priv->state);
570 if (priv->state.imap_browse)
571 {
572 init_state(&priv->state);
573 priv->state.imap_browse = true;
575 browser_sort(&priv->state);
576 init_menu(&priv->state, priv->menu, priv->mailbox, priv->sbar);
577 }
578 else if (examine_directory(priv->mailbox, priv->menu, &priv->state,
579 buf_string(&LastDir), NULL) == 0)
580 {
581 init_menu(&priv->state, priv->menu, priv->mailbox, priv->sbar);
582 }
583 else
584 {
585 mutt_error(_("Error scanning directory"));
586 priv->done = true;
587 return FR_ERROR;
588 }
589 priv->kill_prefix = false;
590 if (ARRAY_EMPTY(&priv->state.entry))
591 {
592 mutt_error(_("No files match the file mask"));
593 return FR_ERROR;
594 }
595 return FR_SUCCESS;
596}
597
601static int op_exit(struct BrowserPrivateData *priv, const struct KeyEvent *event)
602{
603 if (priv->multiple)
604 {
605 char **tfiles = NULL;
606
607 if (priv->menu->tag_prefix && (priv->menu->num_tagged != 0))
608 {
609 *priv->numfiles = priv->menu->num_tagged;
610 tfiles = MUTT_MEM_CALLOC(*priv->numfiles, char *);
611 size_t j = 0;
612 struct FolderFile *ff = NULL;
613 ARRAY_FOREACH(ff, &priv->state.entry)
614 {
615 if (ff->tagged)
616 {
617 struct Buffer *buf = buf_pool_get();
619 expand_path(buf, false);
620 tfiles[j++] = buf_strdup(buf);
621 buf_pool_release(&buf);
622 }
623 }
624 *priv->files = tfiles;
625 }
626 else if (!buf_is_empty(priv->file)) /* no tagged entries. return selected entry */
627 {
628 *priv->numfiles = 1;
629 tfiles = MUTT_MEM_CALLOC(*priv->numfiles, char *);
630 expand_path(priv->file, false);
631 tfiles[0] = buf_strdup(priv->file);
632 *priv->files = tfiles;
633 }
634 }
635
636 priv->done = true;
637 return FR_DONE;
638}
639
647static int op_generic_select_entry(struct BrowserPrivateData *priv, const struct KeyEvent *event)
648{
649 if (ARRAY_EMPTY(&priv->state.entry))
650 {
651 mutt_warning(_("No files match the file mask"));
652 return FR_ERROR;
653 }
654
655 const int op = event->op;
656 int index = menu_get_index(priv->menu);
657 struct FolderFile *ff = ARRAY_GET(&priv->state.entry, index);
658 if ((priv->menu->tag_prefix) && (op == OP_GENERIC_SELECT_ENTRY))
659 {
660 // Do nothing
661 }
662 else if (S_ISDIR(ff->mode) ||
663 (S_ISLNK(ff->mode) && link_is_dir(buf_string(&LastDir), ff->name)) || ff->inferiors)
664 {
665 /* make sure this isn't a MH or maildir mailbox */
666 struct Buffer *buf = buf_pool_get();
667 if (priv->state.is_mailbox_list)
668 {
669 buf_strcpy(buf, ff->name);
670 expand_path(buf, false);
671 }
672 else if (priv->state.imap_browse)
673 {
674 buf_strcpy(buf, ff->name);
675 }
676 else
677 {
679 }
680
681 enum MailboxType type = mx_path_probe(buf_string(buf));
682 buf_pool_release(&buf);
683
684 if ((op == OP_DESCEND_DIRECTORY) || (type == MUTT_MAILBOX_ERROR) ||
685 (type == MUTT_UNKNOWN) || ff->inferiors)
686 {
687 /* save the old directory */
689
690 if (mutt_str_equal(ff->name, ".."))
691 {
692 size_t lastdirlen = buf_len(&LastDir);
693 if ((lastdirlen > 1) && mutt_str_equal("..", buf_string(&LastDir) + lastdirlen - 2))
694 {
695 buf_addstr(&LastDir, "/..");
696 }
697 else
698 {
699 char *p = NULL;
700 if (lastdirlen > 1)
701 p = strrchr(LastDir.data + 1, '/');
702
703 if (p)
704 {
705 *p = '\0';
707 }
708 else
709 {
710 if (buf_string(&LastDir)[0] == '/')
711 buf_strcpy(&LastDir, "/");
712 else
713 buf_addstr(&LastDir, "/..");
714 }
715 }
716 }
717 else if (priv->state.is_mailbox_list)
718 {
719 buf_strcpy(&LastDir, ff->name);
720 expand_path(&LastDir, false);
721 }
722 else if (priv->state.imap_browse)
723 {
724 buf_strcpy(&LastDir, ff->name);
725 /* tack on delimiter here */
726
727 /* special case "" needs no delimiter */
728 struct Url *url = url_parse(ff->name);
729 if (url && url->path && (ff->delim != '\0'))
730 {
731 buf_addch(&LastDir, ff->delim);
732 }
733 url_free(&url);
734 }
735 else
736 {
737 struct Buffer *tmp = buf_pool_get();
739 buf_copy(&LastDir, tmp);
740 buf_pool_release(&tmp);
741 }
742
743 destroy_state(&priv->state);
744 if (priv->kill_prefix)
745 {
746 buf_reset(priv->prefix);
747 priv->kill_prefix = false;
748 }
749 priv->state.is_mailbox_list = false;
750 if (priv->state.imap_browse)
751 {
752 init_state(&priv->state);
753 priv->state.imap_browse = true;
755 browser_sort(&priv->state);
756 }
757 else
758 {
759 if (examine_directory(priv->mailbox, priv->menu, &priv->state,
760 buf_string(&LastDir), buf_string(priv->prefix)) == -1)
761 {
762 /* try to restore the old values */
764 if (examine_directory(priv->mailbox, priv->menu, &priv->state,
765 buf_string(&LastDir), buf_string(priv->prefix)) == -1)
766 {
768 priv->done = true;
769 return FR_DONE;
770 }
771 }
772 /* resolve paths navigated from GUI */
773 if (mutt_path_realpath(&LastDir) == 0)
774 return FR_ERROR;
775 }
776
777 browser_highlight_default(&priv->state, priv->menu);
778 init_menu(&priv->state, priv->menu, priv->mailbox, priv->sbar);
779 priv->goto_swapper[0] = '\0';
780 return FR_SUCCESS;
781 }
782 }
783 else if (op == OP_DESCEND_DIRECTORY)
784 {
785 mutt_error(_("%s is not a directory"), ARRAY_GET(&priv->state.entry, index)->name);
786 return FR_ERROR;
787 }
788
789 if (priv->state.is_mailbox_list || OptNews)
790 {
791 buf_strcpy(priv->file, ff->name);
792 expand_path(priv->file, false);
793 }
794 else if (priv->state.imap_browse)
795 {
796 buf_strcpy(priv->file, ff->name);
797 }
798 else
799 {
801 }
802
803 return op_exit(priv, event);
804}
805
809static int op_load_active(struct BrowserPrivateData *priv, const struct KeyEvent *event)
810{
811 if (!OptNews)
812 return FR_NOT_IMPL;
813
815
816 if (nntp_newsrc_parse(adata) < 0)
817 return FR_ERROR;
818
819 for (size_t i = 0; i < adata->groups_num; i++)
820 {
821 struct NntpMboxData *mdata = adata->groups_list[i];
822 if (mdata)
823 mdata->deleted = true;
824 }
828
829 destroy_state(&priv->state);
830 if (priv->state.is_mailbox_list)
831 {
832 examine_mailboxes(priv->mailbox, priv->menu, &priv->state);
833 }
834 else
835 {
836 if (examine_directory(priv->mailbox, priv->menu, &priv->state, NULL, NULL) == -1)
837 return FR_ERROR;
838 }
839 init_menu(&priv->state, priv->menu, priv->mailbox, priv->sbar);
840 return FR_SUCCESS;
841}
842
846static int op_mailbox_list(struct BrowserPrivateData *priv, const struct KeyEvent *event)
847{
849 return FR_SUCCESS;
850}
851
855static int op_rename_mailbox(struct BrowserPrivateData *priv, const struct KeyEvent *event)
856{
857 int index = menu_get_index(priv->menu);
858 struct FolderFile *ff = ARRAY_GET(&priv->state.entry, index);
859 if (!ff->imap)
860 {
861 mutt_error(_("Rename is only supported for IMAP mailboxes"));
862 return FR_ERROR;
863 }
864
865 if (imap_mailbox_rename(ff->name) < 0)
866 return FR_ERROR;
867
868 destroy_state(&priv->state);
869 init_state(&priv->state);
870 priv->state.imap_browse = true;
872 browser_sort(&priv->state);
873 browser_highlight_default(&priv->state, priv->menu);
874 init_menu(&priv->state, priv->menu, priv->mailbox, priv->sbar);
875
876 return FR_SUCCESS;
877}
878
886static int op_sort(struct BrowserPrivateData *priv, const struct KeyEvent *event)
887{
888 bool resort = true;
889 int sort = -1;
890 const int op = event->op;
891 int reverse = (op == OP_SORT_REVERSE);
892
893 switch (mw_multi_choice((reverse) ?
894 /* L10N: The highlighted letters must match the "Sort" options */
895 _("Reverse sort by (d)ate, (a)lpha, si(z)e, d(e)scription, (c)ount, ne(w) count, or do(n)'t sort?") :
896 /* L10N: The highlighted letters must match the "Reverse Sort" options */
897 _("Sort by (d)ate, (a)lpha, si(z)e, d(e)scription, (c)ount, ne(w) count, or do(n)'t sort?"),
898 /* L10N: These must match the highlighted letters from "Sort" and "Reverse Sort" */
899 _("dazecwn")))
900 {
901 case -1: /* abort */
902 resort = false;
903 break;
904
905 case 1: /* (d)ate */
906 sort = BROWSER_SORT_DATE;
907 break;
908
909 case 2: /* (a)lpha */
910 sort = BROWSER_SORT_ALPHA;
911 break;
912
913 case 3: /* si(z)e */
914 sort = BROWSER_SORT_SIZE;
915 break;
916
917 case 4: /* d(e)scription */
918 sort = BROWSER_SORT_DESC;
919 break;
920
921 case 5: /* (c)ount */
922 sort = BROWSER_SORT_COUNT;
923 break;
924
925 case 6: /* ne(w) count */
926 sort = BROWSER_SORT_NEW;
927 break;
928
929 case 7: /* do(n)'t sort */
931 break;
932 }
933
934 if (!resort)
935 return FR_NO_ACTION;
936
937 sort |= reverse ? SORT_REVERSE : 0;
938 cs_subset_str_native_set(NeoMutt->sub, "browser_sort", sort, NULL);
939 browser_sort(&priv->state);
940 browser_highlight_default(&priv->state, priv->menu);
942 return FR_SUCCESS;
943}
944
952static int op_subscribe_pattern(struct BrowserPrivateData *priv, const struct KeyEvent *event)
953{
954 if (!OptNews)
955 return FR_NOT_IMPL;
956
958 regex_t rx = { 0 };
959 int index = menu_get_index(priv->menu);
960
961 char tmp2[256] = { 0 };
962
963 const int op = event->op;
964 struct Buffer *buf = buf_pool_get();
965 if (op == OP_SUBSCRIBE_PATTERN)
966 snprintf(tmp2, sizeof(tmp2), _("Subscribe pattern: "));
967 else
968 snprintf(tmp2, sizeof(tmp2), _("Unsubscribe pattern: "));
969 /* buf comes from the buffer pool, so defaults to size 1024 */
970 if ((mw_get_field(tmp2, buf, MUTT_COMP_NO_FLAGS, HC_PATTERN, &CompletePatternOps, NULL) != 0) ||
971 buf_is_empty(buf))
972 {
973 buf_pool_release(&buf);
974 return FR_NO_ACTION;
975 }
976
977 int err = REG_COMP(&rx, buf->data, REG_NOSUB);
978 if (err != 0)
979 {
980 regerror(err, &rx, buf->data, buf->dsize);
981 regfree(&rx);
982 mutt_error("%s", buf_string(buf));
983 buf_pool_release(&buf);
984 return FR_ERROR;
985 }
987 index = 0;
988 buf_pool_release(&buf);
989
990 int rc = nntp_newsrc_parse(adata);
991 if (rc < 0)
992 return FR_ERROR;
993
994 struct FolderFile *ff = NULL;
995 ARRAY_FOREACH_FROM(ff, &priv->state.entry, index)
996 {
997 if (regexec(&rx, ff->name, 0, NULL, 0) == 0)
998 {
999 if (op == OP_SUBSCRIBE_PATTERN)
1000 mutt_newsgroup_subscribe(adata, ff->name);
1001 else
1002 mutt_newsgroup_unsubscribe(adata, ff->name);
1003 }
1004 }
1005
1006 if (op == OP_SUBSCRIBE_PATTERN)
1007 {
1008 for (size_t j = 0; j < adata->groups_num; j++)
1009 {
1010 struct NntpMboxData *mdata = adata->groups_list[j];
1011 if (mdata && mdata->group && !mdata->subscribed)
1012 {
1013 if (regexec(&rx, mdata->group, 0, NULL, 0) == 0)
1014 {
1016 browser_add_folder(priv->menu, &priv->state, mdata->group, NULL, NULL, NULL, mdata);
1017 }
1018 }
1019 }
1020 init_menu(&priv->state, priv->menu, priv->mailbox, priv->sbar);
1021 }
1022 if (rc > 0)
1027 regfree(&rx);
1028 return FR_SUCCESS;
1029}
1030
1038static int op_toggle_mailboxes(struct BrowserPrivateData *priv, const struct KeyEvent *event)
1039{
1040 if (priv->state.is_mailbox_list)
1041 {
1043 }
1044
1045 const int op = event->op;
1046 if (op == OP_TOGGLE_MAILBOXES)
1047 {
1049 }
1050
1051 if (op == OP_BROWSER_GOTO_FOLDER)
1052 {
1053 /* When in mailboxes mode, disables this feature */
1054 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
1055 if (c_folder)
1056 {
1057 mutt_debug(LL_DEBUG3, "= hit! Folder: %s, LastDir: %s\n", c_folder,
1059 if (priv->goto_swapper[0] == '\0')
1060 {
1061 if (!mutt_str_equal(buf_string(&LastDir), c_folder))
1062 {
1063 /* Stores into goto_swapper LastDir, and swaps to `$folder` */
1064 mutt_str_copy(priv->goto_swapper, buf_string(&LastDir), sizeof(priv->goto_swapper));
1066 buf_strcpy(&LastDir, c_folder);
1067 }
1068 }
1069 else
1070 {
1073 priv->goto_swapper[0] = '\0';
1074 }
1075 }
1076 }
1077 destroy_state(&priv->state);
1078 buf_reset(priv->prefix);
1079 priv->kill_prefix = false;
1080
1081 if (priv->state.is_mailbox_list)
1082 {
1083 examine_mailboxes(priv->mailbox, priv->menu, &priv->state);
1084 }
1085 else if (imap_path_probe(buf_string(&LastDir), NULL) == MUTT_IMAP)
1086 {
1087 init_state(&priv->state);
1088 priv->state.imap_browse = true;
1090 browser_sort(&priv->state);
1091 }
1092 else if (examine_directory(priv->mailbox, priv->menu, &priv->state,
1093 buf_string(&LastDir), buf_string(priv->prefix)) == -1)
1094 {
1095 priv->done = true;
1096 return FR_ERROR;
1097 }
1098 init_menu(&priv->state, priv->menu, priv->mailbox, priv->sbar);
1099 if (priv->state.is_mailbox_list)
1101 return FR_ERROR;
1102}
1103
1104// -----------------------------------------------------------------------------
1105
1109static const struct BrowserFunction BrowserFunctions[] = {
1110 // clang-format off
1111 { OP_BROWSER_GOTO_FOLDER, op_toggle_mailboxes },
1112 { OP_BROWSER_NEW_FILE, op_browser_new_file },
1113 { OP_BROWSER_SUBSCRIBE, op_browser_subscribe },
1114 { OP_BROWSER_TELL, op_browser_tell },
1115 { OP_BROWSER_TOGGLE_LSUB, op_browser_toggle_lsub },
1116 { OP_BROWSER_UNSUBSCRIBE, op_browser_subscribe },
1117 { OP_BROWSER_VIEW_FILE, op_browser_view_file },
1118 { OP_CATCHUP, op_catchup },
1119 { OP_CHANGE_DIRECTORY, op_change_directory },
1120 { OP_CHECK_NEW, op_toggle_mailboxes },
1121 { OP_CREATE_MAILBOX, op_create_mailbox },
1122 { OP_DELETE_MAILBOX, op_delete_mailbox },
1123 { OP_DESCEND_DIRECTORY, op_generic_select_entry },
1124 { OP_ENTER_MASK, op_enter_mask },
1125 { OP_EXIT, op_exit },
1126 { OP_GENERIC_SELECT_ENTRY, op_generic_select_entry },
1127 { OP_GOTO_PARENT, op_change_directory },
1128 { OP_LOAD_ACTIVE, op_load_active },
1129 { OP_MAILBOX_LIST, op_mailbox_list },
1130 { OP_RENAME_MAILBOX, op_rename_mailbox },
1131 { OP_SORT, op_sort },
1132 { OP_SORT_REVERSE, op_sort },
1133 { OP_SUBSCRIBE_PATTERN, op_subscribe_pattern },
1134 { OP_TOGGLE_MAILBOXES, op_toggle_mailboxes },
1135 { OP_UNCATCHUP, op_catchup },
1136 { OP_UNSUBSCRIBE_PATTERN, op_subscribe_pattern },
1137 { 0, NULL },
1138 // clang-format on
1139};
1140
1147int browser_function_dispatcher(struct MuttWindow *win, const struct KeyEvent *event)
1148{
1149 // The Dispatcher may be called on any Window in the Dialog
1150 struct MuttWindow *dlg = dialog_find(win);
1151 if (!dlg || !dlg->wdata)
1152 return FR_ERROR;
1153
1154 struct Menu *menu = dlg->wdata;
1155 struct BrowserPrivateData *priv = menu->mdata;
1156 if (!priv)
1157 return FR_ERROR;
1158
1159 int rc = FR_UNKNOWN;
1160 for (size_t i = 0; BrowserFunctions[i].op != OP_NULL; i++)
1161 {
1162 const struct BrowserFunction *fn = &BrowserFunctions[i];
1163 if (fn->op == event->op)
1164 {
1165 rc = fn->function(priv, event);
1166 break;
1167 }
1168 }
1169
1170 return rc;
1171}
#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_FOREACH_FROM(elem, head, from)
Iterate from an index to the end.
Definition array.h:235
#define ARRAY_GET(head, idx)
Return the element at index.
Definition array.h:109
GUI display the mailboxes in a side panel.
int bool_str_toggle(struct ConfigSubset *sub, const char *name, struct Buffer *err)
Toggle the value of a bool.
Definition bool.c:229
int imap_browse(const char *path, struct BrowserState *state)
IMAP hook into the folder browser.
Definition browse.c:196
int imap_mailbox_create(const char *path)
Create a new IMAP mailbox.
Definition browse.c:393
int imap_mailbox_rename(const char *path)
Rename a mailbox.
Definition browse.c:448
const struct CompleteOps CompleteMailboxOps
Auto-Completion of Files / Mailboxes.
Definition complete.c:159
static const struct MenuOpSeq BrowserDefaultBindings[]
Key bindings for the file Browser Menu.
Definition functions.c:101
void browser_init_keys(struct SubMenu *sm_generic)
Initialise the Browser Keybindings - Implements ::init_keys_api.
Definition functions.c:127
static const struct MenuFuncOp OpBrowser[]
Functions for the file Browser Menu.
Definition functions.c:67
void destroy_state(struct BrowserState *state)
Free the BrowserState.
Definition functions.c:145
int browser_function_dispatcher(struct MuttWindow *win, const struct KeyEvent *event)
Perform a Browser function.
Definition functions.c:1147
static const struct BrowserFunction BrowserFunctions[]
All the NeoMutt functions that the Browser supports.
Definition functions.c:1109
Browser functions.
Select a Mailbox from a list.
void browser_sort(struct BrowserState *state)
Sort the entries in the browser.
Definition sort.c:186
Private state data for the Browser.
Browser sorting functions.
@ BROWSER_SORT_ALPHA
Sort by name.
Definition sort.h:31
@ BROWSER_SORT_UNSORTED
Sort into the raw order.
Definition sort.h:37
@ BROWSER_SORT_COUNT
Sort by total message count.
Definition sort.h:32
@ BROWSER_SORT_DATE
Sort by date.
Definition sort.h:33
@ BROWSER_SORT_NEW
Sort by count of new messages.
Definition sort.h:35
@ BROWSER_SORT_SIZE
Sort by size.
Definition sort.h:36
@ BROWSER_SORT_DESC
Sort by description.
Definition sort.h:34
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:161
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition buffer.c:491
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition buffer.c:76
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition buffer.c:291
void buf_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition buffer.c:182
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition buffer.c:241
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition buffer.c:226
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:395
size_t buf_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition buffer.c:601
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition buffer.c:571
size_t buf_concat_path(struct Buffer *buf, const char *dir, const char *fname)
Join a directory name and a filename.
Definition buffer.c:509
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
const struct Regex * cs_subset_regex(const struct ConfigSubset *sub, const char *name)
Get a regex config item by name.
Definition helpers.c:217
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition helpers.c:291
Convenience wrapper for the config headers.
#define CSR_RESULT(x)
Extract the result code from CSR_* flags.
Definition set.h:52
#define CSR_SUCCESS
Action completed successfully.
Definition set.h:33
#define SORT_REVERSE
Reverse the order of the sort.
Definition sort.h:40
Convenience wrapper for the core headers.
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition mailbox.h:213
MailboxType
Supported mailbox formats.
Definition mailbox.h:40
@ MUTT_MAILBOX_ERROR
Error occurred examining Mailbox.
Definition mailbox.h:42
@ MUTT_IMAP
'IMAP' Mailbox type
Definition mailbox.h:49
@ MUTT_UNKNOWN
Mailbox wasn't recognised.
Definition mailbox.h:43
struct MuttWindow * dialog_find(struct MuttWindow *win)
Find the parent Dialog of a Window.
Definition dialog.c:89
@ FR_SUCCESS
Valid function - successfully performed.
Definition dispatcher.h:40
@ FR_DONE
Exit the Dialog.
Definition dispatcher.h:36
@ FR_UNKNOWN
Unknown function.
Definition dispatcher.h:34
@ FR_ERROR
Valid function - error occurred.
Definition dispatcher.h:39
@ FR_NOT_IMPL
Invalid function - feature not enabled.
Definition dispatcher.h:37
@ FR_NO_ACTION
Valid function - no action performed.
Definition dispatcher.h:38
int examine_directory(struct Mailbox *m, struct Menu *menu, struct BrowserState *state, const char *dirname, const char *prefix)
Get list of all files/newsgroups with mask.
void init_menu(struct BrowserState *state, struct Menu *menu, struct Mailbox *m, struct MuttWindow *sbar)
Set up a new menu.
struct Buffer LastDir
Browser: previous selected directory.
void init_state(struct BrowserState *state)
Initialise a browser state.
struct Buffer LastDirBackup
Browser: backup copy of the current directory.
void browser_add_folder(const struct Menu *menu, struct BrowserState *state, const char *name, const char *desc, const struct stat *st, struct Mailbox *m, void *data)
Add a folder to the browser list.
void browser_highlight_default(struct BrowserState *state, struct Menu *menu)
Decide which browser item should be highlighted.
int examine_mailboxes(struct Mailbox *m, struct Menu *menu, struct BrowserState *state)
Get list of mailboxes/subscribed newsgroups.
bool link_is_dir(const char *folder, const char *path)
Does this symlink point to a directory?
Edit a string.
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition wdata.h:42
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition body.c:58
Structs that make up an email.
void mutt_unget_op(int op)
Return an operation to the input buffer.
Definition get.c:133
#define MFF_DEPRECATED
Redraw the pager.
Definition get.h:44
bool OptNews
(pseudo) used to change reader mode
Definition globals.c:53
Global variables.
static int op_generic_select_entry(struct AliasMenuData *mdata, const struct KeyEvent *event)
select the current entry - Implements alias_function_t -
Definition functions.c:231
static int op_sort(struct AliasMenuData *mdata, const struct KeyEvent *event)
sort aliases - Implements alias_function_t -
Definition functions.c:406
static int op_exit(struct AliasMenuData *mdata, const struct KeyEvent *event)
exit this menu - Implements alias_function_t -
Definition functions.c:217
static int op_browser_new_file(struct BrowserPrivateData *priv, const struct KeyEvent *event)
Select a new file in this directory - Implements browser_function_t -.
Definition functions.c:162
static int op_rename_mailbox(struct BrowserPrivateData *priv, const struct KeyEvent *event)
Rename the current mailbox (IMAP only) - Implements browser_function_t -.
Definition functions.c:855
static int op_create_mailbox(struct BrowserPrivateData *priv, const struct KeyEvent *event)
Create a new mailbox (IMAP only) - Implements browser_function_t -.
Definition functions.c:462
static int op_browser_view_file(struct BrowserPrivateData *priv, const struct KeyEvent *event)
View file - Implements browser_function_t -.
Definition functions.c:268
static int op_mailbox_list(struct BrowserPrivateData *priv, const struct KeyEvent *event)
List mailboxes with new mail - Implements browser_function_t -.
Definition functions.c:846
static int op_catchup(struct BrowserPrivateData *priv, const struct KeyEvent *event)
Mark all articles in newsgroup as read - Implements browser_function_t -.
Definition functions.c:313
static int op_browser_subscribe(struct BrowserPrivateData *priv, const struct KeyEvent *event)
Subscribe to current mbox (IMAP/NNTP only) - Implements browser_function_t -.
Definition functions.c:189
static int op_delete_mailbox(struct BrowserPrivateData *priv, const struct KeyEvent *event)
Delete the current mailbox (IMAP only) - Implements browser_function_t -.
Definition functions.c:489
static int op_load_active(struct BrowserPrivateData *priv, const struct KeyEvent *event)
Load list of all newsgroups from NNTP server - Implements browser_function_t -.
Definition functions.c:809
static int op_enter_mask(struct BrowserPrivateData *priv, const struct KeyEvent *event)
Enter a file mask - Implements browser_function_t -.
Definition functions.c:537
static int op_subscribe_pattern(struct BrowserPrivateData *priv, const struct KeyEvent *event)
Subscribe to newsgroups matching a pattern - Implements browser_function_t -.
Definition functions.c:952
static int op_browser_tell(struct BrowserPrivateData *priv, const struct KeyEvent *event)
Display the currently selected file's name - Implements browser_function_t -.
Definition functions.c:244
static int op_browser_toggle_lsub(struct BrowserPrivateData *priv, const struct KeyEvent *event)
Toggle view all/subscribed mailboxes (IMAP only) - Implements browser_function_t -.
Definition functions.c:257
static int op_toggle_mailboxes(struct BrowserPrivateData *priv, const struct KeyEvent *event)
Toggle whether to browse mailboxes or all files - Implements browser_function_t -.
Definition functions.c:1038
static int op_change_directory(struct BrowserPrivateData *priv, const struct KeyEvent *event)
Change directories - Implements browser_function_t -.
Definition functions.c:353
int mw_get_field(const char *prompt, struct Buffer *buf, CompletionFlags complete, enum HistoryClass hclass, const struct CompleteOps *comp_api, void *cdata)
Ask the user for a string -.
Definition window.c:271
int mw_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question -.
Definition question.c:62
#define mutt_warning(...)
Definition logging2.h:92
#define mutt_error(...)
Definition logging2.h:94
#define mutt_message(...)
Definition logging2.h:93
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
#define mutt_perror(...)
Definition logging2.h:95
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox?
Definition imap.c:2543
Convenience wrapper for the gui headers.
Read/write command history from/to a file.
@ HC_FILE
Files.
Definition lib.h:58
@ HC_PATTERN
Patterns.
Definition lib.h:59
@ HC_OTHER
Miscellaneous strings.
Definition lib.h:60
IMAP network mailbox.
int imap_subscribe(const char *path, bool subscribe)
Subscribe to a mailbox.
Definition imap.c:1405
int imap_delete_mailbox(struct Mailbox *m, char *path)
Delete a mailbox.
Definition imap.c:611
void km_menu_add_submenu(struct MenuDefinition *md, struct SubMenu *sm)
Add a SubMenu to a Menu Definition.
Definition init.c:123
struct SubMenu * km_register_submenu(const struct MenuFuncOp functions[])
Register a submenu.
Definition init.c:91
struct MenuDefinition * km_register_menu(int menu, const char *name)
Register a menu.
Definition init.c:107
void km_menu_add_bindings(struct MenuDefinition *md, const struct MenuOpSeq bindings[])
Add Keybindings to a Menu.
Definition init.c:136
Manage keymappings.
@ LL_DEBUG3
Log at debug level 3.
Definition logging2.h:47
#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
GUI present the user with a selectable list.
#define MENU_REDRAW_FULL
Redraw everything.
Definition lib.h:59
#define MENU_REDRAW_INDEX
Redraw the index.
Definition lib.h:56
void menu_queue_redraw(struct Menu *menu, MenuRedrawFlags redraw)
Queue a request for a redraw.
Definition menu.c:186
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition menu.c:162
MenuRedrawFlags menu_set_index(struct Menu *menu, int index)
Set the current selection in the Menu.
Definition menu.c:176
Convenience wrapper for the library headers.
#define _(a)
Definition message.h:28
size_t mutt_path_realpath(struct Buffer *path)
Resolve path, unraveling symlinks.
Definition path.c:377
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:662
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition string.c:583
int mutt_view_attachment(FILE *fp, struct Body *b, enum ViewAttachMode mode, struct Email *e, struct AttachCtx *actx, struct MuttWindow *win)
View an attachment.
@ MUTT_VA_REGULAR
View using default method.
Definition mutt_attach.h:44
bool mutt_mailbox_list(void)
Show a message with the list of mailboxes with new mail.
Mailbox helper functions.
void mutt_get_parent_path(const char *path, char *buf, size_t buflen)
Find the parent of a path (or mailbox)
Definition muttlib.c:866
void expand_path(struct Buffer *buf, bool regex)
Create the canonical path.
Definition muttlib.c:121
Some miscellaneous functions.
enum MailboxType mx_path_probe(const char *path)
Find a mailbox that understands a path.
Definition mx.c:1323
API for mailboxes.
Nntp-specific Account data.
Usenet network mailbox type; talk to an NNTP server.
void nntp_clear_cache(struct NntpAccountData *adata)
Clear the NNTP cache.
Definition newsrc.c:840
int nntp_active_fetch(struct NntpAccountData *adata, bool mark_new)
Fetch list of all newsgroups from server.
Definition nntp.c:2034
int nntp_newsrc_parse(struct NntpAccountData *adata)
Parse .newsrc file.
Definition newsrc.c:163
void nntp_newsrc_close(struct NntpAccountData *adata)
Unlock and close .newsrc file.
Definition newsrc.c:119
struct NntpMboxData * mutt_newsgroup_catchup(struct Mailbox *m, struct NntpAccountData *adata, char *group)
Catchup newsgroup.
Definition newsrc.c:1225
int nntp_newsrc_update(struct NntpAccountData *adata)
Update .newsrc file.
Definition newsrc.c:442
struct NntpMboxData * mutt_newsgroup_subscribe(struct NntpAccountData *adata, char *group)
Subscribe newsgroup.
Definition newsrc.c:1174
struct NntpMboxData * mutt_newsgroup_uncatchup(struct Mailbox *m, struct NntpAccountData *adata, char *group)
Uncatchup newsgroup.
Definition newsrc.c:1264
struct NntpAccountData * CurrentNewsSrv
Current NNTP news server.
Definition nntp.c:74
struct NntpMboxData * mutt_newsgroup_unsubscribe(struct NntpAccountData *adata, char *group)
Unsubscribe newsgroup.
Definition newsrc.c:1198
Nntp-specific Mailbox data.
const struct CompleteOps CompletePatternOps
Auto-Completion of Patterns.
Definition complete.c:97
Match patterns to emails.
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
@ MUTT_NO
User answered 'No', or assume 'No'.
Definition quad.h:38
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition quad.h:39
Ask the user a question.
enum QuadOption query_yesorno(const char *prompt, enum QuadOption def)
Ask the user a Yes/No question.
Definition question.c:326
#define REG_COMP(preg, regex, cflags)
Compile a regular expression.
Definition regex3.h:49
Convenience wrapper for the send headers.
struct Body * mutt_make_file_attach(const char *path, struct ConfigSubset *sub)
Create a file attachment.
Definition sendlib.c:606
void * adata
Private data (for Mailbox backends)
Definition account.h:42
The body of an email.
Definition body.h:36
A NeoMutt function.
Definition functions.h:49
int op
Op code, e.g. OP_MAIN_LIMIT.
Definition functions.h:50
browser_function_t function
Function to call.
Definition functions.h:51
Private state data for the Browser.
char *** files
Array of selected files.
struct Menu * menu
Menu.
struct Buffer * prefix
Folder prefix string.
struct Buffer * old_last_dir
Previous to last dir.
bool kill_prefix
Prefix is in use.
bool done
Should we close the Dialog?
int last_selected_mailbox
Index of last selected Mailbox.
int * numfiles
Number of selected files.
struct Mailbox * mailbox
Mailbox.
struct BrowserState state
State containing list of files/dir/mailboxes.
struct Buffer * file
Buffer for the result.
bool multiple
Allow multiple selections.
struct MuttWindow * sbar
Status Bar.
char goto_swapper[PATH_MAX]
Saved path after <goto-folder>
State of the file/mailbox browser.
Definition lib.h:145
char * folder
Folder name.
Definition lib.h:148
bool is_mailbox_list
Viewing mailboxes.
Definition lib.h:149
struct BrowserEntryArray entry
Array of files / dirs / mailboxes.
Definition lib.h:146
bool imap_browse
IMAP folder.
Definition lib.h:147
String manipulation buffer.
Definition buffer.h:36
size_t dsize
Length of data.
Definition buffer.h:39
char * data
Pointer to data.
Definition buffer.h:37
Input for the file completion function.
Definition curs_lib.h:39
Browser entry representing a folder/dir.
Definition lib.h:79
bool selectable
Folder can be selected.
Definition lib.h:97
char delim
Path delimiter.
Definition lib.h:94
bool imap
This is an IMAP folder.
Definition lib.h:96
char * name
Name of file/dir/mailbox.
Definition lib.h:87
bool tagged
Folder is tagged.
Definition lib.h:103
char * desc
Description of mailbox.
Definition lib.h:88
mode_t mode
File permissions.
Definition lib.h:80
bool inferiors
Folder has children.
Definition lib.h:98
An event such as a keypress.
Definition get.h:50
int op
Function opcode, e.g. OP_HELP.
Definition get.h:52
void * mdata
Driver specific data.
Definition mailbox.h:131
Functions for a Dialog or Window.
Definition menu.h:81
Mapping between a function and an operation.
Definition menu.h:39
Mapping between an operation and a key sequence.
Definition menu.h:49
Definition lib.h:79
struct MuttWindow * win
Window holding the Menu.
Definition lib.h:87
int num_tagged
Number of tagged entries.
Definition lib.h:94
void * mdata
Private data.
Definition lib.h:148
bool tag_prefix
User has pressed <tag-prefix>
Definition lib.h:85
void * wdata
Private data.
Container for Accounts, Notifications.
Definition neomutt.h:41
char * home_dir
User's home directory.
Definition neomutt.h:56
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
NNTP-specific Account data -.
Definition adata.h:36
struct NntpMboxData ** groups_list
List of newsgroups.
Definition adata.h:60
unsigned int groups_num
Number of newsgroups.
Definition adata.h:58
NNTP-specific Mailbox data -.
Definition mdata.h:34
bool deleted
Newsgroup is deleted.
Definition mdata.h:45
struct NntpAccountData * adata
Account data.
Definition mdata.h:48
Cached regular expression.
Definition regex3.h:85
char * pattern
printable version
Definition regex3.h:86
Collection of related functions.
Definition menu.h:69
A parsed URL proto://user:password@host:port/path?a=1&b=2
Definition url.h:69
char * path
Path.
Definition url.h:75
int cs_subset_str_native_set(const struct ConfigSubset *sub, const char *name, intptr_t value, struct Buffer *err)
Natively set the value of a string config item.
Definition subset.c:303
int cs_subset_str_string_set(const struct ConfigSubset *sub, const char *name, const char *value, struct Buffer *err)
Set a config item by string.
Definition subset.c:392
@ MENU_BROWSER
General file/mailbox browser.
Definition type.h:39
struct Url * url_parse(const char *src)
Fill in Url.
Definition url.c:239
void url_free(struct Url **ptr)
Free the contents of a URL.
Definition url.c:124