NeoMutt  2024-03-23-23-gec7045
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
functions.c
Go to the documentation of this file.
1
30#include "config.h"
31#ifdef _MAKEDOC
32#include "docs/makedoc_defs.h"
33#else
34#include <stdbool.h>
35#include <stdio.h>
36#include <string.h>
37#include <sys/stat.h>
38#include "mutt/lib.h"
39#include "config/lib.h"
40#include "email/lib.h"
41#include "core/lib.h"
42#include "gui/lib.h"
43#include "mutt.h"
44#include "lib.h"
45#include "attach/lib.h"
46#include "editor/lib.h"
47#include "history/lib.h"
48#include "imap/lib.h"
49#include "key/lib.h"
50#include "menu/lib.h"
51#include "nntp/lib.h"
52#include "pattern/lib.h"
53#include "question/lib.h"
54#include "send/lib.h"
55#include "functions.h"
56#include "globals.h"
57#include "mutt_mailbox.h"
58#include "muttlib.h"
59#include "mx.h"
60#include "nntp/adata.h"
61#include "nntp/mdata.h"
62#include "private_data.h"
63#endif
64
66static const char *Not_available_in_this_menu = N_("Not available in this menu");
67
68static int op_subscribe_pattern(struct BrowserPrivateData *priv, int op);
69
70// clang-format off
74const struct MenuFuncOp OpBrowser[] = { /* map: browser */
75 { "catchup", OP_CATCHUP },
76 { "change-dir", OP_CHANGE_DIRECTORY },
77 { "check-new", OP_CHECK_NEW },
78 { "create-mailbox", OP_CREATE_MAILBOX },
79 { "delete-mailbox", OP_DELETE_MAILBOX },
80 { "descend-directory", OP_DESCEND_DIRECTORY },
81 { "display-filename", OP_BROWSER_TELL },
82 { "enter-mask", OP_ENTER_MASK },
83 { "exit", OP_EXIT },
84 { "goto-folder", OP_BROWSER_GOTO_FOLDER },
85 { "goto-parent", OP_GOTO_PARENT },
86 { "mailbox-list", OP_MAILBOX_LIST },
87 { "reload-active", OP_LOAD_ACTIVE },
88 { "rename-mailbox", OP_RENAME_MAILBOX },
89 { "select-new", OP_BROWSER_NEW_FILE },
90 { "sort", OP_SORT },
91 { "sort-reverse", OP_SORT_REVERSE },
92 { "subscribe", OP_BROWSER_SUBSCRIBE },
93 { "subscribe-pattern", OP_SUBSCRIBE_PATTERN },
94 { "toggle-mailboxes", OP_TOGGLE_MAILBOXES },
95 { "toggle-subscribed", OP_BROWSER_TOGGLE_LSUB },
96 { "uncatchup", OP_UNCATCHUP },
97 { "unsubscribe", OP_BROWSER_UNSUBSCRIBE },
98 { "unsubscribe-pattern", OP_UNSUBSCRIBE_PATTERN },
99 { "view-file", OP_BROWSER_VIEW_FILE },
100 // Deprecated
101 { "buffy-list", OP_MAILBOX_LIST },
102 { NULL, 0 },
103};
104
108const struct MenuOpSeq BrowserDefaultBindings[] = { /* map: browser */
109 { OP_BROWSER_GOTO_FOLDER, "=" },
110 { OP_BROWSER_NEW_FILE, "N" },
111 { OP_BROWSER_SUBSCRIBE, "s" },
112 { OP_BROWSER_TELL, "@" },
113 { OP_BROWSER_TOGGLE_LSUB, "T" },
114 { OP_BROWSER_UNSUBSCRIBE, "u" },
115 { OP_BROWSER_VIEW_FILE, " " }, // <Space>
116 { OP_CHANGE_DIRECTORY, "c" },
117 { OP_CREATE_MAILBOX, "C" },
118 { OP_DELETE_MAILBOX, "d" },
119 { OP_ENTER_MASK, "m" },
120 { OP_EXIT, "q" },
121 { OP_GOTO_PARENT, "p" },
122 { OP_MAILBOX_LIST, "." },
123 { OP_RENAME_MAILBOX, "r" },
124 { OP_SORT, "o" },
125 { OP_SORT_REVERSE, "O" },
126 { OP_TOGGLE_MAILBOXES, "\t" }, // <Tab>
127 { 0, NULL },
128};
129// clang-format on
130
137void destroy_state(struct BrowserState *state)
138{
139 struct FolderFile *ff = NULL;
140 ARRAY_FOREACH(ff, &state->entry)
141 {
142 FREE(&ff->name);
143 FREE(&ff->desc);
144 }
145 ARRAY_FREE(&state->entry);
146 FREE(&state->folder);
147}
148
149// -----------------------------------------------------------------------------
150
154static int op_browser_new_file(struct BrowserPrivateData *priv, int op)
155{
156 struct Buffer *buf = buf_pool_get();
157 buf_printf(buf, "%s/", buf_string(&LastDir));
158
159 struct FileCompletionData cdata = { false, priv->mailbox, NULL, NULL };
160 const int rc = mw_get_field(_("New file name: "), buf, MUTT_COMP_NO_FLAGS,
161 HC_FILE, &CompleteMailboxOps, &cdata);
162 if (rc != 0)
163 {
164 buf_pool_release(&buf);
165 return FR_NO_ACTION;
166 }
167
168 buf_copy(priv->file, buf);
169 buf_pool_release(&buf);
170 priv->done = true;
171 return FR_DONE;
172}
173
181static int op_browser_subscribe(struct BrowserPrivateData *priv, int op)
182{
183 if (OptNews)
184 {
186 int index = menu_get_index(priv->menu);
187
188 if (ARRAY_EMPTY(&priv->state.entry))
189 {
190 mutt_error(_("No newsgroups match the mask"));
191 return FR_ERROR;
192 }
193
194 int rc = nntp_newsrc_parse(adata);
195 if (rc < 0)
196 return FR_ERROR;
197
198 struct FolderFile *ff = ARRAY_GET(&priv->state.entry, index);
199 if (op == OP_BROWSER_SUBSCRIBE)
200 mutt_newsgroup_subscribe(adata, ff->name);
201 else
203
204 menu_set_index(priv->menu, index + 1);
205
206 if (rc > 0)
208 nntp_newsrc_update(adata);
209 nntp_clear_cache(adata);
210 nntp_newsrc_close(adata);
211 }
212 else
213 {
214 if (ARRAY_EMPTY(&priv->state.entry))
215 {
216 mutt_error(_("There are no mailboxes"));
217 return FR_ERROR;
218 }
219
220 char tmp2[256] = { 0 };
221 int index = menu_get_index(priv->menu);
222 struct FolderFile *ff = ARRAY_GET(&priv->state.entry, index);
223 mutt_str_copy(tmp2, ff->name, sizeof(tmp2));
224 mutt_expand_path(tmp2, sizeof(tmp2));
225 imap_subscribe(tmp2, (op == OP_BROWSER_SUBSCRIBE));
226 }
227 return FR_SUCCESS;
228}
229
233static int op_browser_tell(struct BrowserPrivateData *priv, int op)
234{
235 int index = menu_get_index(priv->menu);
236 if (ARRAY_EMPTY(&priv->state.entry))
237 return FR_ERROR;
238
239 mutt_message("%s", ARRAY_GET(&priv->state.entry, index)->name);
240 return FR_SUCCESS;
241}
242
246static int op_browser_toggle_lsub(struct BrowserPrivateData *priv, int op)
247{
248 bool_str_toggle(NeoMutt->sub, "imap_list_subscribed", NULL);
249
250 mutt_unget_op(OP_CHECK_NEW);
251 return FR_SUCCESS;
252}
253
257static int op_browser_view_file(struct BrowserPrivateData *priv, int op)
258{
259 if (ARRAY_EMPTY(&priv->state.entry))
260 {
261 mutt_error(_("No files match the file mask"));
262 return FR_ERROR;
263 }
264
265 int index = menu_get_index(priv->menu);
266 struct FolderFile *ff = ARRAY_GET(&priv->state.entry, index);
267 if (ff->selectable)
268 {
269 buf_strcpy(priv->file, ff->name);
270 priv->done = true;
271 return FR_DONE;
272 }
273 else if (S_ISDIR(ff->mode) ||
274 (S_ISLNK(ff->mode) && link_is_dir(buf_string(&LastDir), ff->name)))
275 {
276 mutt_error(_("Can't view a directory"));
277 return FR_ERROR;
278 }
279 else
280 {
281 struct Buffer *path = buf_pool_get();
283 struct Body *b = mutt_make_file_attach(buf_string(path), NeoMutt->sub);
284 if (b)
285 {
286 mutt_view_attachment(NULL, b, MUTT_VA_REGULAR, NULL, NULL, priv->menu->win);
287 mutt_body_free(&b);
289 }
290 else
291 {
292 mutt_error(_("Error trying to view file"));
293 }
294 buf_pool_release(&path);
295 }
296 return FR_ERROR;
297}
298
302static int op_catchup(struct BrowserPrivateData *priv, int op)
303{
304 if (!OptNews)
305 return FR_NOT_IMPL;
306
307 struct NntpMboxData *mdata = NULL;
308
310 if (rc < 0)
311 return FR_ERROR;
312
313 int index = menu_get_index(priv->menu);
314 struct FolderFile *ff = ARRAY_GET(&priv->state.entry, index);
315 if (op == OP_CATCHUP)
317 else
319
320 if (mdata)
321 {
323 index = menu_get_index(priv->menu) + 1;
324 if (index < priv->menu->max)
325 menu_set_index(priv->menu, index);
326 }
327
328 if (rc != 0)
330
332 return FR_ERROR;
333}
334
342static int op_change_directory(struct BrowserPrivateData *priv, int op)
343{
344 if (OptNews)
345 return FR_NOT_IMPL;
346
347 struct Buffer *buf = buf_pool_get();
348 buf_copy(buf, &LastDir);
349 if (!priv->state.imap_browse)
350 {
351 /* add '/' at the end of the directory name if not already there */
352 size_t len = buf_len(buf);
353 if ((len > 0) && (buf_string(&LastDir)[len - 1] != '/'))
354 buf_addch(buf, '/');
355 }
356
357 if (op == OP_CHANGE_DIRECTORY)
358 {
359 struct FileCompletionData cdata = { false, priv->mailbox, NULL, NULL };
360 int rc = mw_get_field(_("Chdir to: "), buf, MUTT_COMP_NO_FLAGS, HC_FILE,
361 &CompleteMailboxOps, &cdata);
362 if ((rc != 0) && buf_is_empty(buf))
363 {
364 buf_pool_release(&buf);
365 return FR_NO_ACTION;
366 }
367 }
368 else if (op == OP_GOTO_PARENT)
369 {
370 mutt_get_parent_path(buf_string(buf), buf->data, buf->dsize);
371 }
372
373 if (!buf_is_empty(buf))
374 {
375 priv->state.is_mailbox_list = false;
376 buf_expand_path(buf);
377 if (imap_path_probe(buf_string(buf), NULL) == MUTT_IMAP)
378 {
379 buf_copy(&LastDir, buf);
380 destroy_state(&priv->state);
381 init_state(&priv->state, NULL);
382 priv->state.imap_browse = true;
384 browser_sort(&priv->state);
385 priv->menu->mdata = &priv->state.entry;
386 priv->menu->mdata_free = NULL; // Menu doesn't own the data
387 browser_highlight_default(&priv->state, priv->menu);
388 init_menu(&priv->state, priv->menu, priv->mailbox, priv->sbar);
389 }
390 else
391 {
392 if (buf_string(buf)[0] != '/')
393 {
394 /* in case dir is relative, make it relative to LastDir,
395 * not current working dir */
396 struct Buffer *tmp = buf_pool_get();
398 buf_copy(buf, tmp);
399 buf_pool_release(&tmp);
400 }
401 /* Resolve path from <chdir>
402 * Avoids buildup such as /a/b/../../c
403 * Symlinks are always unraveled to keep code simple */
404 if (mutt_path_realpath(buf) == 0)
405 {
406 buf_pool_release(&buf);
407 return FR_ERROR;
408 }
409
410 struct stat st = { 0 };
411 if (stat(buf_string(buf), &st) == 0)
412 {
413 if (S_ISDIR(st.st_mode))
414 {
415 destroy_state(&priv->state);
416 if (examine_directory(priv->mailbox, priv->menu, &priv->state,
417 buf_string(buf), buf_string(priv->prefix)) == 0)
418 {
419 buf_copy(&LastDir, buf);
420 }
421 else
422 {
423 mutt_error(_("Error scanning directory"));
424 if (examine_directory(priv->mailbox, priv->menu, &priv->state,
425 buf_string(&LastDir), buf_string(priv->prefix)) == -1)
426 {
427 priv->done = true;
428 return FR_ERROR;
429 }
430 }
431 browser_highlight_default(&priv->state, priv->menu);
432 init_menu(&priv->state, priv->menu, priv->mailbox, priv->sbar);
433 }
434 else
435 {
436 mutt_error(_("%s is not a directory"), buf_string(buf));
437 }
438 }
439 else
440 {
441 mutt_perror("%s", buf_string(buf));
442 }
443 }
444 }
445 buf_pool_release(&buf);
446 return FR_ERROR;
447}
448
452static int op_create_mailbox(struct BrowserPrivateData *priv, int op)
453{
454 if (!priv->state.imap_browse)
455 {
456 mutt_error(_("Create is only supported for IMAP mailboxes"));
457 return FR_ERROR;
458 }
459
461 return FR_ERROR;
462
463 /* TODO: find a way to detect if the new folder would appear in
464 * this window, and insert it without starting over. */
465 destroy_state(&priv->state);
466 init_state(&priv->state, NULL);
467 priv->state.imap_browse = true;
469 browser_sort(&priv->state);
470 priv->menu->mdata = &priv->state.entry;
471 priv->menu->mdata_free = NULL; // Menu doesn't own the data
472 browser_highlight_default(&priv->state, priv->menu);
473 init_menu(&priv->state, priv->menu, priv->mailbox, priv->sbar);
474
475 return FR_SUCCESS;
476}
477
481static int op_delete_mailbox(struct BrowserPrivateData *priv, int op)
482{
483 int index = menu_get_index(priv->menu);
484 struct FolderFile *ff = ARRAY_GET(&priv->state.entry, index);
485 if (!ff->imap)
486 {
487 mutt_error(_("Delete is only supported for IMAP mailboxes"));
488 return FR_ERROR;
489 }
490
491 char msg[128] = { 0 };
492
493 // TODO(sileht): It could be better to select INBOX instead. But I
494 // don't want to manipulate Mailboxes/mailbox->account here for now.
495 // Let's just protect neomutt against crash for now. #1417
496 if (mutt_str_equal(mailbox_path(priv->mailbox), ff->name))
497 {
498 mutt_error(_("Can't delete currently selected mailbox"));
499 return FR_ERROR;
500 }
501
502 snprintf(msg, sizeof(msg), _("Really delete mailbox \"%s\"?"), ff->name);
503 if (query_yesorno(msg, MUTT_NO) != MUTT_YES)
504 {
505 mutt_message(_("Mailbox not deleted"));
506 return FR_NO_ACTION;
507 }
508
509 if (imap_delete_mailbox(priv->mailbox, ff->name) != 0)
510 {
511 mutt_error(_("Mailbox deletion failed"));
512 return FR_ERROR;
513 }
514
515 /* free the mailbox from the browser */
516 FREE(&ff->name);
517 FREE(&ff->desc);
518 /* and move all other entries up */
519 ARRAY_REMOVE(&priv->state.entry, ff);
520 mutt_message(_("Mailbox deleted"));
521 init_menu(&priv->state, priv->menu, priv->mailbox, priv->sbar);
522
523 return FR_SUCCESS;
524}
525
529static int op_enter_mask(struct BrowserPrivateData *priv, int op)
530{
531 const struct Regex *c_mask = cs_subset_regex(NeoMutt->sub, "mask");
532 struct Buffer *buf = buf_pool_get();
533 buf_strcpy(buf, c_mask ? c_mask->pattern : NULL);
534 if (mw_get_field(_("File Mask: "), buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0)
535 {
536 buf_pool_release(&buf);
537 return FR_NO_ACTION;
538 }
539
540 buf_fix_dptr(buf);
541
542 priv->state.is_mailbox_list = false;
543 /* assume that the user wants to see everything */
544 if (buf_is_empty(buf))
545 buf_strcpy(buf, ".");
546
547 struct Buffer *errmsg = buf_pool_get();
548 int rc = cs_subset_str_string_set(NeoMutt->sub, "mask", buf_string(buf), errmsg);
549 buf_pool_release(&buf);
550 if (CSR_RESULT(rc) != CSR_SUCCESS)
551 {
552 if (!buf_is_empty(errmsg))
553 {
554 mutt_error("%s", buf_string(errmsg));
555 buf_pool_release(&errmsg);
556 }
557 return FR_ERROR;
558 }
559 buf_pool_release(&errmsg);
560
561 destroy_state(&priv->state);
562 if (priv->state.imap_browse)
563 {
564 init_state(&priv->state, NULL);
565 priv->state.imap_browse = true;
567 browser_sort(&priv->state);
568 priv->menu->mdata = &priv->state.entry;
569 priv->menu->mdata_free = NULL; // Menu doesn't own the data
570 init_menu(&priv->state, priv->menu, priv->mailbox, priv->sbar);
571 }
572 else if (examine_directory(priv->mailbox, priv->menu, &priv->state,
573 buf_string(&LastDir), NULL) == 0)
574 {
575 init_menu(&priv->state, priv->menu, priv->mailbox, priv->sbar);
576 }
577 else
578 {
579 mutt_error(_("Error scanning directory"));
580 priv->done = true;
581 return FR_ERROR;
582 }
583 priv->kill_prefix = false;
584 if (ARRAY_EMPTY(&priv->state.entry))
585 {
586 mutt_error(_("No files match the file mask"));
587 return FR_ERROR;
588 }
589 return FR_SUCCESS;
590}
591
595static int op_exit(struct BrowserPrivateData *priv, int op)
596{
597 if (priv->multiple)
598 {
599 char **tfiles = NULL;
600
601 if (priv->menu->num_tagged)
602 {
603 *priv->numfiles = priv->menu->num_tagged;
604 tfiles = mutt_mem_calloc(*priv->numfiles, sizeof(char *));
605 size_t j = 0;
606 struct FolderFile *ff = NULL;
607 ARRAY_FOREACH(ff, &priv->state.entry)
608 {
609 if (ff->tagged)
610 {
611 struct Buffer *buf = buf_pool_get();
613 buf_expand_path(buf);
614 tfiles[j++] = buf_strdup(buf);
615 buf_pool_release(&buf);
616 }
617 }
618 *priv->files = tfiles;
619 }
620 else if (!buf_is_empty(priv->file)) /* no tagged entries. return selected entry */
621 {
622 *priv->numfiles = 1;
623 tfiles = mutt_mem_calloc(*priv->numfiles, sizeof(char *));
624 buf_expand_path(priv->file);
625 tfiles[0] = buf_strdup(priv->file);
626 *priv->files = tfiles;
627 }
628 }
629
630 priv->done = true;
631 return FR_DONE;
632}
633
641static int op_generic_select_entry(struct BrowserPrivateData *priv, int op)
642{
643 if (ARRAY_EMPTY(&priv->state.entry))
644 {
645 mutt_error(_("No files match the file mask"));
646 return FR_ERROR;
647 }
648
649 int index = menu_get_index(priv->menu);
650 struct FolderFile *ff = ARRAY_GET(&priv->state.entry, index);
651 if (S_ISDIR(ff->mode) ||
652 (S_ISLNK(ff->mode) && link_is_dir(buf_string(&LastDir), ff->name)) || ff->inferiors)
653 {
654 /* make sure this isn't a MH or maildir mailbox */
655 struct Buffer *buf = buf_pool_get();
656 if (priv->state.is_mailbox_list)
657 {
658 buf_strcpy(buf, ff->name);
659 buf_expand_path(buf);
660 }
661 else if (priv->state.imap_browse)
662 {
663 buf_strcpy(buf, ff->name);
664 }
665 else
666 {
668 }
669
670 enum MailboxType type = mx_path_probe(buf_string(buf));
671 buf_pool_release(&buf);
672
673 if ((op == OP_DESCEND_DIRECTORY) || (type == MUTT_MAILBOX_ERROR) ||
674 (type == MUTT_UNKNOWN) || ff->inferiors)
675 {
676 /* save the old directory */
677 buf_copy(priv->OldLastDir, &LastDir);
678
679 if (mutt_str_equal(ff->name, ".."))
680 {
681 size_t lastdirlen = buf_len(&LastDir);
682 if ((lastdirlen > 1) && mutt_str_equal("..", buf_string(&LastDir) + lastdirlen - 2))
683 {
684 buf_addstr(&LastDir, "/..");
685 }
686 else
687 {
688 char *p = NULL;
689 if (lastdirlen > 1)
690 p = strrchr(LastDir.data + 1, '/');
691
692 if (p)
693 {
694 *p = '\0';
696 }
697 else
698 {
699 if (buf_string(&LastDir)[0] == '/')
700 buf_strcpy(&LastDir, "/");
701 else
702 buf_addstr(&LastDir, "/..");
703 }
704 }
705 }
706 else if (priv->state.is_mailbox_list)
707 {
708 buf_strcpy(&LastDir, ff->name);
710 }
711 else if (priv->state.imap_browse)
712 {
713 buf_strcpy(&LastDir, ff->name);
714 /* tack on delimiter here */
715
716 /* special case "" needs no delimiter */
717 struct Url *url = url_parse(ff->name);
718 if (url && url->path && (ff->delim != '\0'))
719 {
720 buf_addch(&LastDir, ff->delim);
721 }
722 url_free(&url);
723 }
724 else
725 {
726 struct Buffer *tmp = buf_pool_get();
728 buf_copy(&LastDir, tmp);
729 buf_pool_release(&tmp);
730 }
731
732 destroy_state(&priv->state);
733 if (priv->kill_prefix)
734 {
735 buf_reset(priv->prefix);
736 priv->kill_prefix = false;
737 }
738 priv->state.is_mailbox_list = false;
739 if (priv->state.imap_browse)
740 {
741 init_state(&priv->state, NULL);
742 priv->state.imap_browse = true;
744 browser_sort(&priv->state);
745 priv->menu->mdata = &priv->state.entry;
746 priv->menu->mdata_free = NULL; // Menu doesn't own the data
747 }
748 else
749 {
750 if (examine_directory(priv->mailbox, priv->menu, &priv->state,
751 buf_string(&LastDir), buf_string(priv->prefix)) == -1)
752 {
753 /* try to restore the old values */
754 buf_copy(&LastDir, priv->OldLastDir);
755 if (examine_directory(priv->mailbox, priv->menu, &priv->state,
756 buf_string(&LastDir), buf_string(priv->prefix)) == -1)
757 {
759 priv->done = true;
760 return FR_DONE;
761 }
762 }
763 /* resolve paths navigated from GUI */
764 if (mutt_path_realpath(&LastDir) == 0)
765 return FR_ERROR;
766 }
767
768 browser_highlight_default(&priv->state, priv->menu);
769 init_menu(&priv->state, priv->menu, priv->mailbox, priv->sbar);
770 priv->goto_swapper[0] = '\0';
771 return FR_SUCCESS;
772 }
773 }
774 else if (op == OP_DESCEND_DIRECTORY)
775 {
776 mutt_error(_("%s is not a directory"), ARRAY_GET(&priv->state.entry, index)->name);
777 return FR_ERROR;
778 }
779
780 if (priv->state.is_mailbox_list || OptNews)
781 {
782 buf_strcpy(priv->file, ff->name);
783 buf_expand_path(priv->file);
784 }
785 else if (priv->state.imap_browse)
786 {
787 buf_strcpy(priv->file, ff->name);
788 }
789 else
790 {
792 }
793
794 return op_exit(priv, op);
795}
796
800static int op_load_active(struct BrowserPrivateData *priv, int op)
801{
802 if (!OptNews)
803 return FR_NOT_IMPL;
804
806
807 if (nntp_newsrc_parse(adata) < 0)
808 return FR_ERROR;
809
810 for (size_t i = 0; i < adata->groups_num; i++)
811 {
812 struct NntpMboxData *mdata = adata->groups_list[i];
813 if (mdata)
814 mdata->deleted = true;
815 }
819
820 destroy_state(&priv->state);
821 if (priv->state.is_mailbox_list)
822 {
823 examine_mailboxes(priv->mailbox, priv->menu, &priv->state);
824 }
825 else
826 {
827 if (examine_directory(priv->mailbox, priv->menu, &priv->state, NULL, NULL) == -1)
828 return FR_ERROR;
829 }
830 init_menu(&priv->state, priv->menu, priv->mailbox, priv->sbar);
831 return FR_SUCCESS;
832}
833
837static int op_mailbox_list(struct BrowserPrivateData *priv, int op)
838{
840 return FR_SUCCESS;
841}
842
846static int op_rename_mailbox(struct BrowserPrivateData *priv, int op)
847{
848 int index = menu_get_index(priv->menu);
849 struct FolderFile *ff = ARRAY_GET(&priv->state.entry, index);
850 if (!ff->imap)
851 {
852 mutt_error(_("Rename is only supported for IMAP mailboxes"));
853 return FR_ERROR;
854 }
855
856 if (imap_mailbox_rename(ff->name) < 0)
857 return FR_ERROR;
858
859 destroy_state(&priv->state);
860 init_state(&priv->state, NULL);
861 priv->state.imap_browse = true;
863 browser_sort(&priv->state);
864 priv->menu->mdata = &priv->state.entry;
865 priv->menu->mdata_free = NULL; // Menu doesn't own the data
866 browser_highlight_default(&priv->state, priv->menu);
867 init_menu(&priv->state, priv->menu, priv->mailbox, priv->sbar);
868
869 return FR_SUCCESS;
870}
871
879static int op_sort(struct BrowserPrivateData *priv, int op)
880{
881 bool resort = true;
882 int sort = -1;
883 int reverse = (op == OP_SORT_REVERSE);
884
885 switch (mw_multi_choice((reverse) ?
886 /* L10N: The highlighted letters must match the "Sort" options */
887 _("Reverse sort by (d)ate, (a)lpha, si(z)e, d(e)scription, (c)ount, ne(w) count, or do(n)'t sort?") :
888 /* L10N: The highlighted letters must match the "Reverse Sort" options */
889 _("Sort by (d)ate, (a)lpha, si(z)e, d(e)scription, (c)ount, ne(w) count, or do(n)'t sort?"),
890 /* L10N: These must match the highlighted letters from "Sort" and "Reverse Sort" */
891 _("dazecwn")))
892 {
893 case -1: /* abort */
894 resort = false;
895 break;
896
897 case 1: /* (d)ate */
898 sort = SORT_DATE;
899 break;
900
901 case 2: /* (a)lpha */
902 sort = SORT_SUBJECT;
903 break;
904
905 case 3: /* si(z)e */
906 sort = SORT_SIZE;
907 break;
908
909 case 4: /* d(e)scription */
910 sort = SORT_DESC;
911 break;
912
913 case 5: /* (c)ount */
914 sort = SORT_COUNT;
915 break;
916
917 case 6: /* ne(w) count */
918 sort = SORT_UNREAD;
919 break;
920
921 case 7: /* do(n)'t sort */
922 sort = SORT_ORDER;
923 break;
924 }
925
926 if (!resort)
927 return FR_NO_ACTION;
928
929 sort |= reverse ? SORT_REVERSE : 0;
930 cs_subset_str_native_set(NeoMutt->sub, "sort_browser", sort, NULL);
931 browser_sort(&priv->state);
932 browser_highlight_default(&priv->state, priv->menu);
934 return FR_SUCCESS;
935}
936
944static int op_subscribe_pattern(struct BrowserPrivateData *priv, int op)
945{
946 if (!OptNews)
947 return FR_NOT_IMPL;
948
950 regex_t rx = { 0 };
951 int index = menu_get_index(priv->menu);
952
953 char tmp2[256] = { 0 };
954
955 struct Buffer *buf = buf_pool_get();
956 if (op == OP_SUBSCRIBE_PATTERN)
957 snprintf(tmp2, sizeof(tmp2), _("Subscribe pattern: "));
958 else
959 snprintf(tmp2, sizeof(tmp2), _("Unsubscribe pattern: "));
960 /* buf comes from the buffer pool, so defaults to size 1024 */
961 if ((mw_get_field(tmp2, buf, MUTT_COMP_NO_FLAGS, HC_PATTERN, &CompletePatternOps, NULL) != 0) ||
962 buf_is_empty(buf))
963 {
964 buf_pool_release(&buf);
965 return FR_NO_ACTION;
966 }
967
968 int err = REG_COMP(&rx, buf->data, REG_NOSUB);
969 if (err != 0)
970 {
971 regerror(err, &rx, buf->data, buf->dsize);
972 regfree(&rx);
973 mutt_error("%s", buf_string(buf));
974 buf_pool_release(&buf);
975 return FR_ERROR;
976 }
978 index = 0;
979 buf_pool_release(&buf);
980
981 int rc = nntp_newsrc_parse(adata);
982 if (rc < 0)
983 return FR_ERROR;
984
985 struct FolderFile *ff = NULL;
986 ARRAY_FOREACH_FROM(ff, &priv->state.entry, index)
987 {
988 if (regexec(&rx, ff->name, 0, NULL, 0) == 0)
989 {
990 if (op == OP_SUBSCRIBE_PATTERN)
991 mutt_newsgroup_subscribe(adata, ff->name);
992 else
994 }
995 }
996
997 if (op == OP_SUBSCRIBE_PATTERN)
998 {
999 for (size_t j = 0; j < adata->groups_num; j++)
1000 {
1001 struct NntpMboxData *mdata = adata->groups_list[j];
1002 if (mdata && mdata->group && !mdata->subscribed)
1003 {
1004 if (regexec(&rx, mdata->group, 0, NULL, 0) == 0)
1005 {
1007 browser_add_folder(priv->menu, &priv->state, mdata->group, NULL, NULL, NULL, mdata);
1008 }
1009 }
1010 }
1011 init_menu(&priv->state, priv->menu, priv->mailbox, priv->sbar);
1012 }
1013 if (rc > 0)
1018 regfree(&rx);
1019 return FR_SUCCESS;
1020}
1021
1029static int op_toggle_mailboxes(struct BrowserPrivateData *priv, int op)
1030{
1031 if (priv->state.is_mailbox_list)
1032 {
1034 }
1035
1036 if (op == OP_TOGGLE_MAILBOXES)
1037 {
1039 }
1040
1041 if (op == OP_BROWSER_GOTO_FOLDER)
1042 {
1043 /* When in mailboxes mode, disables this feature */
1044 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
1045 if (c_folder)
1046 {
1047 mutt_debug(LL_DEBUG3, "= hit! Folder: %s, LastDir: %s\n", c_folder,
1049 if (priv->goto_swapper[0] == '\0')
1050 {
1051 if (!mutt_str_equal(buf_string(&LastDir), c_folder))
1052 {
1053 /* Stores into goto_swapper LastDir, and swaps to `$folder` */
1054 mutt_str_copy(priv->goto_swapper, buf_string(&LastDir), sizeof(priv->goto_swapper));
1056 buf_strcpy(&LastDir, c_folder);
1057 }
1058 }
1059 else
1060 {
1063 priv->goto_swapper[0] = '\0';
1064 }
1065 }
1066 }
1067 destroy_state(&priv->state);
1068 buf_reset(priv->prefix);
1069 priv->kill_prefix = false;
1070
1071 if (priv->state.is_mailbox_list)
1072 {
1073 examine_mailboxes(priv->mailbox, priv->menu, &priv->state);
1074 }
1075 else if (imap_path_probe(buf_string(&LastDir), NULL) == MUTT_IMAP)
1076 {
1077 init_state(&priv->state, NULL);
1078 priv->state.imap_browse = true;
1080 browser_sort(&priv->state);
1081 priv->menu->mdata = &priv->state.entry;
1082 priv->menu->mdata_free = NULL; // Menu doesn't own the data
1083 }
1084 else if (examine_directory(priv->mailbox, priv->menu, &priv->state,
1085 buf_string(&LastDir), buf_string(priv->prefix)) == -1)
1086 {
1087 priv->done = true;
1088 return FR_ERROR;
1089 }
1090 init_menu(&priv->state, priv->menu, priv->mailbox, priv->sbar);
1091 if (priv->state.is_mailbox_list)
1093 return FR_ERROR;
1094}
1095
1096// -----------------------------------------------------------------------------
1097
1101static const struct BrowserFunction BrowserFunctions[] = {
1102 // clang-format off
1103 { OP_BROWSER_GOTO_FOLDER, op_toggle_mailboxes },
1104 { OP_BROWSER_NEW_FILE, op_browser_new_file },
1105 { OP_BROWSER_SUBSCRIBE, op_browser_subscribe },
1106 { OP_BROWSER_TELL, op_browser_tell },
1107 { OP_BROWSER_TOGGLE_LSUB, op_browser_toggle_lsub },
1108 { OP_BROWSER_UNSUBSCRIBE, op_browser_subscribe },
1109 { OP_BROWSER_VIEW_FILE, op_browser_view_file },
1110 { OP_CATCHUP, op_catchup },
1111 { OP_CHANGE_DIRECTORY, op_change_directory },
1112 { OP_CHECK_NEW, op_toggle_mailboxes },
1113 { OP_CREATE_MAILBOX, op_create_mailbox },
1114 { OP_DELETE_MAILBOX, op_delete_mailbox },
1115 { OP_DESCEND_DIRECTORY, op_generic_select_entry },
1116 { OP_ENTER_MASK, op_enter_mask },
1117 { OP_EXIT, op_exit },
1118 { OP_GENERIC_SELECT_ENTRY, op_generic_select_entry },
1119 { OP_GOTO_PARENT, op_change_directory },
1120 { OP_LOAD_ACTIVE, op_load_active },
1121 { OP_MAILBOX_LIST, op_mailbox_list },
1122 { OP_RENAME_MAILBOX, op_rename_mailbox },
1123 { OP_SORT, op_sort },
1124 { OP_SORT_REVERSE, op_sort },
1125 { OP_SUBSCRIBE_PATTERN, op_subscribe_pattern },
1126 { OP_TOGGLE_MAILBOXES, op_toggle_mailboxes },
1127 { OP_UNCATCHUP, op_catchup },
1128 { OP_UNSUBSCRIBE_PATTERN, op_subscribe_pattern },
1129 { 0, NULL },
1130 // clang-format on
1131};
1132
1140{
1141 if (!win)
1142 {
1144 return FR_ERROR;
1145 }
1146
1147 struct BrowserPrivateData *priv = win->parent->wdata;
1148 if (!priv)
1149 return FR_ERROR;
1150
1151 int rc = FR_UNKNOWN;
1152 for (size_t i = 0; BrowserFunctions[i].op != OP_NULL; i++)
1153 {
1154 const struct BrowserFunction *fn = &BrowserFunctions[i];
1155 if (fn->op == op)
1156 {
1157 rc = fn->function(priv, op);
1158 break;
1159 }
1160 }
1161
1162 return rc;
1163}
#define ARRAY_REMOVE(head, elem)
Remove an entry from the array, shifting down the subsequent entries.
Definition: array.h:267
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition: array.h:212
#define ARRAY_EMPTY(head)
Check if an array is empty.
Definition: array.h:74
#define ARRAY_FREE(head)
Release all memory.
Definition: array.h:204
#define ARRAY_FOREACH_FROM(elem, head, from)
Iterate from an index to the end.
Definition: array.h:223
#define ARRAY_GET(head, idx)
Return the element at index.
Definition: array.h:109
static const char * Not_available_in_this_menu
Error message for unavailable functions.
Definition: functions.c:55
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:224
const struct CompleteOps CompleteMailboxOps
Auto-Completion of Files / Mailboxes.
Definition: complete.c:160
int browser_function_dispatcher(struct MuttWindow *win, int op)
Perform a Browser function.
Definition: functions.c:1139
const struct MenuOpSeq BrowserDefaultBindings[]
Key bindings for the file Browser Menu.
Definition: functions.c:108
const struct MenuFuncOp OpBrowser[]
Functions for the file Browser Menu.
Definition: functions.c:74
void destroy_state(struct BrowserState *state)
Free the BrowserState.
Definition: functions.c:137
static const struct BrowserFunction BrowserFunctions[]
All the NeoMutt functions that the Browser supports.
Definition: functions.c:1101
void browser_sort(struct BrowserState *state)
Sort the entries in the browser.
Definition: sort.c:186
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:178
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:508
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:93
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:308
void buf_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:199
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:258
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:243
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:412
size_t buf_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition: buffer.c:618
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:588
size_t buf_concat_path(struct Buffer *buf, const char *dir, const char *fname)
Join a directory name and a filename.
Definition: buffer.c:526
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:97
const struct Regex * cs_subset_regex(const struct ConfigSubset *sub, const char *name)
Get a regex config item by name.
Definition: helpers.c:218
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:292
Convenience wrapper for the config headers.
char * HomeDir
User's home directory.
Definition: globals.c:38
#define CSR_RESULT(x)
Definition: set.h:52
#define CSR_SUCCESS
Action completed successfully.
Definition: set.h:35
Convenience wrapper for the core headers.
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:223
MailboxType
Supported mailbox formats.
Definition: mailbox.h:41
@ MUTT_MAILBOX_ERROR
Error occurred examining Mailbox.
Definition: mailbox.h:43
@ MUTT_IMAP
'IMAP' Mailbox type
Definition: mailbox.h:50
@ MUTT_UNKNOWN
Mailbox wasn't recognised.
Definition: mailbox.h:44
void mutt_unget_op(int op)
Return an operation to the input buffer.
Definition: get.c:125
@ FR_SUCCESS
Valid function - successfully performed.
Definition: dispatcher.h:39
@ FR_DONE
Exit the Dialog.
Definition: dispatcher.h:35
@ FR_UNKNOWN
Unknown function.
Definition: dispatcher.h:33
@ FR_ERROR
Valid function - error occurred.
Definition: dispatcher.h:38
@ FR_NOT_IMPL
Invalid function - feature not enabled.
Definition: dispatcher.h:36
@ FR_NO_ACTION
Valid function - no action performed.
Definition: dispatcher.h:37
void init_state(struct BrowserState *state, struct Menu *menu)
Initialise a browser state.
Definition: dlg_browser.c:689
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.
Definition: dlg_browser.c:712
void init_menu(struct BrowserState *state, struct Menu *menu, struct Mailbox *m, struct MuttWindow *sbar)
Set up a new menu.
Definition: dlg_browser.c:1029
struct Buffer LastDir
Browser: previous selected directory.
Definition: dlg_browser.c:140
struct Buffer LastDirBackup
Browser: backup copy of the current directory.
Definition: dlg_browser.c:142
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.
Definition: dlg_browser.c:638
void browser_highlight_default(struct BrowserState *state, struct Menu *menu)
Decide which browser item should be highlighted.
Definition: dlg_browser.c:1003
int examine_mailboxes(struct Mailbox *m, struct Menu *menu, struct BrowserState *state)
Get list of mailboxes/subscribed newsgroups.
Definition: dlg_browser.c:839
bool link_is_dir(const char *folder, const char *path)
Does this symlink point to a directory?
Definition: dlg_browser.c:176
Edit a string.
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:58
Structs that make up an email.
bool OptNews
(pseudo) used to change reader mode
Definition: globals.c:70
static int op_generic_select_entry(struct AliasMenuData *mdata, int op)
select the current entry - Implements alias_function_t -
Definition: functions.c:205
static int op_exit(struct AliasMenuData *mdata, int op)
exit this menu - Implements alias_function_t -
Definition: functions.c:191
static int op_sort(struct AliasMenuData *mdata, int op)
sort aliases - Implements alias_function_t -
Definition: functions.c:347
static int op_browser_view_file(struct BrowserPrivateData *priv, int op)
View file - Implements browser_function_t -.
Definition: functions.c:257
static int op_browser_new_file(struct BrowserPrivateData *priv, int op)
Select a new file in this directory - Implements browser_function_t -.
Definition: functions.c:154
static int op_enter_mask(struct BrowserPrivateData *priv, int op)
Enter a file mask - Implements browser_function_t -.
Definition: functions.c:529
static int op_subscribe_pattern(struct BrowserPrivateData *priv, int op)
Subscribe to newsgroups matching a pattern - Implements browser_function_t -.
Definition: functions.c:944
static int op_catchup(struct BrowserPrivateData *priv, int op)
Mark all articles in newsgroup as read - Implements browser_function_t -.
Definition: functions.c:302
static int op_rename_mailbox(struct BrowserPrivateData *priv, int op)
Rename the current mailbox (IMAP only) - Implements browser_function_t -.
Definition: functions.c:846
static int op_browser_subscribe(struct BrowserPrivateData *priv, int op)
Subscribe to current mbox (IMAP/NNTP only) - Implements browser_function_t -.
Definition: functions.c:181
static int op_browser_toggle_lsub(struct BrowserPrivateData *priv, int op)
Toggle view all/subscribed mailboxes (IMAP only) - Implements browser_function_t -.
Definition: functions.c:246
static int op_create_mailbox(struct BrowserPrivateData *priv, int op)
Create a new mailbox (IMAP only) - Implements browser_function_t -.
Definition: functions.c:452
static int op_delete_mailbox(struct BrowserPrivateData *priv, int op)
Delete the current mailbox (IMAP only) - Implements browser_function_t -.
Definition: functions.c:481
static int op_load_active(struct BrowserPrivateData *priv, int op)
Load list of all newsgroups from NNTP server - Implements browser_function_t -.
Definition: functions.c:800
static int op_toggle_mailboxes(struct BrowserPrivateData *priv, int op)
Toggle whether to browse mailboxes or all files - Implements browser_function_t -.
Definition: functions.c:1029
static int op_browser_tell(struct BrowserPrivateData *priv, int op)
Display the currently selected file's name - Implements browser_function_t -.
Definition: functions.c:233
static int op_mailbox_list(struct BrowserPrivateData *priv, int op)
List mailboxes with new mail - Implements browser_function_t -.
Definition: functions.c:837
static int op_change_directory(struct BrowserPrivateData *priv, int op)
Change directories - Implements browser_function_t -.
Definition: functions.c:342
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:274
int mw_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question -.
Definition: question.c:64
#define mutt_error(...)
Definition: logging2.h:92
#define mutt_message(...)
Definition: logging2.h:91
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
#define mutt_perror(...)
Definition: logging2.h:93
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe() -.
Definition: imap.c:2342
Convenience wrapper for the gui headers.
Read/write command history from/to a file.
@ HC_FILE
Files.
Definition: lib.h:54
@ HC_PATTERN
Patterns.
Definition: lib.h:55
@ HC_OTHER
Miscellaneous strings.
Definition: lib.h:56
int imap_browse(const char *path, struct BrowserState *state)
IMAP hook into the folder browser.
Definition: browse.c:197
int imap_mailbox_create(const char *path)
Create a new IMAP mailbox.
Definition: browse.c:397
int imap_mailbox_rename(const char *path)
Rename a mailbox.
Definition: browse.c:452
IMAP network mailbox.
int imap_subscribe(char *path, bool subscribe)
Subscribe to a mailbox.
Definition: imap.c:1222
int imap_delete_mailbox(struct Mailbox *m, char *path)
Delete a mailbox.
Definition: imap.c:506
Manage keymappings.
@ LL_DEBUG3
Log at debug level 3.
Definition: logging2.h:45
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
#define FREE(x)
Definition: memory.h:45
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:185
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition: menu.c:161
MenuRedrawFlags menu_set_index(struct Menu *menu, int index)
Set the current selection in the Menu.
Definition: menu.c:175
Convenience wrapper for the library headers.
#define N_(a)
Definition: message.h:32
#define _(a)
Definition: message.h:28
size_t mutt_path_realpath(struct Buffer *path)
Resolve path, unraveling symlinks.
Definition: path.c:373
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:709
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:630
Many unsorted constants and some structs.
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:56
int mutt_view_attachment(FILE *fp, struct Body *b, enum ViewAttachMode mode, struct Email *e, struct AttachCtx *actx, struct MuttWindow *win)
View an attachment.
Definition: mutt_attach.c:418
@ 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.
Definition: mutt_mailbox.c:247
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:971
char * mutt_expand_path(char *buf, size_t buflen)
Create the canonical path.
Definition: muttlib.c:123
void buf_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:328
Some miscellaneous functions.
enum MailboxType mx_path_probe(const char *path)
Find a mailbox that understands a path.
Definition: mx.c:1319
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:852
int nntp_active_fetch(struct NntpAccountData *adata, bool mark_new)
Fetch list of all newsgroups from server.
Definition: nntp.c:1989
int nntp_newsrc_parse(struct NntpAccountData *adata)
Parse .newsrc file.
Definition: newsrc.c:165
void nntp_newsrc_close(struct NntpAccountData *adata)
Unlock and close .newsrc file.
Definition: newsrc.c:121
struct NntpMboxData * mutt_newsgroup_catchup(struct Mailbox *m, struct NntpAccountData *adata, char *group)
Catchup newsgroup.
Definition: newsrc.c:1350
int nntp_newsrc_update(struct NntpAccountData *adata)
Update .newsrc file.
Definition: newsrc.c:444
struct NntpMboxData * mutt_newsgroup_subscribe(struct NntpAccountData *adata, char *group)
Subscribe newsgroup.
Definition: newsrc.c:1299
struct NntpMboxData * mutt_newsgroup_uncatchup(struct Mailbox *m, struct NntpAccountData *adata, char *group)
Uncatchup newsgroup.
Definition: newsrc.c:1389
struct NntpAccountData * CurrentNewsSrv
Current NNTP news server.
Definition: nntp.c:77
struct NntpMboxData * mutt_newsgroup_unsubscribe(struct NntpAccountData *adata, char *group)
Unsubscribe newsgroup.
Definition: newsrc.c:1323
Nntp-specific Mailbox data.
Private state data for the Pager.
const struct CompleteOps CompletePatternOps
Auto-Completion of Patterns.
Definition: complete.c:82
Match patterns to emails.
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
@ 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:327
#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
Sidebar functions.
@ SORT_SUBJECT
Sort by the email's subject.
Definition: sort2.h:38
@ SORT_ORDER
Sort by the order the messages appear in the mailbox.
Definition: sort2.h:40
@ SORT_SIZE
Sort by the size of the email.
Definition: sort2.h:36
@ SORT_DESC
Sort by the folder's description.
Definition: sort2.h:55
@ SORT_DATE
Sort by the date the email was sent.
Definition: sort2.h:35
@ SORT_COUNT
Sort by number of emails in a folder.
Definition: sort2.h:50
@ SORT_UNREAD
Sort by the number of unread emails.
Definition: sort2.h:51
#define SORT_REVERSE
Reverse the order of the sort.
Definition: sort2.h:71
Key value store.
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:44
int op
Op code, e.g. OP_MAIN_LIMIT.
Definition: functions.h:45
browser_function_t function
Function to call.
Definition: functions.h:46
Private state data for the Browser.
Definition: private_data.h:34
char *** files
Array of selected files.
Definition: private_data.h:38
struct Menu * menu
Menu.
Definition: private_data.h:43
struct Buffer * prefix
Folder prefix string.
Definition: private_data.h:49
bool kill_prefix
Prefix is in use.
Definition: private_data.h:44
bool done
Should we close the Dialog?
Definition: private_data.h:53
struct Buffer * OldLastDir
Previous to last dir.
Definition: private_data.h:48
int last_selected_mailbox
Index of last selected Mailbox.
Definition: private_data.h:50
int * numfiles
Number of selected files.
Definition: private_data.h:39
struct Mailbox * mailbox
Mailbox.
Definition: private_data.h:37
struct BrowserState state
State containing list of files/dir/mailboxes.
Definition: private_data.h:42
struct Buffer * file
Buffer for the result.
Definition: private_data.h:36
bool multiple
Allow multiple selections.
Definition: private_data.h:45
struct MuttWindow * sbar
Status Bar.
Definition: private_data.h:51
char goto_swapper[PATH_MAX]
Saved path after <goto-folder>
Definition: private_data.h:47
State of the file/mailbox browser.
Definition: lib.h:144
char * folder
Folder name.
Definition: lib.h:147
bool is_mailbox_list
Viewing mailboxes.
Definition: lib.h:148
struct BrowserEntryArray entry
Array of files / dirs / mailboxes.
Definition: lib.h:145
bool imap_browse
IMAP folder.
Definition: lib.h:146
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:40
Browser entry representing a folder/dir.
Definition: lib.h:78
bool selectable
Folder can be selected.
Definition: lib.h:96
char delim
Path delimiter.
Definition: lib.h:93
bool imap
This is an IMAP folder.
Definition: lib.h:95
char * name
Name of file/dir/mailbox.
Definition: lib.h:86
bool tagged
Folder is tagged.
Definition: lib.h:102
char * desc
Description of mailbox.
Definition: lib.h:87
mode_t mode
File permissions.
Definition: lib.h:79
bool inferiors
Folder has children.
Definition: lib.h:97
void * mdata
Driver specific data.
Definition: mailbox.h:132
Mapping between a function and an operation.
Definition: lib.h:101
Mapping between an operation and a key sequence.
Definition: lib.h:110
struct MuttWindow * win
Window holding the Menu.
Definition: lib.h:86
int num_tagged
Number of tagged entries.
Definition: lib.h:93
void(* mdata_free)(struct Menu *menu, void **ptr)
Definition: lib.h:161
void * mdata
Private data.
Definition: lib.h:147
void * wdata
Private data.
Definition: mutt_window.h:145
struct MuttWindow * parent
Parent Window.
Definition: mutt_window.h:135
Container for Accounts, Notifications.
Definition: neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
NNTP-specific Account data -.
Definition: adata.h:36
unsigned int groups_num
Definition: adata.h:58
void ** groups_list
Definition: adata.h:60
NNTP-specific Mailbox data -.
Definition: mdata.h:34
struct NntpAccountData * adata
Definition: mdata.h:48
Cached regular expression.
Definition: regex3.h:85
char * pattern
printable version
Definition: regex3.h:86
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:297
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:386
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