NeoMutt  2023-03-22
Teaching an old dog new tricks
DOXYGEN
browser.c
Go to the documentation of this file.
1
69#include "config.h"
70#include <dirent.h>
71#include <errno.h>
72#include <grp.h>
73#include <limits.h>
74#include <locale.h>
75#include <pwd.h>
76#include <stdbool.h>
77#include <stdint.h>
78#include <stdio.h>
79#include <string.h>
80#include <sys/stat.h>
81#include <time.h>
82#include "mutt/lib.h"
83#include "config/lib.h"
84#include "core/lib.h"
85#include "conn/lib.h"
86#include "gui/lib.h"
87#include "lib.h"
88#include "menu/lib.h"
89#include "format_flags.h"
90#include "functions.h"
91#include "globals.h"
92#include "keymap.h"
93#include "mutt_logging.h"
94#include "mutt_mailbox.h"
95#include "muttlib.h"
96#include "mx.h"
97#include "opcodes.h"
98#include "private_data.h"
99#ifdef USE_IMAP
100#include "imap/lib.h"
101#endif
102#ifdef USE_NNTP
103#include "nntp/lib.h"
104#include "nntp/adata.h"
105#include "nntp/mdata.h"
106#endif
107
109static const struct Mapping FolderHelp[] = {
110 // clang-format off
111 { N_("Exit"), OP_EXIT },
112 { N_("Chdir"), OP_CHANGE_DIRECTORY },
113 { N_("Goto"), OP_BROWSER_GOTO_FOLDER },
114 { N_("Mask"), OP_ENTER_MASK },
115 { N_("Help"), OP_HELP },
116 { NULL, 0 },
117 // clang-format on
118};
119
120#ifdef USE_NNTP
122static const struct Mapping FolderNewsHelp[] = {
123 // clang-format off
124 { N_("Exit"), OP_EXIT },
125 { N_("List"), OP_TOGGLE_MAILBOXES },
126 { N_("Subscribe"), OP_BROWSER_SUBSCRIBE },
127 { N_("Unsubscribe"), OP_BROWSER_UNSUBSCRIBE },
128 { N_("Catchup"), OP_CATCHUP },
129 { N_("Mask"), OP_ENTER_MASK },
130 { N_("Help"), OP_HELP },
131 { NULL, 0 },
132 // clang-format on
133};
134#endif
135
136struct Buffer LastDir = { 0 };
137struct Buffer LastDirBackup = { 0 };
138
144static void init_lastdir(void)
145{
146 static bool done = false;
147 if (!done)
148 {
151 done = true;
152 }
153}
154
159{
162}
163
171bool link_is_dir(const char *folder, const char *path)
172{
173 struct stat st = { 0 };
174 bool retval = false;
175
176 struct Buffer *fullpath = mutt_buffer_pool_get();
177 mutt_buffer_concat_path(fullpath, folder, path);
178
179 if (stat(mutt_buffer_string(fullpath), &st) == 0)
180 retval = S_ISDIR(st.st_mode);
181
182 mutt_buffer_pool_release(&fullpath);
183
184 return retval;
185}
186
208static const char *folder_format_str(char *buf, size_t buflen, size_t col, int cols,
209 char op, const char *src, const char *prec,
210 const char *if_str, const char *else_str,
211 intptr_t data, MuttFormatFlags flags)
212{
213 char fn[128] = { 0 };
214 char fmt[128] = { 0 };
215 struct Folder *folder = (struct Folder *) data;
216 bool optional = (flags & MUTT_FORMAT_OPTIONAL);
217
218 switch (op)
219 {
220 case 'C':
221 snprintf(fmt, sizeof(fmt), "%%%sd", prec);
222 snprintf(buf, buflen, fmt, folder->num + 1);
223 break;
224
225 case 'd':
226 case 'D':
227 if (folder->ff->local)
228 {
229 bool do_locales = true;
230
231 const char *t_fmt = NULL;
232 if (op == 'D')
233 {
234 const char *const c_date_format = cs_subset_string(NeoMutt->sub, "date_format");
235 t_fmt = NONULL(c_date_format);
236 if (*t_fmt == '!')
237 {
238 t_fmt++;
239 do_locales = false;
240 }
241 }
242 else
243 {
244 static const time_t one_year = 31536000;
245 t_fmt = ((mutt_date_now() - folder->ff->mtime) < one_year) ? "%b %d %H:%M" : "%b %d %Y";
246 }
247
248 if (!do_locales)
249 setlocale(LC_TIME, "C");
250 char date[128] = { 0 };
251 mutt_date_localtime_format(date, sizeof(date), t_fmt, folder->ff->mtime);
252 if (!do_locales)
253 setlocale(LC_TIME, "");
254
255 mutt_format_s(buf, buflen, prec, date);
256 }
257 else
258 {
259 mutt_format_s(buf, buflen, prec, "");
260 }
261 break;
262
263 case '[':
264 if (folder->ff->local)
265 {
266 char buf2[128] = { 0 };
267 bool do_locales = true;
268 struct tm tm = { 0 };
269
270 char *p = buf;
271
272 const char *cp = src;
273 if (*cp == '!')
274 {
275 do_locales = false;
276 cp++;
277 }
278
279 size_t len = buflen - 1;
280 while ((len > 0) && (*cp != ']'))
281 {
282 if (*cp == '%')
283 {
284 cp++;
285 if (len >= 2)
286 {
287 *p++ = '%';
288 *p++ = *cp;
289 len -= 2;
290 }
291 else
292 {
293 break; /* not enough space */
294 }
295 cp++;
296 }
297 else
298 {
299 *p++ = *cp++;
300 len--;
301 }
302 }
303 *p = '\0';
304
305 tm = mutt_date_localtime(folder->ff->mtime);
306
307 if (!do_locales)
308 setlocale(LC_TIME, "C");
309 strftime(buf2, sizeof(buf2), buf, &tm);
310 if (!do_locales)
311 setlocale(LC_TIME, "");
312
313 snprintf(fmt, sizeof(fmt), "%%%ss", prec);
314 snprintf(buf, buflen, fmt, buf2);
315 if (len > 0)
316 src = cp + 1;
317 }
318 else
319 {
320 mutt_format_s(buf, buflen, prec, "");
321 }
322 break;
323
324 case 'f':
325 {
326 char *s = NULL;
327
328 s = NONULL(folder->ff->name);
329
330 snprintf(fn, sizeof(fn), "%s%s", s,
331 folder->ff->local ?
332 (S_ISLNK(folder->ff->mode) ?
333 "@" :
334 (S_ISDIR(folder->ff->mode) ?
335 "/" :
336 (((folder->ff->mode & S_IXUSR) != 0) ? "*" : ""))) :
337 "");
338
339 mutt_format_s(buf, buflen, prec, fn);
340 break;
341 }
342 case 'F':
343 {
344 if (folder->ff->local)
345 {
346 char permission[11] = { 0 };
347 snprintf(permission, sizeof(permission), "%c%c%c%c%c%c%c%c%c%c",
348 S_ISDIR(folder->ff->mode) ? 'd' : (S_ISLNK(folder->ff->mode) ? 'l' : '-'),
349 ((folder->ff->mode & S_IRUSR) != 0) ? 'r' : '-',
350 ((folder->ff->mode & S_IWUSR) != 0) ? 'w' : '-',
351 ((folder->ff->mode & S_ISUID) != 0) ? 's' :
352 ((folder->ff->mode & S_IXUSR) != 0) ? 'x' :
353 '-',
354 ((folder->ff->mode & S_IRGRP) != 0) ? 'r' : '-',
355 ((folder->ff->mode & S_IWGRP) != 0) ? 'w' : '-',
356 ((folder->ff->mode & S_ISGID) != 0) ? 's' :
357 ((folder->ff->mode & S_IXGRP) != 0) ? 'x' :
358 '-',
359 ((folder->ff->mode & S_IROTH) != 0) ? 'r' : '-',
360 ((folder->ff->mode & S_IWOTH) != 0) ? 'w' : '-',
361 ((folder->ff->mode & S_ISVTX) != 0) ? 't' :
362 ((folder->ff->mode & S_IXOTH) != 0) ? 'x' :
363 '-');
364 mutt_format_s(buf, buflen, prec, permission);
365 }
366#ifdef USE_IMAP
367 else if (folder->ff->imap)
368 {
369 char permission[11] = { 0 };
370 /* mark folders with subfolders AND mail */
371 snprintf(permission, sizeof(permission), "IMAP %c",
372 (folder->ff->inferiors && folder->ff->selectable) ? '+' : ' ');
373 mutt_format_s(buf, buflen, prec, permission);
374 }
375#endif
376 else
377 mutt_format_s(buf, buflen, prec, "");
378 break;
379 }
380
381 case 'g':
382 if (folder->ff->local)
383 {
384 struct group *gr = getgrgid(folder->ff->gid);
385 if (gr)
386 {
387 mutt_format_s(buf, buflen, prec, gr->gr_name);
388 }
389 else
390 {
391 snprintf(fmt, sizeof(fmt), "%%%sld", prec);
392 snprintf(buf, buflen, fmt, folder->ff->gid);
393 }
394 }
395 else
396 {
397 mutt_format_s(buf, buflen, prec, "");
398 }
399 break;
400
401 case 'i':
402 {
403 char *s = NULL;
404 if (folder->ff->desc)
405 s = folder->ff->desc;
406 else
407 s = folder->ff->name;
408
409 snprintf(fn, sizeof(fn), "%s%s", s,
410 folder->ff->local ?
411 (S_ISLNK(folder->ff->mode) ?
412 "@" :
413 (S_ISDIR(folder->ff->mode) ?
414 "/" :
415 (((folder->ff->mode & S_IXUSR) != 0) ? "*" : ""))) :
416 "");
417
418 mutt_format_s(buf, buflen, prec, fn);
419 break;
420 }
421
422 case 'l':
423 if (folder->ff->local)
424 {
425 snprintf(fmt, sizeof(fmt), "%%%sd", prec);
426 snprintf(buf, buflen, fmt, folder->ff->nlink);
427 }
428 else
429 {
430 mutt_format_s(buf, buflen, prec, "");
431 }
432 break;
433
434 case 'm':
435 if (!optional)
436 {
437 if (folder->ff->has_mailbox)
438 {
439 snprintf(fmt, sizeof(fmt), "%%%sd", prec);
440 snprintf(buf, buflen, fmt, folder->ff->msg_count);
441 }
442 else
443 {
444 mutt_format_s(buf, buflen, prec, "");
445 }
446 }
447 else if (folder->ff->msg_count == 0)
448 optional = false;
449 break;
450
451 case 'N':
452 snprintf(fmt, sizeof(fmt), "%%%sc", prec);
453 snprintf(buf, buflen, fmt, folder->ff->has_new_mail ? 'N' : ' ');
454 break;
455
456 case 'n':
457 if (!optional)
458 {
459 if (folder->ff->has_mailbox)
460 {
461 snprintf(fmt, sizeof(fmt), "%%%sd", prec);
462 snprintf(buf, buflen, fmt, folder->ff->msg_unread);
463 }
464 else
465 {
466 mutt_format_s(buf, buflen, prec, "");
467 }
468 }
469 else if (folder->ff->msg_unread == 0)
470 optional = false;
471 break;
472
473 case 's':
474 if (folder->ff->local)
475 {
476 mutt_str_pretty_size(fn, sizeof(fn), folder->ff->size);
477 snprintf(fmt, sizeof(fmt), "%%%ss", prec);
478 snprintf(buf, buflen, fmt, fn);
479 }
480 else
481 {
482 mutt_format_s(buf, buflen, prec, "");
483 }
484 break;
485
486 case 't':
487 snprintf(fmt, sizeof(fmt), "%%%sc", prec);
488 snprintf(buf, buflen, fmt, folder->ff->tagged ? '*' : ' ');
489 break;
490
491 case 'u':
492 if (folder->ff->local)
493 {
494 struct passwd *pw = getpwuid(folder->ff->uid);
495 if (pw)
496 {
497 mutt_format_s(buf, buflen, prec, pw->pw_name);
498 }
499 else
500 {
501 snprintf(fmt, sizeof(fmt), "%%%sld", prec);
502 snprintf(buf, buflen, fmt, folder->ff->uid);
503 }
504 }
505 else
506 {
507 mutt_format_s(buf, buflen, prec, "");
508 }
509 break;
510
511 default:
512 snprintf(fmt, sizeof(fmt), "%%%sc", prec);
513 snprintf(buf, buflen, fmt, op);
514 break;
515 }
516
517 if (optional)
518 {
519 mutt_expando_format(buf, buflen, col, cols, if_str, folder_format_str, data,
521 }
522 else if (flags & MUTT_FORMAT_OPTIONAL)
523 {
524 mutt_expando_format(buf, buflen, col, cols, else_str, folder_format_str,
526 }
527
528 /* We return the format string, unchanged */
529 return src;
530}
531
542void browser_add_folder(const struct Menu *menu, struct BrowserState *state,
543 const char *name, const char *desc,
544 const struct stat *st, struct Mailbox *m, void *data)
545{
546 if ((!menu || state->is_mailbox_list) && m && !m->visible)
547 {
548 return;
549 }
550
551 struct FolderFile ff = { 0 };
552
553 if (st)
554 {
555 ff.mode = st->st_mode;
556 ff.mtime = st->st_mtime;
557 ff.size = st->st_size;
558 ff.gid = st->st_gid;
559 ff.uid = st->st_uid;
560 ff.nlink = st->st_nlink;
561 ff.local = true;
562 }
563 else
564 {
565 ff.local = false;
566 }
567
568 if (m)
569 {
570 ff.has_mailbox = true;
571 ff.gen = m->gen;
572 ff.has_new_mail = m->has_new;
573 ff.msg_count = m->msg_count;
574 ff.msg_unread = m->msg_unread;
575 }
576
577 ff.name = mutt_str_dup(name);
578 ff.desc = mutt_str_dup(desc ? desc : name);
579#ifdef USE_IMAP
580 ff.imap = false;
581#endif
582#ifdef USE_NNTP
583 if (OptNews)
584 ff.nd = data;
585#endif
586
587 ARRAY_ADD(&state->entry, ff);
588}
589
595void init_state(struct BrowserState *state, struct Menu *menu)
596{
597 ARRAY_INIT(&state->entry);
598 ARRAY_RESERVE(&state->entry, 256);
599#ifdef USE_IMAP
600 state->imap_browse = false;
601#endif
602 if (menu)
603 {
604 menu->mdata = &state->entry;
605 menu->mdata_free = NULL; // Menu doesn't own the data
606 }
607}
608
619int examine_directory(struct Mailbox *m, struct Menu *menu, struct BrowserState *state,
620 const char *dirname, const char *prefix)
621{
622 int rc = -1;
623 struct Buffer *buf = mutt_buffer_pool_get();
624#ifdef USE_NNTP
625 if (OptNews)
626 {
628
629 init_state(state, menu);
630
631 for (unsigned int i = 0; i < adata->groups_num; i++)
632 {
633 struct NntpMboxData *mdata = adata->groups_list[i];
634 if (!mdata)
635 continue;
636 if (prefix && *prefix && !mutt_str_startswith(mdata->group, prefix))
637 continue;
638 const struct Regex *c_mask = cs_subset_regex(NeoMutt->sub, "mask");
639 if (!mutt_regex_match(c_mask, mdata->group))
640 {
641 continue;
642 }
643 browser_add_folder(menu, state, mdata->group, NULL, NULL, NULL, mdata);
644 }
645 }
646 else
647#endif /* USE_NNTP */
648 {
649 struct stat st = { 0 };
650 DIR *dir = NULL;
651 struct dirent *de = NULL;
652
653 while (stat(dirname, &st) == -1)
654 {
655 if (errno == ENOENT)
656 {
657 /* The last used directory is deleted, try to use the parent dir. */
658 char *c = strrchr(dirname, '/');
659
660 if (c && (c > dirname))
661 {
662 *c = '\0';
663 continue;
664 }
665 }
666 mutt_perror(dirname);
667 goto ed_out;
668 }
669
670 if (!S_ISDIR(st.st_mode))
671 {
672 mutt_error(_("%s is not a directory"), dirname);
673 goto ed_out;
674 }
675
676 if (m)
678
679 dir = mutt_file_opendir(dirname, MUTT_OPENDIR_NONE);
680 if (!dir)
681 {
682 mutt_perror(dirname);
683 goto ed_out;
684 }
685
686 init_state(state, menu);
687
688 struct MailboxList ml = STAILQ_HEAD_INITIALIZER(ml);
690 while ((de = readdir(dir)))
691 {
692 if (mutt_str_equal(de->d_name, "."))
693 continue; /* we don't need . */
694
695 if (prefix && *prefix && !mutt_str_startswith(de->d_name, prefix))
696 {
697 continue;
698 }
699 const struct Regex *c_mask = cs_subset_regex(NeoMutt->sub, "mask");
700 if (!mutt_regex_match(c_mask, de->d_name))
701 {
702 continue;
703 }
704
705 mutt_buffer_concat_path(buf, dirname, de->d_name);
706 if (lstat(mutt_buffer_string(buf), &st) == -1)
707 continue;
708
709 /* No size for directories or symlinks */
710 if (S_ISDIR(st.st_mode) || S_ISLNK(st.st_mode))
711 st.st_size = 0;
712 else if (!S_ISREG(st.st_mode))
713 continue;
714
715 struct MailboxNode *np = NULL;
716 STAILQ_FOREACH(np, &ml, entries)
717 {
719 break;
720 }
721
722 if (np && m && mutt_str_equal(np->mailbox->realpath, m->realpath))
723 {
724 np->mailbox->msg_count = m->msg_count;
725 np->mailbox->msg_unread = m->msg_unread;
726 }
727 browser_add_folder(menu, state, de->d_name, NULL, &st, np ? np->mailbox : NULL, NULL);
728 }
730 closedir(dir);
731 }
732 browser_sort(state);
733 rc = 0;
734ed_out:
736 return rc;
737}
738
747int examine_mailboxes(struct Mailbox *m, struct Menu *menu, struct BrowserState *state)
748{
749 struct stat st = { 0 };
750 struct Buffer *md = NULL;
751 struct Buffer *mailbox = NULL;
752
753#ifdef USE_NNTP
754 if (OptNews)
755 {
757
758 init_state(state, menu);
759
760 for (unsigned int i = 0; i < adata->groups_num; i++)
761 {
762 const bool c_show_only_unread = cs_subset_bool(NeoMutt->sub, "show_only_unread");
763 struct NntpMboxData *mdata = adata->groups_list[i];
764 if (mdata && (mdata->has_new_mail ||
765 (mdata->subscribed && (mdata->unread || !c_show_only_unread))))
766 {
767 browser_add_folder(menu, state, mdata->group, NULL, NULL, NULL, mdata);
768 }
769 }
770 }
771 else
772#endif
773 {
774 init_state(state, menu);
775
777 return -1;
778 mailbox = mutt_buffer_pool_get();
780
782
783 struct MailboxList ml = STAILQ_HEAD_INITIALIZER(ml);
785 struct MailboxNode *np = NULL;
786 STAILQ_FOREACH(np, &ml, entries)
787 {
788 if (!np->mailbox)
789 continue;
790
791 if (m && mutt_str_equal(np->mailbox->realpath, m->realpath))
792 {
793 np->mailbox->msg_count = m->msg_count;
794 np->mailbox->msg_unread = m->msg_unread;
795 }
796
798 const bool c_browser_abbreviate_mailboxes = cs_subset_bool(NeoMutt->sub, "browser_abbreviate_mailboxes");
799 if (c_browser_abbreviate_mailboxes)
801
802 switch (np->mailbox->type)
803 {
804 case MUTT_IMAP:
805 case MUTT_POP:
807 np->mailbox->name, NULL, np->mailbox, NULL);
808 continue;
809 case MUTT_NOTMUCH:
810 case MUTT_NNTP:
811 browser_add_folder(menu, state, mailbox_path(np->mailbox),
812 np->mailbox->name, NULL, np->mailbox, NULL);
813 continue;
814 default: /* Continue */
815 break;
816 }
817
818 if (lstat(mailbox_path(np->mailbox), &st) == -1)
819 continue;
820
821 if ((!S_ISREG(st.st_mode)) && (!S_ISDIR(st.st_mode)) && (!S_ISLNK(st.st_mode)))
822 continue;
823
824 if (np->mailbox->type == MUTT_MAILDIR)
825 {
826 struct stat st2 = { 0 };
827
828 mutt_buffer_printf(md, "%s/new", mailbox_path(np->mailbox));
829 if (stat(mutt_buffer_string(md), &st) < 0)
830 st.st_mtime = 0;
831 mutt_buffer_printf(md, "%s/cur", mailbox_path(np->mailbox));
832 if (stat(mutt_buffer_string(md), &st2) < 0)
833 st2.st_mtime = 0;
834 if (st2.st_mtime > st.st_mtime)
835 st.st_mtime = st2.st_mtime;
836 }
837
838 browser_add_folder(menu, state, mutt_buffer_string(mailbox),
839 np->mailbox->name, &st, np->mailbox, NULL);
840 }
842 }
843 browser_sort(state);
844
845 mutt_buffer_pool_release(&mailbox);
847 return 0;
848}
849
853static int select_file_search(struct Menu *menu, regex_t *rx, int line)
854{
855 struct BrowserStateEntry *entry = menu->mdata;
856#ifdef USE_NNTP
857 if (OptNews)
858 return regexec(rx, ARRAY_GET(entry, line)->desc, 0, NULL, 0);
859#endif
860 struct FolderFile *ff = ARRAY_GET(entry, line);
861 char *search_on = ff->desc ? ff->desc : ff->name;
862
863 return regexec(rx, search_on, 0, NULL, 0);
864}
865
869static void folder_make_entry(struct Menu *menu, char *buf, size_t buflen, int line)
870{
871 struct BrowserState *bstate = menu->mdata;
872 struct BrowserStateEntry *entry = &bstate->entry;
873 struct Folder folder = {
874 .ff = ARRAY_GET(entry, line),
875 .num = line,
876 };
877
878#ifdef USE_NNTP
879 if (OptNews)
880 {
881 const char *const c_group_index_format = cs_subset_string(NeoMutt->sub, "group_index_format");
882 mutt_expando_format(buf, buflen, 0, menu->win->state.cols,
883 NONULL(c_group_index_format), group_index_format_str,
884 (intptr_t) &folder, MUTT_FORMAT_ARROWCURSOR);
885 }
886 else
887#endif
888 if (bstate->is_mailbox_list)
889 {
890 const char *const c_mailbox_folder_format = cs_subset_string(NeoMutt->sub, "mailbox_folder_format");
891 mutt_expando_format(buf, buflen, 0, menu->win->state.cols,
892 NONULL(c_mailbox_folder_format), folder_format_str,
893 (intptr_t) &folder, MUTT_FORMAT_ARROWCURSOR);
894 }
895 else
896 {
897 const char *const c_folder_format = cs_subset_string(NeoMutt->sub, "folder_format");
898 mutt_expando_format(buf, buflen, 0, menu->win->state.cols, NONULL(c_folder_format),
899 folder_format_str, (intptr_t) &folder, MUTT_FORMAT_ARROWCURSOR);
900 }
901}
902
911void browser_highlight_default(struct BrowserState *state, struct Menu *menu)
912{
913 menu->top = 0;
914 /* Reset menu position to 1.
915 * We do not risk overflow as the init_menu function changes
916 * current if it is bigger than state->entrylen. */
917 if (!ARRAY_EMPTY(&state->entry) &&
918 (mutt_str_equal(ARRAY_FIRST(&state->entry)->desc, "..") ||
919 mutt_str_equal(ARRAY_FIRST(&state->entry)->desc, "../")))
920 {
921 /* Skip the first entry, unless there's only one entry. */
922 menu_set_index(menu, (menu->max > 1));
923 }
924 else
925 {
926 menu_set_index(menu, 0);
927 }
928}
929
937void init_menu(struct BrowserState *state, struct Menu *menu, struct Mailbox *m,
938 struct MuttWindow *sbar)
939{
940 char title[256] = { 0 };
941 menu->max = ARRAY_SIZE(&state->entry);
942
943 int index = menu_get_index(menu);
944 if (index >= menu->max)
945 menu_set_index(menu, menu->max - 1);
946 if (index < 0)
947 menu_set_index(menu, 0);
948 if (menu->top > index)
949 menu->top = 0;
950
951 menu->num_tagged = 0;
952
953#ifdef USE_NNTP
954 if (OptNews)
955 {
956 if (state->is_mailbox_list)
957 {
958 snprintf(title, sizeof(title), _("Subscribed newsgroups"));
959 }
960 else
961 {
962 snprintf(title, sizeof(title), _("Newsgroups on server [%s]"),
964 }
965 }
966 else
967#endif
968 {
969 if (state->is_mailbox_list)
970 {
971 snprintf(title, sizeof(title), _("Mailboxes [%d]"),
973 }
974 else
975 {
976 struct Buffer *path = mutt_buffer_pool_get();
979 const struct Regex *c_mask = cs_subset_regex(NeoMutt->sub, "mask");
980#ifdef USE_IMAP
981 const bool c_imap_list_subscribed = cs_subset_bool(NeoMutt->sub, "imap_list_subscribed");
982 if (state->imap_browse && c_imap_list_subscribed)
983 {
984 snprintf(title, sizeof(title), _("Subscribed [%s], File mask: %s"),
985 mutt_buffer_string(path), NONULL(c_mask ? c_mask->pattern : NULL));
986 }
987 else
988#endif
989 {
990 snprintf(title, sizeof(title), _("Directory [%s], File mask: %s"),
991 mutt_buffer_string(path), NONULL(c_mask ? c_mask->pattern : NULL));
992 }
994 }
995 }
996 sbar_set_title(sbar, title);
997
998 /* Browser tracking feature.
999 * The goal is to highlight the good directory if LastDir is the parent dir
1000 * of LastDirBackup (this occurs mostly when one hit "../"). It should also work
1001 * properly when the user is in examine_mailboxes-mode. */
1003 {
1004 char target_dir[PATH_MAX] = { 0 };
1005
1006#ifdef USE_IMAP
1007 /* Check what kind of dir LastDirBackup is. */
1009 {
1010 mutt_str_copy(target_dir, mutt_buffer_string(&LastDirBackup), sizeof(target_dir));
1011 imap_clean_path(target_dir, sizeof(target_dir));
1012 }
1013 else
1014#endif
1015 mutt_str_copy(target_dir, strrchr(mutt_buffer_string(&LastDirBackup), '/') + 1,
1016 sizeof(target_dir));
1017
1018 /* If we get here, it means that LastDir is the parent directory of
1019 * LastDirBackup. I.e., we're returning from a subdirectory, and we want
1020 * to position the cursor on the directory we're returning from. */
1021 bool matched = false;
1022 struct FolderFile *ff = NULL;
1023 ARRAY_FOREACH(ff, &state->entry)
1024 {
1025 if (mutt_str_equal(ff->name, target_dir))
1026 {
1027 menu_set_index(menu, ARRAY_FOREACH_IDX);
1028 matched = true;
1029 break;
1030 }
1031 }
1032 if (!matched)
1033 browser_highlight_default(state, menu);
1034 }
1035 else
1036 {
1037 browser_highlight_default(state, menu);
1038 }
1039
1041}
1042
1046static int file_tag(struct Menu *menu, int sel, int act)
1047{
1048 struct BrowserStateEntry *entry = menu->mdata;
1049 struct FolderFile *ff = ARRAY_GET(entry, sel);
1050 if (S_ISDIR(ff->mode) ||
1051 (S_ISLNK(ff->mode) && link_is_dir(mutt_buffer_string(&LastDir), ff->name)))
1052 {
1053 mutt_error(_("Can't attach a directory"));
1054 return 0;
1055 }
1056
1057 bool ot = ff->tagged;
1058 ff->tagged = ((act >= 0) ? act : !ff->tagged);
1059
1060 return ff->tagged - ot;
1061}
1062
1067{
1068 if (nc->event_type != NT_CONFIG)
1069 return 0;
1070 if (!nc->global_data || !nc->event_data)
1071 return -1;
1072
1073 struct EventConfig *ev_c = nc->event_data;
1074
1075 if (!mutt_str_equal(ev_c->name, "browser_abbreviate_mailboxes") &&
1076 !mutt_str_equal(ev_c->name, "date_format") && !mutt_str_equal(ev_c->name, "folder") &&
1077 !mutt_str_equal(ev_c->name, "folder_format") &&
1078 !mutt_str_equal(ev_c->name, "group_index_format") &&
1079 !mutt_str_equal(ev_c->name, "mailbox_folder_format") &&
1080 !mutt_str_equal(ev_c->name, "sort_browser"))
1081 {
1082 return 0;
1083 }
1084
1085 struct Menu *menu = nc->global_data;
1087 mutt_debug(LL_DEBUG5, "config done, request WA_RECALC, MENU_REDRAW_FULL\n");
1088
1089 return 0;
1090}
1091
1100{
1101 if (nc->event_type != NT_WINDOW)
1102 return 0;
1103 if (!nc->global_data || !nc->event_data)
1104 return -1;
1106 return 0;
1107
1108 struct MuttWindow *win_menu = nc->global_data;
1109 struct EventWindow *ev_w = nc->event_data;
1110 if (ev_w->win != win_menu)
1111 return 0;
1112
1113 struct Menu *menu = win_menu->wdata;
1114
1117
1118 mutt_debug(LL_DEBUG5, "window delete done\n");
1119 return 0;
1120}
1121
1132void mutt_browser_select_dir(const char *f)
1133{
1134 init_lastdir();
1135
1137
1138 /* Method that will fetch the parent path depending on the type of the path. */
1139 char buf[PATH_MAX] = { 0 };
1142}
1143
1153 struct Mailbox *m, char ***files, int *numfiles)
1154{
1156 priv->file = file;
1157 priv->mailbox = m;
1158 priv->files = files;
1159 priv->numfiles = numfiles;
1160 struct MuttWindow *dlg = NULL;
1161
1162 priv->multiple = (flags & MUTT_SEL_MULTI);
1163 priv->folder = (flags & MUTT_SEL_FOLDER);
1164 priv->state.is_mailbox_list = (flags & MUTT_SEL_MAILBOX) && priv->folder;
1165 priv->last_selected_mailbox = -1;
1166
1167 init_lastdir();
1168
1169#ifdef USE_NNTP
1170 if (OptNews)
1171 {
1172 if (mutt_buffer_is_empty(file))
1173 {
1175
1176 /* default state for news reader mode is browse subscribed newsgroups */
1177 priv->state.is_mailbox_list = false;
1178 for (size_t i = 0; i < adata->groups_num; i++)
1179 {
1180 struct NntpMboxData *mdata = adata->groups_list[i];
1181 if (mdata && mdata->subscribed)
1182 {
1183 priv->state.is_mailbox_list = true;
1184 break;
1185 }
1186 }
1187 }
1188 else
1189 {
1190 mutt_buffer_copy(priv->prefix, file);
1191 }
1192 }
1193 else
1194#endif
1195 if (!mutt_buffer_is_empty(file))
1196 {
1198#ifdef USE_IMAP
1199 if (imap_path_probe(mutt_buffer_string(file), NULL) == MUTT_IMAP)
1200 {
1201 init_state(&priv->state, NULL);
1202 priv->state.imap_browse = true;
1203 if (imap_browse(mutt_buffer_string(file), &priv->state) == 0)
1204 {
1206 browser_sort(&priv->state);
1207 }
1208 }
1209 else
1210 {
1211#endif
1212 int i;
1213 for (i = mutt_buffer_len(file) - 1;
1214 (i > 0) && ((mutt_buffer_string(file))[i] != '/'); i--)
1215 {
1216 ; // do nothing
1217 }
1218
1219 if (i > 0)
1220 {
1221 if ((mutt_buffer_string(file))[0] == '/')
1222 {
1224 }
1225 else
1226 {
1230 }
1231 }
1232 else
1233 {
1234 if ((mutt_buffer_string(file))[0] == '/')
1236 else
1238 }
1239
1240 if ((i <= 0) && (mutt_buffer_string(file)[0] != '/'))
1241 mutt_buffer_copy(priv->prefix, file);
1242 else
1243 mutt_buffer_strcpy(priv->prefix, mutt_buffer_string(file) + i + 1);
1244 priv->kill_prefix = true;
1245#ifdef USE_IMAP
1246 }
1247#endif
1248 }
1249 else
1250 {
1251 if (!priv->folder)
1252 {
1254 }
1255 else
1256 {
1257 /* Whether we use the tracking feature of the browser depends
1258 * on which sort method we chose to use. This variable is defined
1259 * only to help readability of the code. */
1260 bool browser_track = false;
1261
1262 const short c_sort_browser = cs_subset_sort(NeoMutt->sub, "sort_browser");
1263 switch (c_sort_browser & SORT_MASK)
1264 {
1265 case SORT_DESC:
1266 case SORT_SUBJECT:
1267 case SORT_ORDER:
1268 browser_track = true;
1269 break;
1270 }
1271
1272 /* We use mutt_browser_select_dir to initialize the two
1273 * variables (LastDir, LastDirBackup) at the appropriate
1274 * values.
1275 *
1276 * We do it only when LastDir is not set (first pass there)
1277 * or when CurrentFolder and LastDirBackup are not the same.
1278 * This code is executed only when we list files, not when
1279 * we press up/down keys to navigate in a displayed list.
1280 *
1281 * We only do this when CurrentFolder has been set (ie, not
1282 * when listing folders on startup with "neomutt -y").
1283 *
1284 * This tracker is only used when browser_track is true,
1285 * meaning only with sort methods SUBJECT/DESC for now. */
1286 if (CurrentFolder)
1287 {
1289 {
1290 /* If browsing in "local"-mode, than we chose to define LastDir to
1291 * MailDir */
1293 {
1294 case MUTT_IMAP:
1295 case MUTT_MAILDIR:
1296 case MUTT_MBOX:
1297 case MUTT_MH:
1298 case MUTT_MMDF:
1299 {
1300 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
1301 const char *const c_spool_file = cs_subset_string(NeoMutt->sub, "spool_file");
1302 if (c_folder)
1303 mutt_buffer_strcpy(&LastDir, c_folder);
1304 else if (c_spool_file)
1305 mutt_browser_select_dir(c_spool_file);
1306 break;
1307 }
1308 default:
1310 break;
1311 }
1312 }
1314 {
1316 }
1317 }
1318
1319 /* When browser tracking feature is disabled, clear LastDirBackup */
1320 if (!browser_track)
1322 }
1323
1324#ifdef USE_IMAP
1325 if (!priv->state.is_mailbox_list &&
1327 {
1328 init_state(&priv->state, NULL);
1329 priv->state.imap_browse = true;
1331 browser_sort(&priv->state);
1332 }
1333 else
1334#endif
1335 {
1336 size_t i = mutt_buffer_len(&LastDir);
1337 while ((i > 0) && (mutt_buffer_string(&LastDir)[--i] == '/'))
1338 LastDir.data[i] = '\0';
1342 }
1343 }
1344
1345 mutt_buffer_reset(file);
1346
1347 const struct Mapping *help_data = NULL;
1348#ifdef USE_NNTP
1349 if (OptNews)
1350 help_data = FolderNewsHelp;
1351 else
1352#endif
1353 help_data = FolderHelp;
1354
1355 dlg = simple_dialog_new(MENU_FOLDER, WT_DLG_BROWSER, help_data);
1356
1357 priv->menu = dlg->wdata;
1358 dlg->wdata = priv;
1361 if (priv->multiple)
1362 priv->menu->tag = file_tag;
1363
1364 priv->sbar = window_find_child(dlg, WT_STATUS_BAR);
1366
1367 struct MuttWindow *win_menu = priv->menu->win;
1368
1369 // NT_COLOR is handled by the SimpleDialog
1372
1373 if (priv->state.is_mailbox_list)
1374 {
1375 examine_mailboxes(m, NULL, &priv->state);
1376 }
1377 else
1378#ifdef USE_IMAP
1379 if (!priv->state.imap_browse)
1380#endif
1381 {
1382 // examine_directory() calls browser_add_folder() which needs the menu
1383 if (examine_directory(m, priv->menu, &priv->state, mutt_buffer_string(&LastDir),
1384 mutt_buffer_string(priv->prefix)) == -1)
1385 {
1386 goto bail;
1387 }
1388 }
1389
1390 init_menu(&priv->state, priv->menu, m, priv->sbar);
1391 // only now do we have a valid priv->state to attach
1392 priv->menu->mdata = &priv->state;
1393
1394 // ---------------------------------------------------------------------------
1395 // Event Loop
1396 int op = OP_NULL;
1397 do
1398 {
1399 menu_tagging_dispatcher(priv->menu->win, op);
1400 window_redraw(NULL);
1401
1402 op = km_dokey(MENU_FOLDER);
1403 mutt_debug(LL_DEBUG1, "Got op %s (%d)\n", opcodes_get_name(op), op);
1404 if (op < 0)
1405 continue;
1406 if (op == OP_NULL)
1407 {
1409 continue;
1410 }
1412
1413 int rc = browser_function_dispatcher(priv->win_browser, op);
1414
1415 if (rc == FR_UNKNOWN)
1416 rc = menu_function_dispatcher(priv->menu->win, op);
1417 if (rc == FR_UNKNOWN)
1418 rc = global_function_dispatcher(NULL, op);
1419 } while (!priv->done);
1420 // ---------------------------------------------------------------------------
1421
1422bail:
1423 simple_dialog_free(&dlg);
1425}
1426
1436void mutt_select_file(char *file, size_t filelen, SelectFileFlags flags,
1437 struct Mailbox *m, char ***files, int *numfiles)
1438{
1439 struct Buffer *f_buf = mutt_buffer_pool_get();
1440
1441 mutt_buffer_strcpy(f_buf, NONULL(file));
1442 mutt_buffer_select_file(f_buf, flags, m, files, numfiles);
1443 mutt_str_copy(file, mutt_buffer_string(f_buf), filelen);
1444
1446}
#define ARRAY_RESERVE(head, num)
Reserve memory for the array.
Definition: array.h:188
#define ARRAY_FIRST(head)
Convenience method to get the first element.
Definition: array.h:134
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition: array.h:155
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition: array.h:211
#define ARRAY_EMPTY(head)
Check if an array is empty.
Definition: array.h:73
#define ARRAY_SIZE(head)
The number of elements stored.
Definition: array.h:86
#define ARRAY_INIT(head)
Initialize an array.
Definition: array.h:64
#define ARRAY_GET(head, idx)
Return the element at index.
Definition: array.h:108
int browser_function_dispatcher(struct MuttWindow *win_browser, int op)
Perform a Browser function.
Definition: functions.c:1142
#define MUTT_SEL_MAILBOX
Select a mailbox.
Definition: lib.h:56
void browser_sort(struct BrowserState *state)
Sort the entries in the browser.
Definition: sort.c:194
#define MUTT_SEL_FOLDER
Select a local directory.
Definition: lib.h:58
#define MUTT_SEL_MULTI
Multi-selection is enabled.
Definition: lib.h:57
uint8_t SelectFileFlags
Flags for mutt_select_file(), e.g. MUTT_SEL_MAILBOX.
Definition: lib.h:54
struct BrowserPrivateData * browser_private_data_new(void)
Create new Browser Data.
Definition: private_data.c:54
void mutt_select_file(char *file, size_t filelen, SelectFileFlags flags, struct Mailbox *m, char ***files, int *numfiles)
Let the user select a file.
Definition: browser.c:1436
void init_state(struct BrowserState *state, struct Menu *menu)
Initialise a browser state.
Definition: browser.c:595
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: browser.c:619
void init_menu(struct BrowserState *state, struct Menu *menu, struct Mailbox *m, struct MuttWindow *sbar)
Set up a new menu.
Definition: browser.c:937
static void init_lastdir(void)
Initialise the browser directories.
Definition: browser.c:144
static const struct Mapping FolderNewsHelp[]
Help Bar for the NNTP Mailbox browser dialog.
Definition: browser.c:122
struct Buffer LastDir
Definition: browser.c:136
void mutt_browser_select_dir(const char *f)
Remember the last directory selected.
Definition: browser.c:1132
struct Buffer LastDirBackup
Definition: browser.c:137
void mutt_buffer_select_file(struct Buffer *file, SelectFileFlags flags, struct Mailbox *m, char ***files, int *numfiles)
Let the user select a file.
Definition: browser.c:1152
static const struct Mapping FolderHelp[]
Help Bar for the File/Dir/Mailbox browser dialog.
Definition: browser.c:109
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: browser.c:542
void mutt_browser_cleanup(void)
Clean up working Buffers.
Definition: browser.c:158
void browser_highlight_default(struct BrowserState *state, struct Menu *menu)
Decide which browser item should be highlighted.
Definition: browser.c:911
int examine_mailboxes(struct Mailbox *m, struct Menu *menu, struct BrowserState *state)
Get list of mailboxes/subscribed newsgroups.
Definition: browser.c:747
bool link_is_dir(const char *folder, const char *path)
Does this symlink point to a directory?
Definition: browser.c:171
void mutt_buffer_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:313
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:298
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:365
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:347
size_t mutt_buffer_addstr_n(struct Buffer *buf, const char *s, size_t len)
Add a string to a Buffer, expanding it if necessary.
Definition: buffer.c:105
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:409
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:248
void mutt_buffer_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:189
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:168
size_t mutt_buffer_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition: buffer.c:500
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:85
size_t mutt_buffer_strcpy_n(struct Buffer *buf, const char *s, size_t len)
Copy a string into a Buffer.
Definition: buffer.c:380
size_t mutt_buffer_concat_path(struct Buffer *buf, const char *dir, const char *fname)
Join a directory name and a filename.
Definition: buffer.c:427
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:78
const struct Regex * cs_subset_regex(const struct ConfigSubset *sub, const char *name)
Get a regex config item by name.
Definition: helpers.c:243
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
short cs_subset_sort(const struct ConfigSubset *sub, const char *name)
Get a sort config item by name.
Definition: helpers.c:292
Convenience wrapper for the config headers.
Connection Library.
Convenience wrapper for the core headers.
void mutt_format_s(char *buf, size_t buflen, const char *prec, const char *s)
Format a simple string.
Definition: curs_lib.c:792
struct tm mutt_date_localtime(time_t t)
Converts calendar time to a broken-down time structure expressed in user timezone.
Definition: date.c:653
size_t mutt_date_localtime_format(char *buf, size_t buflen, const char *format, time_t t)
Format localtime.
Definition: date.c:698
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:428
@ FR_UNKNOWN
Unknown function.
Definition: dispatcher.h:33
DIR * mutt_file_opendir(const char *path, enum MuttOpenDirMode mode)
Open a directory.
Definition: file.c:614
@ MUTT_OPENDIR_NONE
Plain opendir()
Definition: file.h:73
Flags to control mutt_expando_format()
#define MUTT_FORMAT_NO_FLAGS
No flags are set.
Definition: format_flags.h:30
#define MUTT_FORMAT_OPTIONAL
Allow optional field processing.
Definition: format_flags.h:33
#define MUTT_FORMAT_ARROWCURSOR
Reserve space for arrow_cursor.
Definition: format_flags.h:35
uint8_t MuttFormatFlags
Flags for mutt_expando_format(), e.g. MUTT_FORMAT_FORCESUBJ.
Definition: format_flags.h:29
bool OptNews
(pseudo) used to change reader mode
Definition: globals.c:78
char * CurrentFolder
Currently selected mailbox.
Definition: globals.c:43
int menu_tagging_dispatcher(struct MuttWindow *win, int op)
Perform tagging operations on the Menu - Implements function_dispatcher_t -.
Definition: tagging.c:223
int global_function_dispatcher(struct MuttWindow *win, int op)
Perform a Global function - Implements function_dispatcher_t -.
Definition: global.c:164
int menu_function_dispatcher(struct MuttWindow *win, int op)
Perform a Menu function - Implements function_dispatcher_t -.
Definition: functions.c:320
void mutt_expando_format(char *buf, size_t buflen, size_t col, int cols, const char *src, format_t callback, intptr_t data, MuttFormatFlags flags)
Expand expandos (x) in a string -.
Definition: muttlib.c:778
const char * group_index_format_str(char *buf, size_t buflen, size_t col, int cols, char op, const char *src, const char *prec, const char *if_str, const char *else_str, intptr_t data, MuttFormatFlags flags)
Format a string for the newsgroup menu - Implements format_t -.
Definition: browse.c:55
static const char * folder_format_str(char *buf, size_t buflen, size_t col, int cols, char op, const char *src, const char *prec, const char *if_str, const char *else_str, intptr_t data, MuttFormatFlags flags)
Format a string for the folder browser - Implements format_t -.
Definition: browser.c:208
#define mutt_error(...)
Definition: logging.h:87
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
#define mutt_perror(...)
Definition: logging.h:88
static void folder_make_entry(struct Menu *menu, char *buf, size_t buflen, int line)
Format a menu item for the folder browser - Implements Menu::make_entry() -.
Definition: browser.c:869
static int select_file_search(struct Menu *menu, regex_t *rx, int line)
Menu search callback for matching files - Implements Menu::search() -.
Definition: browser.c:853
static int file_tag(struct Menu *menu, int sel, int act)
Tag an entry in the menu - Implements Menu::tag() -.
Definition: browser.c:1046
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe() -.
Definition: imap.c:2401
static int browser_config_observer(struct NotifyCallback *nc)
Notification that a Config Variable has changed - Implements observer_t -.
Definition: browser.c:1066
static int browser_window_observer(struct NotifyCallback *nc)
Notification that a Window has changed - Implements observer_t -.
Definition: browser.c:1099
void browser_private_data_free(struct BrowserPrivateData **ptr)
Free Private Browser Data - Implements MuttWindow::wdata_free() -.
Definition: private_data.c:36
Convenience wrapper for the gui headers.
void simple_dialog_free(struct MuttWindow **ptr)
Destroy a simple index Dialog.
Definition: simple.c:166
struct MuttWindow * simple_dialog_new(enum MenuType mtype, enum WindowType wtype, const struct Mapping *help_data)
Create a simple index Dialog.
Definition: simple.c:129
int imap_browse(const char *path, struct BrowserState *state)
IMAP hook into the folder browser.
Definition: browse.c:182
IMAP network mailbox.
void imap_clean_path(char *path, size_t plen)
Cleans an IMAP path using imap_fix_path.
Definition: util.c:187
int km_dokey(enum MenuType mtype)
Determine what a keypress should do.
Definition: keymap.c:796
void km_error_key(enum MenuType mtype)
Handle an unbound key sequence.
Definition: keymap.c:1062
Manage keymappings.
@ LL_DEBUG5
Log at debug level 5.
Definition: logging.h:44
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:209
@ MUTT_NOTMUCH
'Notmuch' (virtual) Mailbox type
Definition: mailbox.h:51
@ MUTT_MMDF
'mmdf' Mailbox type
Definition: mailbox.h:46
@ MUTT_POP
'POP3' Mailbox type
Definition: mailbox.h:52
@ MUTT_MH
'MH' Mailbox type
Definition: mailbox.h:47
@ MUTT_NNTP
'NNTP' (Usenet) Mailbox type
Definition: mailbox.h:49
@ MUTT_IMAP
'IMAP' Mailbox type
Definition: mailbox.h:50
@ MUTT_MBOX
'mbox' Mailbox type
Definition: mailbox.h:45
@ MUTT_MAILBOX_ANY
Match any Mailbox type.
Definition: mailbox.h:42
@ MUTT_MAILDIR
'Maildir' Mailbox type
Definition: mailbox.h:48
GUI present the user with a selectable list.
#define MENU_REDRAW_FULL
Redraw everything.
Definition: lib.h:60
void menu_queue_redraw(struct Menu *menu, MenuRedrawFlags redraw)
Queue a request for a redraw.
Definition: menu.c:178
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition: menu.c:154
MenuRedrawFlags menu_set_index(struct Menu *menu, int index)
Set the current selection in the Menu.
Definition: menu.c:168
Convenience wrapper for the library headers.
#define N_(a)
Definition: message.h:32
#define _(a)
Definition: message.h:28
bool notify_observer_remove(struct Notify *notify, const observer_t callback, const void *global_data)
Remove an observer from an object.
Definition: notify.c:228
bool notify_observer_add(struct Notify *notify, enum NotifyType type, observer_t callback, void *global_data)
Add an observer to an object.
Definition: notify.c:189
const char * mutt_path_getcwd(struct Buffer *cwd)
Get the current working directory.
Definition: path.c:561
bool mutt_regex_match(const struct Regex *regex, const char *str)
Shorthand to mutt_regex_capture()
Definition: regex.c:631
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:250
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:807
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:227
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:652
#define PATH_MAX
Definition: mutt.h:41
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:73
NeoMutt Logging.
int mutt_mailbox_check(struct Mailbox *m_cur, CheckStatsFlags flags)
Check all all Mailboxes for new mail.
Definition: mutt_mailbox.c:156
Mailbox helper functions.
void window_redraw(struct MuttWindow *win)
Reflow, recalc and repaint a tree of Windows.
Definition: mutt_window.c:603
struct MuttWindow * window_find_child(struct MuttWindow *win, enum WindowType type)
Recursively find a child Window of a given type.
Definition: mutt_window.c:521
@ WT_DLG_BROWSER
Browser Dialog, mutt_buffer_select_file()
Definition: mutt_window.h:80
@ WT_STATUS_BAR
Status Bar containing extra info about the Index/Pager/etc.
Definition: mutt_window.h:102
@ WT_MENU
An Window containing a Menu.
Definition: mutt_window.h:98
@ NT_WINDOW_DELETE
Window is about to be deleted.
Definition: mutt_window.h:205
void mutt_get_parent_path(const char *path, char *buf, size_t buflen)
Find the parent of a path (or mailbox)
Definition: muttlib.c:1550
void mutt_buffer_pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using '~' or '='.
Definition: muttlib.c:600
void mutt_buffer_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:322
void mutt_str_pretty_size(char *buf, size_t buflen, size_t num)
Display an abbreviated size, like 3.4K.
Definition: muttlib.c:1674
Some miscellaneous functions.
enum MailboxType mx_path_probe(const char *path)
Find a mailbox that understands a path.
Definition: mx.c:1326
API for mailboxes.
#define MUTT_MAILBOX_CHECK_NO_FLAGS
No flags are set.
Definition: mxapi.h:74
void neomutt_mailboxlist_clear(struct MailboxList *ml)
Free a Mailbox List.
Definition: neomutt.c:141
size_t neomutt_mailboxlist_get_all(struct MailboxList *head, struct NeoMutt *n, enum MailboxType type)
Get a List of all Mailboxes.
Definition: neomutt.c:164
Nntp-specific Account data.
Usenet network mailbox type; talk to an NNTP server.
struct NntpAccountData * CurrentNewsSrv
Current NNTP news server.
Definition: nntp.c:77
Nntp-specific Mailbox data.
@ NT_WINDOW
MuttWindow has changed, NotifyWindow, EventWindow.
Definition: notify_type.h:55
@ NT_CONFIG
Config has changed, NotifyConfig, EventConfig.
Definition: notify_type.h:43
const char * opcodes_get_name(int op)
Get the name of an opcode.
Definition: opcodes.c:46
All user-callable functions.
Private state data for the Pager.
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:324
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
#define TAILQ_EMPTY(head)
Definition: queue.h:721
void sbar_set_title(struct MuttWindow *win, const char *title)
Set the title for the Simple Bar.
Definition: sbar.c:224
Sidebar functions.
#define SORT_MASK
Mask for the sort id.
Definition: sort2.h:74
@ SORT_SUBJECT
Sort by the email's subject.
Definition: sort2.h:42
@ SORT_ORDER
Sort by the order the messages appear in the mailbox.
Definition: sort2.h:44
@ SORT_DESC
Sort by the folder's description.
Definition: sort2.h:59
Key value store.
#define NONULL(x)
Definition: string2.h:37
void * adata
Private data (for Mailbox backends)
Definition: account.h:43
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
bool folder
Select folders.
Definition: private_data.h:46
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 * win_browser
Browser Window.
Definition: private_data.h:52
struct MuttWindow * sbar
Status Bar.
Definition: private_data.h:51
State of the file/mailbox browser.
Definition: lib.h:111
char * folder
Folder name.
Definition: lib.h:115
bool is_mailbox_list
Viewing mailboxes.
Definition: lib.h:117
struct BrowserStateEntry entry
Array of files / dirs / mailboxes.
Definition: lib.h:112
bool imap_browse
IMAP folder.
Definition: lib.h:114
String manipulation buffer.
Definition: buffer.h:34
char * data
Pointer to data.
Definition: buffer.h:35
char host[128]
Server to login to.
Definition: connaccount.h:54
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:50
A config-change event.
Definition: subset.h:70
const char * name
Name of config item that changed.
Definition: subset.h:72
An Event that happened to a Window.
Definition: mutt_window.h:215
struct MuttWindow * win
Window that changed.
Definition: mutt_window.h:216
Browser entry representing a folder/dir.
Definition: lib.h:73
bool selectable
Folder can be selected.
Definition: lib.h:92
bool imap
This is an IMAP folder.
Definition: lib.h:91
bool has_mailbox
This is a mailbox.
Definition: lib.h:95
char * name
Name of file/dir/mailbox.
Definition: lib.h:81
uid_t uid
File's User ID.
Definition: lib.h:77
bool tagged
Folder is tagged.
Definition: lib.h:97
gid_t gid
File's Group ID.
Definition: lib.h:78
bool has_new_mail
true if mailbox has "new mail"
Definition: lib.h:84
nlink_t nlink
Number of hard links.
Definition: lib.h:79
char * desc
Description of mailbox.
Definition: lib.h:82
struct NntpMboxData * nd
Extra NNTP data.
Definition: lib.h:99
off_t size
File size.
Definition: lib.h:75
int gen
Unique id, used for (un)sorting.
Definition: lib.h:102
time_t mtime
Modification time.
Definition: lib.h:76
int msg_count
total number of messages
Definition: lib.h:85
mode_t mode
File permissions.
Definition: lib.h:74
bool inferiors
Folder has children.
Definition: lib.h:93
int msg_unread
number of unread messages
Definition: lib.h:86
A folder/dir in the browser.
Definition: lib.h:64
int num
Number in the index.
Definition: lib.h:66
struct FolderFile * ff
File / Dir / Mailbox.
Definition: lib.h:65
List of Mailboxes.
Definition: mailbox.h:152
struct Mailbox * mailbox
Mailbox in the list.
Definition: mailbox.h:153
A mailbox.
Definition: mailbox.h:79
bool has_new
Mailbox has new mail.
Definition: mailbox.h:85
char * realpath
Used for duplicate detection, context comparison, and the sidebar.
Definition: mailbox.h:81
int msg_count
Total number of messages.
Definition: mailbox.h:88
enum MailboxType type
Mailbox type.
Definition: mailbox.h:102
void * mdata
Driver specific data.
Definition: mailbox.h:132
char * name
A short name for the Mailbox.
Definition: mailbox.h:82
bool visible
True if a result of "mailboxes".
Definition: mailbox.h:130
int msg_unread
Number of unread messages.
Definition: mailbox.h:89
int gen
Generation number, for sorting.
Definition: mailbox.h:145
Mapping between user-readable string and a constant.
Definition: mapping.h:32
Definition: lib.h:70
struct MuttWindow * win
Window holding the Menu.
Definition: lib.h:77
void(* make_entry)(struct Menu *menu, char *buf, size_t buflen, int line)
Definition: lib.h:97
int num_tagged
Number of tagged entries.
Definition: lib.h:84
void(* mdata_free)(struct Menu *menu, void **ptr)
Definition: lib.h:152
int(* search)(struct Menu *menu, regex_t *rx, int line)
Definition: lib.h:110
int top
Entry that is the top of the current page.
Definition: lib.h:81
int(* tag)(struct Menu *menu, int sel, int act)
Definition: lib.h:122
void * mdata
Private data.
Definition: lib.h:138
int max
Number of entries in the menu.
Definition: lib.h:72
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:127
void * wdata
Private data.
Definition: mutt_window.h:145
struct Notify * notify
Notifications: NotifyWindow, EventWindow.
Definition: mutt_window.h:138
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct AccountList accounts
List of all Accounts.
Definition: neomutt.h:40
struct Notify * notify
Notifications handler.
Definition: neomutt.h:38
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
NNTP-specific Account data -.
Definition: adata.h:37
struct Connection * conn
Connection to NNTP Server.
Definition: adata.h:63
void ** groups_list
Definition: adata.h:61
NNTP-specific Mailbox data -.
Definition: mdata.h:33
char * group
Name of newsgroup.
Definition: mdata.h:34
struct NntpAccountData * adata
Definition: mdata.h:47
Data passed to a notification function.
Definition: observer.h:34
void * event_data
Data from notify_send()
Definition: observer.h:38
enum NotifyType event_type
Send: Event type, e.g. NT_ACCOUNT.
Definition: observer.h:36
int event_subtype
Send: Event subtype, e.g. NT_ACCOUNT_ADD.
Definition: observer.h:37
void * global_data
Data from notify_observer_add()
Definition: observer.h:39
Cached regular expression.
Definition: regex3.h:89
char * pattern
printable version
Definition: regex3.h:90
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:60
@ MENU_FOLDER
General file/mailbox browser.
Definition: type.h:44