NeoMutt  2023-11-03-85-g512e01
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
dlg_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 "imap/lib.h"
89#include "key/lib.h"
90#include "menu/lib.h"
91#include "nntp/lib.h"
92#include "format_flags.h"
93#include "functions.h"
94#include "globals.h"
95#include "mutt_logging.h"
96#include "mutt_mailbox.h"
97#include "muttlib.h"
98#include "mx.h"
99#include "nntp/adata.h"
100#include "nntp/mdata.h"
101#include "private_data.h"
102
104static const struct Mapping FolderHelp[] = {
105 // clang-format off
106 { N_("Exit"), OP_EXIT },
107 { N_("Chdir"), OP_CHANGE_DIRECTORY },
108 { N_("Goto"), OP_BROWSER_GOTO_FOLDER },
109 { N_("Mask"), OP_ENTER_MASK },
110 { N_("Help"), OP_HELP },
111 { NULL, 0 },
112 // clang-format on
113};
114
116static const struct Mapping FolderNewsHelp[] = {
117 // clang-format off
118 { N_("Exit"), OP_EXIT },
119 { N_("List"), OP_TOGGLE_MAILBOXES },
120 { N_("Subscribe"), OP_BROWSER_SUBSCRIBE },
121 { N_("Unsubscribe"), OP_BROWSER_UNSUBSCRIBE },
122 { N_("Catchup"), OP_CATCHUP },
123 { N_("Mask"), OP_ENTER_MASK },
124 { N_("Help"), OP_HELP },
125 { NULL, 0 },
126 // clang-format on
127};
128
130struct Buffer LastDir = { 0 };
132struct Buffer LastDirBackup = { 0 };
133
139static void init_lastdir(void)
140{
141 static bool done = false;
142 if (!done)
143 {
146 done = true;
147 }
148}
149
154{
157}
158
166bool link_is_dir(const char *folder, const char *path)
167{
168 struct stat st = { 0 };
169 bool rc = false;
170
171 struct Buffer *fullpath = buf_pool_get();
172 buf_concat_path(fullpath, folder, path);
173
174 if (stat(buf_string(fullpath), &st) == 0)
175 rc = S_ISDIR(st.st_mode);
176
177 buf_pool_release(&fullpath);
178
179 return rc;
180}
181
205static const char *folder_format_str(char *buf, size_t buflen, size_t col, int cols,
206 char op, const char *src, const char *prec,
207 const char *if_str, const char *else_str,
208 intptr_t data, MuttFormatFlags flags)
209{
210 char fn[128] = { 0 };
211 char fmt[128] = { 0 };
212 struct Folder *folder = (struct Folder *) data;
213 bool optional = (flags & MUTT_FORMAT_OPTIONAL);
214
215 switch (op)
216 {
217 case 'a':
218 if (!optional)
219 {
220 snprintf(fmt, sizeof(fmt), "%%%sd", prec);
221 snprintf(buf, buflen, fmt, folder->ff->notify_user);
222 }
223 else
224 {
225 if (folder->ff->notify_user == 0)
226 optional = false;
227 }
228 break;
229
230 case 'C':
231 snprintf(fmt, sizeof(fmt), "%%%sd", prec);
232 snprintf(buf, buflen, fmt, folder->num + 1);
233 break;
234
235 case 'd':
236 case 'D':
237 if (folder->ff->local)
238 {
239 bool use_c_locale = false;
240
241 const char *t_fmt = NULL;
242 if (op == 'D')
243 {
244 const char *const c_date_format = cs_subset_string(NeoMutt->sub, "date_format");
245 t_fmt = NONULL(c_date_format);
246 if (*t_fmt == '!')
247 {
248 t_fmt++;
249 use_c_locale = true;
250 }
251 }
252 else
253 {
254 static const time_t one_year = 31536000;
255 t_fmt = ((mutt_date_now() - folder->ff->mtime) < one_year) ? "%b %d %H:%M" : "%b %d %Y";
256 }
257
258 char date[128] = { 0 };
259 if (use_c_locale)
260 {
261 mutt_date_localtime_format_locale(date, sizeof(date), t_fmt,
262 folder->ff->mtime, NeoMutt->time_c_locale);
263 }
264 else
265 {
266 mutt_date_localtime_format(date, sizeof(date), t_fmt, folder->ff->mtime);
267 }
268
269 mutt_format_s(buf, buflen, prec, date);
270 }
271 else
272 {
273 mutt_format_s(buf, buflen, prec, "");
274 }
275 break;
276
277 case '[':
278 if (folder->ff->local)
279 {
280 char buf2[128] = { 0 };
281 bool use_c_locale = false;
282 struct tm tm = { 0 };
283
284 char *p = buf;
285
286 const char *cp = src;
287 if (*cp == '!')
288 {
289 use_c_locale = true;
290 cp++;
291 }
292
293 size_t len = buflen - 1;
294 while ((len > 0) && (*cp != ']'))
295 {
296 if (*cp == '%')
297 {
298 cp++;
299 if (len >= 2)
300 {
301 *p++ = '%';
302 *p++ = *cp;
303 len -= 2;
304 }
305 else
306 {
307 break; /* not enough space */
308 }
309 cp++;
310 }
311 else
312 {
313 *p++ = *cp++;
314 len--;
315 }
316 }
317 *p = '\0';
318
319 tm = mutt_date_localtime(folder->ff->mtime);
320
321 if (use_c_locale)
322 strftime_l(buf2, sizeof(buf2), buf, &tm, NeoMutt->time_c_locale);
323 else
324 strftime(buf2, sizeof(buf2), buf, &tm);
325
326 snprintf(fmt, sizeof(fmt), "%%%ss", prec);
327 snprintf(buf, buflen, fmt, buf2);
328 if (len > 0)
329 src = cp + 1;
330 }
331 else
332 {
333 mutt_format_s(buf, buflen, prec, "");
334 }
335 break;
336
337 case 'f':
338 {
339 char *s = NULL;
340
341 s = NONULL(folder->ff->name);
342
343 snprintf(fn, sizeof(fn), "%s%s", s,
344 folder->ff->local ?
345 (S_ISLNK(folder->ff->mode) ?
346 "@" :
347 (S_ISDIR(folder->ff->mode) ?
348 "/" :
349 (((folder->ff->mode & S_IXUSR) != 0) ? "*" : ""))) :
350 "");
351
352 mutt_format_s(buf, buflen, prec, fn);
353 break;
354 }
355 case 'F':
356 {
357 if (folder->ff->local)
358 {
359 char permission[11] = { 0 };
360 snprintf(permission, sizeof(permission), "%c%c%c%c%c%c%c%c%c%c",
361 S_ISDIR(folder->ff->mode) ? 'd' : (S_ISLNK(folder->ff->mode) ? 'l' : '-'),
362 ((folder->ff->mode & S_IRUSR) != 0) ? 'r' : '-',
363 ((folder->ff->mode & S_IWUSR) != 0) ? 'w' : '-',
364 ((folder->ff->mode & S_ISUID) != 0) ? 's' :
365 ((folder->ff->mode & S_IXUSR) != 0) ? 'x' :
366 '-',
367 ((folder->ff->mode & S_IRGRP) != 0) ? 'r' : '-',
368 ((folder->ff->mode & S_IWGRP) != 0) ? 'w' : '-',
369 ((folder->ff->mode & S_ISGID) != 0) ? 's' :
370 ((folder->ff->mode & S_IXGRP) != 0) ? 'x' :
371 '-',
372 ((folder->ff->mode & S_IROTH) != 0) ? 'r' : '-',
373 ((folder->ff->mode & S_IWOTH) != 0) ? 'w' : '-',
374 ((folder->ff->mode & S_ISVTX) != 0) ? 't' :
375 ((folder->ff->mode & S_IXOTH) != 0) ? 'x' :
376 '-');
377 mutt_format_s(buf, buflen, prec, permission);
378 }
379 else if (folder->ff->imap)
380 {
381 char permission[11] = { 0 };
382 /* mark folders with subfolders AND mail */
383 snprintf(permission, sizeof(permission), "IMAP %c",
384 (folder->ff->inferiors && folder->ff->selectable) ? '+' : ' ');
385 mutt_format_s(buf, buflen, prec, permission);
386 }
387 else
388 {
389 mutt_format_s(buf, buflen, prec, "");
390 }
391 break;
392 }
393
394 case 'g':
395 if (folder->ff->local)
396 {
397 struct group *gr = getgrgid(folder->ff->gid);
398 if (gr)
399 {
400 mutt_format_s(buf, buflen, prec, gr->gr_name);
401 }
402 else
403 {
404 snprintf(fmt, sizeof(fmt), "%%%sld", prec);
405 snprintf(buf, buflen, fmt, folder->ff->gid);
406 }
407 }
408 else
409 {
410 mutt_format_s(buf, buflen, prec, "");
411 }
412 break;
413
414 case 'i':
415 {
416 char *s = NULL;
417 if (folder->ff->desc)
418 s = folder->ff->desc;
419 else
420 s = folder->ff->name;
421
422 snprintf(fn, sizeof(fn), "%s%s", s,
423 folder->ff->local ?
424 (S_ISLNK(folder->ff->mode) ?
425 "@" :
426 (S_ISDIR(folder->ff->mode) ?
427 "/" :
428 (((folder->ff->mode & S_IXUSR) != 0) ? "*" : ""))) :
429 "");
430
431 mutt_format_s(buf, buflen, prec, fn);
432 break;
433 }
434
435 case 'l':
436 if (folder->ff->local)
437 {
438 snprintf(fmt, sizeof(fmt), "%%%sd", prec);
439 snprintf(buf, buflen, fmt, folder->ff->nlink);
440 }
441 else
442 {
443 mutt_format_s(buf, buflen, prec, "");
444 }
445 break;
446
447 case 'm':
448 if (!optional)
449 {
450 if (folder->ff->has_mailbox)
451 {
452 snprintf(fmt, sizeof(fmt), "%%%sd", prec);
453 snprintf(buf, buflen, fmt, folder->ff->msg_count);
454 }
455 else
456 {
457 mutt_format_s(buf, buflen, prec, "");
458 }
459 }
460 else if (folder->ff->msg_count == 0)
461 {
462 optional = false;
463 }
464 break;
465
466 case 'N':
467 snprintf(fmt, sizeof(fmt), "%%%sc", prec);
468 snprintf(buf, buflen, fmt, folder->ff->has_new_mail ? 'N' : ' ');
469 break;
470
471 case 'n':
472 if (!optional)
473 {
474 if (folder->ff->has_mailbox)
475 {
476 snprintf(fmt, sizeof(fmt), "%%%sd", prec);
477 snprintf(buf, buflen, fmt, folder->ff->msg_unread);
478 }
479 else
480 {
481 mutt_format_s(buf, buflen, prec, "");
482 }
483 }
484 else if (folder->ff->msg_unread == 0)
485 {
486 optional = false;
487 }
488 break;
489
490 case 'p':
491 if (!optional)
492 {
493 snprintf(fmt, sizeof(fmt), "%%%sd", prec);
494 snprintf(buf, buflen, fmt, folder->ff->poll_new_mail);
495 }
496 else
497 {
498 if (folder->ff->poll_new_mail == 0)
499 optional = false;
500 }
501 break;
502
503 case 's':
504 if (folder->ff->local)
505 {
506 mutt_str_pretty_size(fn, sizeof(fn), folder->ff->size);
507 snprintf(fmt, sizeof(fmt), "%%%ss", prec);
508 snprintf(buf, buflen, fmt, fn);
509 }
510 else
511 {
512 mutt_format_s(buf, buflen, prec, "");
513 }
514 break;
515
516 case 't':
517 snprintf(fmt, sizeof(fmt), "%%%sc", prec);
518 snprintf(buf, buflen, fmt, folder->ff->tagged ? '*' : ' ');
519 break;
520
521 case 'u':
522 if (folder->ff->local)
523 {
524 struct passwd *pw = getpwuid(folder->ff->uid);
525 if (pw)
526 {
527 mutt_format_s(buf, buflen, prec, pw->pw_name);
528 }
529 else
530 {
531 snprintf(fmt, sizeof(fmt), "%%%sld", prec);
532 snprintf(buf, buflen, fmt, folder->ff->uid);
533 }
534 }
535 else
536 {
537 mutt_format_s(buf, buflen, prec, "");
538 }
539 break;
540
541 default:
542 snprintf(fmt, sizeof(fmt), "%%%sc", prec);
543 snprintf(buf, buflen, fmt, op);
544 break;
545 }
546
547 if (optional)
548 {
549 mutt_expando_format(buf, buflen, col, cols, if_str, folder_format_str, data,
551 }
552 else if (flags & MUTT_FORMAT_OPTIONAL)
553 {
554 mutt_expando_format(buf, buflen, col, cols, else_str, folder_format_str,
556 }
557
558 /* We return the format string, unchanged */
559 return src;
560}
561
572void browser_add_folder(const struct Menu *menu, struct BrowserState *state,
573 const char *name, const char *desc,
574 const struct stat *st, struct Mailbox *m, void *data)
575{
576 if ((!menu || state->is_mailbox_list) && m && !m->visible)
577 {
578 return;
579 }
580
581 struct FolderFile ff = { 0 };
582
583 if (st)
584 {
585 ff.mode = st->st_mode;
586 ff.mtime = st->st_mtime;
587 ff.size = st->st_size;
588 ff.gid = st->st_gid;
589 ff.uid = st->st_uid;
590 ff.nlink = st->st_nlink;
591 ff.local = true;
592 }
593 else
594 {
595 ff.local = false;
596 }
597
598 if (m)
599 {
600 ff.has_mailbox = true;
601 ff.gen = m->gen;
602 ff.has_new_mail = m->has_new;
603 ff.msg_count = m->msg_count;
604 ff.msg_unread = m->msg_unread;
605 ff.notify_user = m->notify_user;
607 }
608
609 ff.name = mutt_str_dup(name);
610 ff.desc = mutt_str_dup(desc ? desc : name);
611 ff.imap = false;
612 if (OptNews)
613 ff.nd = data;
614
615 ARRAY_ADD(&state->entry, ff);
616}
617
623void init_state(struct BrowserState *state, struct Menu *menu)
624{
625 ARRAY_INIT(&state->entry);
626 ARRAY_RESERVE(&state->entry, 256);
627 state->imap_browse = false;
628
629 if (menu)
630 {
631 menu->mdata = &state->entry;
632 menu->mdata_free = NULL; // Menu doesn't own the data
633 }
634}
635
646int examine_directory(struct Mailbox *m, struct Menu *menu, struct BrowserState *state,
647 const char *dirname, const char *prefix)
648{
649 int rc = -1;
650 struct Buffer *buf = buf_pool_get();
651 if (OptNews)
652 {
654
655 init_state(state, menu);
656
657 const struct Regex *c_mask = cs_subset_regex(NeoMutt->sub, "mask");
658 for (unsigned int i = 0; i < adata->groups_num; i++)
659 {
660 struct NntpMboxData *mdata = adata->groups_list[i];
661 if (!mdata)
662 continue;
663 if (prefix && *prefix && !mutt_str_startswith(mdata->group, prefix))
664 continue;
665 if (!mutt_regex_match(c_mask, mdata->group))
666 {
667 continue;
668 }
669 browser_add_folder(menu, state, mdata->group, NULL, NULL, NULL, mdata);
670 }
671 }
672 else
673 {
674 struct stat st = { 0 };
675 DIR *dir = NULL;
676 struct dirent *de = NULL;
677
678 while (stat(dirname, &st) == -1)
679 {
680 if (errno == ENOENT)
681 {
682 /* The last used directory is deleted, try to use the parent dir. */
683 char *c = strrchr(dirname, '/');
684
685 if (c && (c > dirname))
686 {
687 *c = '\0';
688 continue;
689 }
690 }
691 mutt_perror("%s", dirname);
692 goto ed_out;
693 }
694
695 if (!S_ISDIR(st.st_mode))
696 {
697 mutt_error(_("%s is not a directory"), dirname);
698 goto ed_out;
699 }
700
701 if (m)
703
704 dir = mutt_file_opendir(dirname, MUTT_OPENDIR_NONE);
705 if (!dir)
706 {
707 mutt_perror("%s", dirname);
708 goto ed_out;
709 }
710
711 init_state(state, menu);
712
713 struct MailboxList ml = STAILQ_HEAD_INITIALIZER(ml);
715
716 const struct Regex *c_mask = cs_subset_regex(NeoMutt->sub, "mask");
717 while ((de = readdir(dir)))
718 {
719 if (mutt_str_equal(de->d_name, "."))
720 continue; /* we don't need . */
721
722 if (prefix && *prefix && !mutt_str_startswith(de->d_name, prefix))
723 {
724 continue;
725 }
726 if (!mutt_regex_match(c_mask, de->d_name))
727 {
728 continue;
729 }
730
731 buf_concat_path(buf, dirname, de->d_name);
732 if (lstat(buf_string(buf), &st) == -1)
733 continue;
734
735 /* No size for directories or symlinks */
736 if (S_ISDIR(st.st_mode) || S_ISLNK(st.st_mode))
737 st.st_size = 0;
738 else if (!S_ISREG(st.st_mode))
739 continue;
740
741 struct MailboxNode *np = NULL;
742 STAILQ_FOREACH(np, &ml, entries)
743 {
745 break;
746 }
747
748 if (np && m && m->poll_new_mail && mutt_str_equal(np->mailbox->realpath, m->realpath))
749 {
750 np->mailbox->msg_count = m->msg_count;
751 np->mailbox->msg_unread = m->msg_unread;
752 }
753 browser_add_folder(menu, state, de->d_name, NULL, &st, np ? np->mailbox : NULL, NULL);
754 }
756 closedir(dir);
757 }
758 browser_sort(state);
759 rc = 0;
760ed_out:
761 buf_pool_release(&buf);
762 return rc;
763}
764
773int examine_mailboxes(struct Mailbox *m, struct Menu *menu, struct BrowserState *state)
774{
775 struct stat st = { 0 };
776 struct Buffer *md = NULL;
777 struct Buffer *mailbox = NULL;
778
779 if (OptNews)
780 {
782
783 init_state(state, menu);
784
785 const bool c_show_only_unread = cs_subset_bool(NeoMutt->sub, "show_only_unread");
786 for (unsigned int i = 0; i < adata->groups_num; i++)
787 {
788 struct NntpMboxData *mdata = adata->groups_list[i];
789 if (mdata && (mdata->has_new_mail ||
790 (mdata->subscribed && (mdata->unread || !c_show_only_unread))))
791 {
792 browser_add_folder(menu, state, mdata->group, NULL, NULL, NULL, mdata);
793 }
794 }
795 }
796 else
797 {
798 init_state(state, menu);
799
801 return -1;
802 mailbox = buf_pool_get();
803 md = buf_pool_get();
804
806
807 struct MailboxList ml = STAILQ_HEAD_INITIALIZER(ml);
809 struct MailboxNode *np = NULL;
810 const bool c_browser_abbreviate_mailboxes = cs_subset_bool(NeoMutt->sub, "browser_abbreviate_mailboxes");
811
812 STAILQ_FOREACH(np, &ml, entries)
813 {
814 if (!np->mailbox)
815 continue;
816
817 if (m && m->poll_new_mail && mutt_str_equal(np->mailbox->realpath, m->realpath))
818 {
819 np->mailbox->msg_count = m->msg_count;
820 np->mailbox->msg_unread = m->msg_unread;
821 }
822
824 if (c_browser_abbreviate_mailboxes)
826
827 switch (np->mailbox->type)
828 {
829 case MUTT_IMAP:
830 case MUTT_POP:
832 np->mailbox->name, NULL, np->mailbox, NULL);
833 continue;
834 case MUTT_NOTMUCH:
835 case MUTT_NNTP:
836 browser_add_folder(menu, state, mailbox_path(np->mailbox),
837 np->mailbox->name, NULL, np->mailbox, NULL);
838 continue;
839 default: /* Continue */
840 break;
841 }
842
843 if (lstat(mailbox_path(np->mailbox), &st) == -1)
844 continue;
845
846 if ((!S_ISREG(st.st_mode)) && (!S_ISDIR(st.st_mode)) && (!S_ISLNK(st.st_mode)))
847 continue;
848
849 if (np->mailbox->type == MUTT_MAILDIR)
850 {
851 struct stat st2 = { 0 };
852
853 buf_printf(md, "%s/new", mailbox_path(np->mailbox));
854 if (stat(buf_string(md), &st) < 0)
855 st.st_mtime = 0;
856 buf_printf(md, "%s/cur", mailbox_path(np->mailbox));
857 if (stat(buf_string(md), &st2) < 0)
858 st2.st_mtime = 0;
859 if (st2.st_mtime > st.st_mtime)
860 st.st_mtime = st2.st_mtime;
861 }
862
863 browser_add_folder(menu, state, buf_string(mailbox), np->mailbox->name,
864 &st, np->mailbox, NULL);
865 }
867 }
868 browser_sort(state);
869
870 buf_pool_release(&mailbox);
871 buf_pool_release(&md);
872 return 0;
873}
874
878static int select_file_search(struct Menu *menu, regex_t *rx, int line)
879{
880 struct BrowserEntryArray *entry = menu->mdata;
881 if (OptNews)
882 return regexec(rx, ARRAY_GET(entry, line)->desc, 0, NULL, 0);
883 struct FolderFile *ff = ARRAY_GET(entry, line);
884 char *search_on = ff->desc ? ff->desc : ff->name;
885
886 return regexec(rx, search_on, 0, NULL, 0);
887}
888
894static void folder_make_entry(struct Menu *menu, char *buf, size_t buflen, int line)
895{
896 struct BrowserState *bstate = menu->mdata;
897 struct BrowserEntryArray *entry = &bstate->entry;
898 struct Folder folder = {
899 .ff = ARRAY_GET(entry, line),
900 .num = line,
901 };
902
903 if (OptNews)
904 {
905 const char *const c_group_index_format = cs_subset_string(NeoMutt->sub, "group_index_format");
906 mutt_expando_format(buf, buflen, 0, menu->win->state.cols,
907 NONULL(c_group_index_format), group_index_format_str,
908 (intptr_t) &folder, MUTT_FORMAT_ARROWCURSOR);
909 }
910 else if (bstate->is_mailbox_list)
911 {
912 const char *const c_mailbox_folder_format = cs_subset_string(NeoMutt->sub, "mailbox_folder_format");
913 mutt_expando_format(buf, buflen, 0, menu->win->state.cols,
914 NONULL(c_mailbox_folder_format), folder_format_str,
915 (intptr_t) &folder, MUTT_FORMAT_ARROWCURSOR);
916 }
917 else
918 {
919 const char *const c_folder_format = cs_subset_string(NeoMutt->sub, "folder_format");
920 mutt_expando_format(buf, buflen, 0, menu->win->state.cols, NONULL(c_folder_format),
921 folder_format_str, (intptr_t) &folder, MUTT_FORMAT_ARROWCURSOR);
922 }
923}
924
933void browser_highlight_default(struct BrowserState *state, struct Menu *menu)
934{
935 menu->top = 0;
936 /* Reset menu position to 1.
937 * We do not risk overflow as the init_menu function changes
938 * current if it is bigger than state->entrylen. */
939 if (!ARRAY_EMPTY(&state->entry) &&
940 (mutt_str_equal(ARRAY_FIRST(&state->entry)->desc, "..") ||
941 mutt_str_equal(ARRAY_FIRST(&state->entry)->desc, "../")))
942 {
943 /* Skip the first entry, unless there's only one entry. */
944 menu_set_index(menu, (menu->max > 1));
945 }
946 else
947 {
948 menu_set_index(menu, 0);
949 }
950}
951
959void init_menu(struct BrowserState *state, struct Menu *menu, struct Mailbox *m,
960 struct MuttWindow *sbar)
961{
962 char title[256] = { 0 };
963 menu->max = ARRAY_SIZE(&state->entry);
964
965 int index = menu_get_index(menu);
966 if (index >= menu->max)
967 menu_set_index(menu, menu->max - 1);
968 if (index < 0)
969 menu_set_index(menu, 0);
970 if (menu->top > index)
971 menu->top = 0;
972
973 menu->num_tagged = 0;
974
975 if (OptNews)
976 {
977 if (state->is_mailbox_list)
978 {
979 snprintf(title, sizeof(title), _("Subscribed newsgroups"));
980 }
981 else
982 {
983 snprintf(title, sizeof(title), _("Newsgroups on server [%s]"),
985 }
986 }
987 else
988 {
989 if (state->is_mailbox_list)
990 {
991 snprintf(title, sizeof(title), _("Mailboxes [%d]"),
993 }
994 else
995 {
996 struct Buffer *path = buf_pool_get();
997 buf_copy(path, &LastDir);
998 buf_pretty_mailbox(path);
999 const struct Regex *c_mask = cs_subset_regex(NeoMutt->sub, "mask");
1000 const bool c_imap_list_subscribed = cs_subset_bool(NeoMutt->sub, "imap_list_subscribed");
1001 if (state->imap_browse && c_imap_list_subscribed)
1002 {
1003 snprintf(title, sizeof(title), _("Subscribed [%s], File mask: %s"),
1004 buf_string(path), NONULL(c_mask ? c_mask->pattern : NULL));
1005 }
1006 else
1007 {
1008 snprintf(title, sizeof(title), _("Directory [%s], File mask: %s"),
1009 buf_string(path), NONULL(c_mask ? c_mask->pattern : NULL));
1010 }
1011 buf_pool_release(&path);
1012 }
1013 }
1014 sbar_set_title(sbar, title);
1015
1016 /* Browser tracking feature.
1017 * The goal is to highlight the good directory if LastDir is the parent dir
1018 * of LastDirBackup (this occurs mostly when one hit "../"). It should also work
1019 * properly when the user is in examine_mailboxes-mode. */
1021 {
1022 char target_dir[PATH_MAX] = { 0 };
1023
1024 /* Check what kind of dir LastDirBackup is. */
1026 {
1027 mutt_str_copy(target_dir, buf_string(&LastDirBackup), sizeof(target_dir));
1028 imap_clean_path(target_dir, sizeof(target_dir));
1029 }
1030 else
1031 {
1032 mutt_str_copy(target_dir, strrchr(buf_string(&LastDirBackup), '/') + 1,
1033 sizeof(target_dir));
1034 }
1035
1036 /* If we get here, it means that LastDir is the parent directory of
1037 * LastDirBackup. I.e., we're returning from a subdirectory, and we want
1038 * to position the cursor on the directory we're returning from. */
1039 bool matched = false;
1040 struct FolderFile *ff = NULL;
1041 ARRAY_FOREACH(ff, &state->entry)
1042 {
1043 if (mutt_str_equal(ff->name, target_dir))
1044 {
1045 menu_set_index(menu, ARRAY_FOREACH_IDX);
1046 matched = true;
1047 break;
1048 }
1049 }
1050 if (!matched)
1051 browser_highlight_default(state, menu);
1052 }
1053 else
1054 {
1055 browser_highlight_default(state, menu);
1056 }
1057
1059}
1060
1064static int file_tag(struct Menu *menu, int sel, int act)
1065{
1066 struct BrowserEntryArray *entry = menu->mdata;
1067 struct FolderFile *ff = ARRAY_GET(entry, sel);
1068 if (S_ISDIR(ff->mode) ||
1069 (S_ISLNK(ff->mode) && link_is_dir(buf_string(&LastDir), ff->name)))
1070 {
1071 mutt_error(_("Can't attach a directory"));
1072 return 0;
1073 }
1074
1075 bool ot = ff->tagged;
1076 ff->tagged = ((act >= 0) ? act : !ff->tagged);
1077
1078 return ff->tagged - ot;
1079}
1080
1085{
1086 if (nc->event_type != NT_CONFIG)
1087 return 0;
1088 if (!nc->global_data || !nc->event_data)
1089 return -1;
1090
1091 struct EventConfig *ev_c = nc->event_data;
1092
1093 struct BrowserPrivateData *priv = nc->global_data;
1094 struct Menu *menu = priv->menu;
1095
1096 if (mutt_str_equal(ev_c->name, "browser_sort_dirs_first"))
1097 {
1098 struct BrowserState *state = menu->mdata;
1099 browser_sort(state);
1100 browser_highlight_default(state, menu);
1101 }
1102 else if (!mutt_str_equal(ev_c->name, "browser_abbreviate_mailboxes") &&
1103 !mutt_str_equal(ev_c->name, "date_format") &&
1104 !mutt_str_equal(ev_c->name, "folder") &&
1105 !mutt_str_equal(ev_c->name, "folder_format") &&
1106 !mutt_str_equal(ev_c->name, "group_index_format") &&
1107 !mutt_str_equal(ev_c->name, "mailbox_folder_format") &&
1108 !mutt_str_equal(ev_c->name, "sort_browser"))
1109 {
1110 return 0;
1111 }
1112
1114 mutt_debug(LL_DEBUG5, "config done, request WA_RECALC, MENU_REDRAW_FULL\n");
1115
1116 return 0;
1117}
1118
1125{
1126 if (nc->event_type != NT_MAILBOX)
1127 return 0;
1129 return 0;
1130 if (!nc->global_data || !nc->event_data)
1131 return -1;
1132
1133 struct BrowserPrivateData *priv = nc->global_data;
1134
1135 struct BrowserState *state = &priv->state;
1136 if (state->is_mailbox_list)
1137 {
1138 struct EventMailbox *ev_m = nc->event_data;
1139 struct Mailbox *m = ev_m->mailbox;
1140 struct FolderFile *ff = NULL;
1141 ARRAY_FOREACH(ff, &state->entry)
1142 {
1143 if (ff->gen != m->gen)
1144 continue;
1145
1146 ff->has_new_mail = m->has_new;
1147 ff->msg_count = m->msg_count;
1148 ff->msg_unread = m->msg_unread;
1149 ff->notify_user = m->notify_user;
1151 mutt_str_replace(&ff->desc, m->name);
1152 break;
1153 }
1154 }
1155
1157 mutt_debug(LL_DEBUG5, "mailbox done, request WA_RECALC, MENU_REDRAW_FULL\n");
1158
1159 return 0;
1160}
1161
1170{
1171 if (nc->event_type != NT_WINDOW)
1172 return 0;
1173 if (!nc->global_data || !nc->event_data)
1174 return -1;
1176 return 0;
1177
1178 struct BrowserPrivateData *priv = nc->global_data;
1179 struct MuttWindow *win_menu = priv->menu->win;
1180
1181 struct EventWindow *ev_w = nc->event_data;
1182 if (ev_w->win != win_menu)
1183 return 0;
1184
1188
1189 mutt_debug(LL_DEBUG5, "window delete done\n");
1190 return 0;
1191}
1192
1203void mutt_browser_select_dir(const char *f)
1204{
1205 init_lastdir();
1206
1208
1209 /* Method that will fetch the parent path depending on the type of the path. */
1210 char buf[PATH_MAX] = { 0 };
1211 mutt_get_parent_path(buf_string(&LastDirBackup), buf, sizeof(buf));
1212 buf_strcpy(&LastDir, buf);
1213}
1214
1226void dlg_browser(struct Buffer *file, SelectFileFlags flags, struct Mailbox *m,
1227 char ***files, int *numfiles)
1228{
1230 priv->file = file;
1231 priv->mailbox = m;
1232 priv->files = files;
1233 priv->numfiles = numfiles;
1234 struct MuttWindow *dlg = NULL;
1235
1236 priv->multiple = (flags & MUTT_SEL_MULTI);
1237 priv->folder = (flags & MUTT_SEL_FOLDER);
1238 priv->state.is_mailbox_list = (flags & MUTT_SEL_MAILBOX) && priv->folder;
1239 priv->last_selected_mailbox = -1;
1240
1241 init_lastdir();
1242
1243 if (OptNews)
1244 {
1245 if (buf_is_empty(file))
1246 {
1248
1249 /* default state for news reader mode is browse subscribed newsgroups */
1250 priv->state.is_mailbox_list = false;
1251 for (size_t i = 0; i < adata->groups_num; i++)
1252 {
1253 struct NntpMboxData *mdata = adata->groups_list[i];
1254 if (mdata && mdata->subscribed)
1255 {
1256 priv->state.is_mailbox_list = true;
1257 break;
1258 }
1259 }
1260 }
1261 else
1262 {
1263 buf_copy(priv->prefix, file);
1264 }
1265 }
1266 else if (!buf_is_empty(file))
1267 {
1268 buf_expand_path(file);
1269 if (imap_path_probe(buf_string(file), NULL) == MUTT_IMAP)
1270 {
1271 init_state(&priv->state, NULL);
1272 priv->state.imap_browse = true;
1273 if (imap_browse(buf_string(file), &priv->state) == 0)
1274 {
1275 buf_strcpy(&LastDir, priv->state.folder);
1276 browser_sort(&priv->state);
1277 }
1278 }
1279 else
1280 {
1281 int i;
1282 for (i = buf_len(file) - 1; (i > 0) && ((buf_string(file))[i] != '/'); i--)
1283 {
1284 ; // do nothing
1285 }
1286
1287 if (i > 0)
1288 {
1289 if ((buf_string(file))[0] == '/')
1290 {
1291 buf_strcpy_n(&LastDir, buf_string(file), i);
1292 }
1293 else
1294 {
1296 buf_addch(&LastDir, '/');
1297 buf_addstr_n(&LastDir, buf_string(file), i);
1298 }
1299 }
1300 else
1301 {
1302 if ((buf_string(file))[0] == '/')
1303 buf_strcpy(&LastDir, "/");
1304 else
1306 }
1307
1308 if ((i <= 0) && (buf_string(file)[0] != '/'))
1309 buf_copy(priv->prefix, file);
1310 else
1311 buf_strcpy(priv->prefix, buf_string(file) + i + 1);
1312 priv->kill_prefix = true;
1313 }
1314 }
1315 else
1316 {
1317 if (priv->folder)
1318 {
1319 /* Whether we use the tracking feature of the browser depends
1320 * on which sort method we chose to use. This variable is defined
1321 * only to help readability of the code. */
1322 bool browser_track = false;
1323
1324 const enum SortType c_sort_browser = cs_subset_sort(NeoMutt->sub, "sort_browser");
1325 switch (c_sort_browser & SORT_MASK)
1326 {
1327 case SORT_DESC:
1328 case SORT_SUBJECT:
1329 case SORT_ORDER:
1330 browser_track = true;
1331 break;
1332 }
1333
1334 /* We use mutt_browser_select_dir to initialize the two
1335 * variables (LastDir, LastDirBackup) at the appropriate
1336 * values.
1337 *
1338 * We do it only when LastDir is not set (first pass there)
1339 * or when CurrentFolder and LastDirBackup are not the same.
1340 * This code is executed only when we list files, not when
1341 * we press up/down keys to navigate in a displayed list.
1342 *
1343 * We only do this when CurrentFolder has been set (ie, not
1344 * when listing folders on startup with "neomutt -y").
1345 *
1346 * This tracker is only used when browser_track is true,
1347 * meaning only with sort methods SUBJECT/DESC for now. */
1348 if (CurrentFolder)
1349 {
1350 if (buf_is_empty(&LastDir))
1351 {
1352 /* If browsing in "local"-mode, than we chose to define LastDir to
1353 * MailDir */
1355 {
1356 case MUTT_IMAP:
1357 case MUTT_MAILDIR:
1358 case MUTT_MBOX:
1359 case MUTT_MH:
1360 case MUTT_MMDF:
1361 {
1362 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
1363 const char *const c_spool_file = cs_subset_string(NeoMutt->sub, "spool_file");
1364 if (c_folder)
1365 buf_strcpy(&LastDir, c_folder);
1366 else if (c_spool_file)
1367 mutt_browser_select_dir(c_spool_file);
1368 break;
1369 }
1370 default:
1372 break;
1373 }
1374 }
1376 {
1378 }
1379 }
1380
1381 /* When browser tracking feature is disabled, clear LastDirBackup */
1382 if (!browser_track)
1384 }
1385 else
1386 {
1388 }
1389
1390 if (!priv->state.is_mailbox_list &&
1392 {
1393 init_state(&priv->state, NULL);
1394 priv->state.imap_browse = true;
1396 browser_sort(&priv->state);
1397 }
1398 else
1399 {
1400 size_t i = buf_len(&LastDir);
1401 while ((i > 0) && (buf_string(&LastDir)[--i] == '/'))
1402 LastDir.data[i] = '\0';
1404 if (buf_is_empty(&LastDir))
1406 }
1407 }
1408
1409 buf_reset(file);
1410
1411 const struct Mapping *help_data = NULL;
1412
1413 if (OptNews)
1414 help_data = FolderNewsHelp;
1415 else
1416 help_data = FolderHelp;
1417
1418 dlg = simple_dialog_new(MENU_FOLDER, WT_DLG_BROWSER, help_data);
1419
1420 priv->menu = dlg->wdata;
1421 dlg->wdata = priv;
1424 if (priv->multiple)
1425 priv->menu->tag = file_tag;
1426
1427 priv->sbar = window_find_child(dlg, WT_STATUS_BAR);
1429
1430 struct MuttWindow *win_menu = priv->menu->win;
1431
1432 // NT_COLOR is handled by the SimpleDialog
1436
1437 struct MuttWindow *old_focus = window_set_focus(priv->menu->win);
1438
1439 if (priv->state.is_mailbox_list)
1440 {
1441 examine_mailboxes(m, NULL, &priv->state);
1442 }
1443 else if (!priv->state.imap_browse)
1444 {
1445 // examine_directory() calls browser_add_folder() which needs the menu
1446 if (examine_directory(m, priv->menu, &priv->state, buf_string(&LastDir),
1447 buf_string(priv->prefix)) == -1)
1448 {
1449 goto bail;
1450 }
1451 }
1452
1453 init_menu(&priv->state, priv->menu, m, priv->sbar);
1454 // only now do we have a valid priv->state to attach
1455 priv->menu->mdata = &priv->state;
1456
1457 // ---------------------------------------------------------------------------
1458 // Event Loop
1459 int op = OP_NULL;
1460 do
1461 {
1462 menu_tagging_dispatcher(priv->menu->win, op);
1463 window_redraw(NULL);
1464
1466 mutt_debug(LL_DEBUG1, "Got op %s (%d)\n", opcodes_get_name(op), op);
1467 if (op < 0)
1468 continue;
1469 if (op == OP_NULL)
1470 {
1472 continue;
1473 }
1475
1476 int rc = browser_function_dispatcher(priv->win_browser, op);
1477
1478 if (rc == FR_UNKNOWN)
1479 rc = menu_function_dispatcher(priv->menu->win, op);
1480 if (rc == FR_UNKNOWN)
1481 rc = global_function_dispatcher(NULL, op);
1482 } while (!priv->done);
1483 // ---------------------------------------------------------------------------
1484
1485bail:
1486 window_set_focus(old_focus);
1487 simple_dialog_free(&dlg);
1489}
#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, int op)
Perform a Browser function.
Definition: functions.c:1138
#define MUTT_SEL_MAILBOX
Select a mailbox.
Definition: lib.h:58
void browser_sort(struct BrowserState *state)
Sort the entries in the browser.
Definition: sort.c:185
#define MUTT_SEL_FOLDER
Select a local directory.
Definition: lib.h:60
#define MUTT_SEL_MULTI
Multi-selection is enabled.
Definition: lib.h:59
uint8_t SelectFileFlags
Flags for mutt_select_file(), e.g. MUTT_SEL_MAILBOX.
Definition: lib.h:56
struct BrowserPrivateData * browser_private_data_new(void)
Create new Browser Data.
Definition: private_data.c:55
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:173
size_t buf_addstr_n(struct Buffer *buf, const char *s, size_t len)
Add a string to a Buffer, expanding it if necessary.
Definition: buffer.c:108
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:466
void buf_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:389
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:88
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:303
void buf_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:194
size_t buf_strcpy_n(struct Buffer *buf, const char *s, size_t len)
Copy a string into a Buffer.
Definition: buffer.c:422
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:253
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:407
size_t buf_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition: buffer.c:572
size_t buf_concat_path(struct Buffer *buf, const char *dir, const char *fname)
Join a directory name and a filename.
Definition: buffer.c:484
void buf_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:349
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:93
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
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:48
short cs_subset_sort(const struct ConfigSubset *sub, const char *name)
Get a sort config item by name.
Definition: helpers.c:267
Convenience wrapper for the config headers.
Connection Library.
Convenience wrapper for the core headers.
@ FR_UNKNOWN
Unknown function.
Definition: dispatcher.h:33
void init_state(struct BrowserState *state, struct Menu *menu)
Initialise a browser state.
Definition: dlg_browser.c:623
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:646
void init_menu(struct BrowserState *state, struct Menu *menu, struct Mailbox *m, struct MuttWindow *sbar)
Set up a new menu.
Definition: dlg_browser.c:959
static void init_lastdir(void)
Initialise the browser directories.
Definition: dlg_browser.c:139
static const struct Mapping FolderNewsHelp[]
Help Bar for the NNTP Mailbox browser dialog.
Definition: dlg_browser.c:116
struct Buffer LastDir
Browser: previous selected directory.
Definition: dlg_browser.c:130
void mutt_browser_select_dir(const char *f)
Remember the last directory selected.
Definition: dlg_browser.c:1203
struct Buffer LastDirBackup
Browser: backup copy of the current directory.
Definition: dlg_browser.c:132
static const struct Mapping FolderHelp[]
Help Bar for the File/Dir/Mailbox browser dialog.
Definition: dlg_browser.c:104
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:572
void mutt_browser_cleanup(void)
Clean up working Buffers.
Definition: dlg_browser.c:153
void browser_highlight_default(struct BrowserState *state, struct Menu *menu)
Decide which browser item should be highlighted.
Definition: dlg_browser.c:933
int examine_mailboxes(struct Mailbox *m, struct Menu *menu, struct BrowserState *state)
Get list of mailboxes/subscribed newsgroups.
Definition: dlg_browser.c:773
bool link_is_dir(const char *folder, const char *path)
Does this symlink point to a directory?
Definition: dlg_browser.c:166
DIR * mutt_file_opendir(const char *path, enum MuttOpenDirMode mode)
Open a directory.
Definition: file.c:616
@ MUTT_OPENDIR_NONE
Plain opendir()
Definition: file.h:73
void mutt_format_s(char *buf, size_t buflen, const char *prec, const char *s)
Format a simple string.
Definition: format.c:215
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
int km_dokey(enum MenuType mtype, GetChFlags flags)
Determine what a keypress should do.
Definition: get.c:475
void km_error_key(enum MenuType mtype)
Handle an unbound key sequence.
Definition: get.c:305
bool OptNews
(pseudo) used to change reader mode
Definition: globals.c:75
char * CurrentFolder
Currently selected mailbox.
Definition: globals.c:44
int menu_tagging_dispatcher(struct MuttWindow *win, int op)
Perform tagging operations on the Menu - Implements function_dispatcher_t -.
Definition: tagging.c:230
int global_function_dispatcher(struct MuttWindow *win, int op)
Perform a Global function - Implements function_dispatcher_t -.
Definition: global.c:169
int menu_function_dispatcher(struct MuttWindow *win, int op)
Perform a Menu function - Implements function_dispatcher_t -.
Definition: functions.c:317
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:739
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:57
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: dlg_browser.c:205
void dlg_browser(struct Buffer *file, SelectFileFlags flags, struct Mailbox *m, char ***files, int *numfiles)
Let the user select a file -.
Definition: dlg_browser.c:1226
#define mutt_error(...)
Definition: logging2.h:92
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
#define mutt_perror(...)
Definition: logging2.h:93
static void folder_make_entry(struct Menu *menu, char *buf, size_t buflen, int line)
Format a Folder for the Menu - Implements Menu::make_entry() -.
Definition: dlg_browser.c:894
static int select_file_search(struct Menu *menu, regex_t *rx, int line)
Menu search callback for matching files - Implements Menu::search() -.
Definition: dlg_browser.c:878
static int file_tag(struct Menu *menu, int sel, int act)
Tag an entry in the menu - Implements Menu::tag() -.
Definition: dlg_browser.c:1064
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe() -.
Definition: imap.c:2327
static int browser_config_observer(struct NotifyCallback *nc)
Notification that a Config Variable has changed - Implements observer_t -.
Definition: dlg_browser.c:1084
static int browser_mailbox_observer(struct NotifyCallback *nc)
Notification that a Mailbox has changed - Implements observer_t -.
Definition: dlg_browser.c:1124
static int browser_window_observer(struct NotifyCallback *nc)
Notification that a Window has changed - Implements observer_t -.
Definition: dlg_browser.c:1169
void browser_private_data_free(struct BrowserPrivateData **ptr)
Free Private Browser Data - Implements MuttWindow::wdata_free() -.
Definition: private_data.c:37
Convenience wrapper for the gui headers.
void simple_dialog_free(struct MuttWindow **ptr)
Destroy a simple index Dialog.
Definition: simple.c:168
struct MuttWindow * simple_dialog_new(enum MenuType mtype, enum WindowType wtype, const struct Mapping *help_data)
Create a simple index Dialog.
Definition: simple.c:132
int imap_browse(const char *path, struct BrowserState *state)
IMAP hook into the folder browser.
Definition: browse.c:192
IMAP network mailbox.
void imap_clean_path(char *path, size_t plen)
Cleans an IMAP path using imap_fix_path.
Definition: util.c:187
Manage keymappings.
#define GETCH_NO_FLAGS
No flags are set.
Definition: lib.h:52
@ LL_DEBUG5
Log at debug level 5.
Definition: logging2.h:47
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
@ NT_MAILBOX_DELETE
Mailbox is about to be deleted.
Definition: mailbox.h:170
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:210
@ 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:180
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition: menu.c:156
MenuRedrawFlags menu_set_index(struct Menu *menu, int index)
Set the current selection in the Menu.
Definition: menu.c:170
struct tm mutt_date_localtime(time_t t)
Converts calendar time to a broken-down time structure expressed in user timezone.
Definition: date.c:879
size_t mutt_date_localtime_format(char *buf, size_t buflen, const char *format, time_t t)
Format localtime.
Definition: date.c:924
size_t mutt_date_localtime_format_locale(char *buf, size_t buflen, const char *format, time_t t, locale_t loc)
Format localtime using a given locale.
Definition: date.c:942
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:446
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:230
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:191
const char * mutt_path_getcwd(struct Buffer *cwd)
Get the current working directory.
Definition: path.c:498
bool mutt_regex_match(const struct Regex *regex, const char *str)
Shorthand to mutt_regex_capture()
Definition: regex.c:636
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:251
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:798
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:228
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:653
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:327
#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:166
Mailbox helper functions.
void window_redraw(struct MuttWindow *win)
Reflow, recalc and repaint a tree of Windows.
Definition: mutt_window.c:634
struct MuttWindow * window_set_focus(struct MuttWindow *win)
Set the Window focus.
Definition: mutt_window.c:684
struct MuttWindow * window_find_child(struct MuttWindow *win, enum WindowType type)
Recursively find a child Window of a given type.
Definition: mutt_window.c:533
@ WT_DLG_BROWSER
Browser Dialog, dlg_browser()
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:229
void mutt_get_parent_path(const char *path, char *buf, size_t buflen)
Find the parent of a path (or mailbox)
Definition: muttlib.c:1511
void buf_pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using '~' or '='.
Definition: muttlib.c:556
void mutt_str_pretty_size(char *buf, size_t buflen, size_t num)
Display an abbreviated size, like 3.4K.
Definition: muttlib.c:1641
void buf_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:329
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:53
void neomutt_mailboxlist_clear(struct MailboxList *ml)
Free a Mailbox List.
Definition: neomutt.c:162
size_t neomutt_mailboxlist_get_all(struct MailboxList *head, struct NeoMutt *n, enum MailboxType type)
Get a List of all Mailboxes.
Definition: neomutt.c:185
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:57
@ NT_CONFIG
Config has changed, NotifyConfig, EventConfig.
Definition: notify_type.h:43
@ NT_MAILBOX
Mailbox has changed, NotifyMailbox, EventMailbox.
Definition: notify_type.h:49
const char * opcodes_get_name(int op)
Get the name of an opcode.
Definition: opcodes.c:48
Private state data for the Pager.
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
#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:227
Sidebar functions.
#define SORT_MASK
Mask for the sort id.
Definition: sort2.h:74
SortType
Methods for sorting.
Definition: sort2.h:38
@ 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:114
char * folder
Folder name.
Definition: lib.h:117
bool is_mailbox_list
Viewing mailboxes.
Definition: lib.h:118
struct BrowserEntryArray entry
Array of files / dirs / mailboxes.
Definition: lib.h:115
bool imap_browse
IMAP folder.
Definition: lib.h:116
String manipulation buffer.
Definition: buffer.h:34
char * data
Pointer to data.
Definition: buffer.h:35
struct Notify * notify
Notifications: NotifyConfig, EventConfig.
Definition: subset.h:52
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:71
const char * name
Name of config item that changed.
Definition: subset.h:73
An Event that happened to a Mailbox.
Definition: mailbox.h:186
struct Mailbox * mailbox
The Mailbox this Event relates to.
Definition: mailbox.h:187
An Event that happened to a Window.
Definition: mutt_window.h:239
struct MuttWindow * win
Window that changed.
Definition: mutt_window.h:240
WindowNotifyFlags flags
Attributes of Window that changed.
Definition: mutt_window.h:241
Browser entry representing a folder/dir.
Definition: lib.h:78
bool selectable
Folder can be selected.
Definition: lib.h:96
bool imap
This is an IMAP folder.
Definition: lib.h:95
bool has_mailbox
This is a mailbox.
Definition: lib.h:98
char * name
Name of file/dir/mailbox.
Definition: lib.h:86
uid_t uid
File's User ID.
Definition: lib.h:82
bool tagged
Folder is tagged.
Definition: lib.h:102
gid_t gid
File's Group ID.
Definition: lib.h:83
bool has_new_mail
true if mailbox has "new mail"
Definition: lib.h:89
bool poll_new_mail
Check mailbox for new mail.
Definition: lib.h:101
bool notify_user
User will be notified of new mail.
Definition: lib.h:100
nlink_t nlink
Number of hard links.
Definition: lib.h:84
char * desc
Description of mailbox.
Definition: lib.h:87
struct NntpMboxData * nd
Extra NNTP data.
Definition: lib.h:103
off_t size
File size.
Definition: lib.h:80
int gen
Unique id, used for (un)sorting.
Definition: lib.h:105
time_t mtime
Modification time.
Definition: lib.h:81
int msg_count
total number of messages
Definition: lib.h:90
mode_t mode
File permissions.
Definition: lib.h:79
bool inferiors
Folder has children.
Definition: lib.h:97
int msg_unread
number of unread messages
Definition: lib.h:91
A folder/dir in the browser.
Definition: lib.h:69
int num
Number in the index.
Definition: lib.h:71
struct FolderFile * ff
File / Dir / Mailbox.
Definition: lib.h:70
List of Mailboxes.
Definition: mailbox.h:153
struct Mailbox * mailbox
Mailbox in the list.
Definition: mailbox.h:154
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
bool poll_new_mail
Check for new mail.
Definition: mailbox.h:114
void * mdata
Driver specific data.
Definition: mailbox.h:131
char * name
A short name for the Mailbox.
Definition: mailbox.h:82
bool notify_user
Notify the user of new mail.
Definition: mailbox.h:112
bool visible
True if a result of "mailboxes".
Definition: mailbox.h:129
int msg_unread
Number of unread messages.
Definition: mailbox.h:89
int gen
Generation number, for sorting.
Definition: mailbox.h:146
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:96
int num_tagged
Number of tagged entries.
Definition: lib.h:84
void(* mdata_free)(struct Menu *menu, void **ptr)
Definition: lib.h:151
int(* search)(struct Menu *menu, regex_t *rx, int line)
Definition: lib.h:109
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:121
void * mdata
Private data.
Definition: lib.h:137
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:41
struct AccountList accounts
List of all Accounts.
Definition: neomutt.h:46
struct Notify * notify
Notifications handler.
Definition: neomutt.h:42
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
locale_t time_c_locale
Current locale but LC_TIME=C.
Definition: neomutt.h:47
NNTP-specific Account data -.
Definition: adata.h:36
struct Connection * conn
Connection to NNTP Server.
Definition: adata.h:62
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
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:45