X-Git-Url: http://git.madism.org/?a=blobdiff_plain;f=lib-ui%2Fbrowser.c;fp=lib-ui%2Fbrowser.c;h=466cf77715b59ad44f7d5cd7afcfdbcb47602c14;hb=c81a65db2499a363af5af28610db5f7e69e15839;hp=0000000000000000000000000000000000000000;hpb=9438b6c87f1552be4389afe4abf7bdc3b30ad203;p=apps%2Fmadmutt.git diff --git a/lib-ui/browser.c b/lib-ui/browser.c new file mode 100644 index 0000000..466cf77 --- /dev/null +++ b/lib-ui/browser.c @@ -0,0 +1,1073 @@ +/* + * Copyright notice from original mutt: + * Copyright (C) 1996-2000 Michael R. Elkins + * + * This file is part of mutt-ng, see http://www.muttng.org/. + * It's licensed under the GNU General Public License, + * please see the file GPL in the top level source directory. + */ + +#include + +#include +#include +#include + +#include +#include "menu.h" +#include "browser.h" + +#include "mutt.h" +#include "buffy.h" +#include "sort.h" +#include "attach.h" + +#include + +typedef struct folder_t { + struct folder_file *ff; + int num; +} FOLDER; + +static char LastDir[_POSIX_PATH_MAX] = ""; +static char LastDirBackup[_POSIX_PATH_MAX] = ""; + +/* Frees up the memory allocated for the local-global variables. */ +static void destroy_state (struct browser_state *state) +{ + int c; + + for (c = 0; c < state->entrylen; c++) { + p_delete(&state->entry[c].name); + p_delete(&state->entry[c].desc); + p_delete(&state->entry[c].st); + } + p_delete(&state->folder); + p_delete(&state->entry); +} + +static int browser_compare_subject (const void *a, const void *b) +{ + struct folder_file *pa = (struct folder_file *) a; + struct folder_file *pb = (struct folder_file *) b; + + int r = strcoll(NONULL(pa->name), NONULL(pb->name)); + + return ((BrowserSort & SORT_REVERSE) ? -r : r); +} + +static int browser_compare_date (const void *a, const void *b) +{ + struct folder_file *pa = (struct folder_file *) a; + struct folder_file *pb = (struct folder_file *) b; + + int r = pa->mtime - pb->mtime; + + return ((BrowserSort & SORT_REVERSE) ? -r : r); +} + +static int browser_compare_size (const void *a, const void *b) +{ + struct folder_file *pa = (struct folder_file *) a; + struct folder_file *pb = (struct folder_file *) b; + + int r = pa->size - pb->size; + + return ((BrowserSort & SORT_REVERSE) ? -r : r); +} + +static void browser_sort (struct browser_state *state) +{ + int (*f) (const void *, const void *); + + switch (BrowserSort & SORT_MASK) { + case SORT_ORDER: + return; + case SORT_DATE: + f = browser_compare_date; + break; + case SORT_SIZE: + f = browser_compare_size; + break; + case SORT_SUBJECT: + default: + f = browser_compare_subject; + break; + } + qsort (state->entry, state->entrylen, sizeof (struct folder_file), f); +} + +static int link_is_dir (const char *folder, const char *path) +{ + struct stat st; + char fullpath[_POSIX_PATH_MAX]; + + mutt_concat_path(fullpath, sizeof(fullpath), folder, path); + + if (stat (fullpath, &st) == 0) + return (S_ISDIR (st.st_mode)); + else + return 0; +} + +static const char * +folder_format_str(char *dest, ssize_t destlen, char op, + const char *src, const char *fmt, + const char *ifstr, const char *elstr, + anytype data, format_flag flags) +{ + char fn[STRING], tmp[STRING], permission[11], date[16]; + const char *t_fmt; + time_t tnow; + FOLDER *folder = data.ptr; + struct passwd *pw; + struct group *gr; + int optional = (flags & M_FORMAT_OPTIONAL); + + switch (op) { + case 'C': + snprintf (tmp, sizeof (tmp), "%%%sd", fmt); + snprintf (dest, destlen, tmp, folder->num + 1); + break; + + case 'd': + if (folder->ff->st != NULL) { + tnow = time (NULL); + t_fmt = + tnow - folder->ff->st->st_mtime < + 31536000 ? "%b %d %H:%M" : "%b %d %Y"; + strftime (date, sizeof (date), t_fmt, + localtime (&folder->ff->st->st_mtime)); + mutt_format_s (dest, destlen, fmt, date); + } + else + mutt_format_s (dest, destlen, fmt, ""); + break; + + case 'f': + { + const char *s; + + if (folder->ff->imap) + s = NONULL(folder->ff->desc); + else + s = NONULL(folder->ff->name); + + snprintf (fn, sizeof (fn), "%s%s", s, + folder->ff->st ? (S_ISLNK (folder->ff->st->st_mode) ? "@" : + (S_ISDIR (folder->ff->st->st_mode) ? "/" : + ((folder->ff->st->st_mode & S_IXUSR) != + 0 ? "*" : ""))) : ""); + + mutt_format_s (dest, destlen, fmt, fn); + break; + } + case 'F': + if (folder->ff->st != NULL) { + snprintf (permission, sizeof (permission), "%c%c%c%c%c%c%c%c%c%c", + S_ISDIR(folder->ff->st-> st_mode) + ? 'd' : (S_ISLNK(folder->ff->st-> st_mode) ? 'l' : '-'), + (folder->ff->st->st_mode & S_IRUSR) != 0 ? 'r' : '-', + (folder->ff->st->st_mode & S_IWUSR) != 0 ? 'w' : '-', + (folder->ff->st->st_mode & S_ISUID) != + 0 ? 's' : (folder->ff->st->st_mode & S_IXUSR) != + 0 ? 'x' : '-', + (folder->ff->st->st_mode & S_IRGRP) != 0 ? 'r' : '-', + (folder->ff->st->st_mode & S_IWGRP) != 0 ? 'w' : '-', + (folder->ff->st->st_mode & S_ISGID) != + 0 ? 's' : (folder->ff->st->st_mode & S_IXGRP) != + 0 ? 'x' : '-', + (folder->ff->st->st_mode & S_IROTH) != 0 ? 'r' : '-', + (folder->ff->st->st_mode & S_IWOTH) != 0 ? 'w' : '-', + (folder->ff->st->st_mode & S_ISVTX) != + 0 ? 't' : (folder->ff->st->st_mode & S_IXOTH) != + 0 ? 'x' : '-'); + mutt_format_s (dest, destlen, fmt, permission); + } + else if (folder->ff->imap) { + /* mark folders with subfolders AND mail */ + snprintf (permission, sizeof (permission), "IMAP %c", + (folder->ff->inferiors + && folder->ff->selectable) ? '+' : ' '); + mutt_format_s (dest, destlen, fmt, permission); + } + else + mutt_format_s (dest, destlen, fmt, ""); + break; + + case 'g': + if (folder->ff->st != NULL) { + if ((gr = getgrgid (folder->ff->st->st_gid))) + mutt_format_s (dest, destlen, fmt, gr->gr_name); + else { + snprintf (tmp, sizeof (tmp), "%%%sld", fmt); + snprintf (dest, destlen, tmp, folder->ff->st->st_gid); + } + } + else + mutt_format_s (dest, destlen, fmt, ""); + break; + + case 'l': + if (folder->ff->st != NULL) { + snprintf (tmp, sizeof (tmp), "%%%sd", fmt); + snprintf (dest, destlen, tmp, folder->ff->st->st_nlink); + } + else + mutt_format_s (dest, destlen, fmt, ""); + break; + + case 'N': + if (imap_is_magic (folder->ff->desc, NULL) == M_IMAP) { + if (!optional) { + snprintf (tmp, sizeof (tmp), "%%%sd", fmt); + snprintf (dest, destlen, tmp, folder->ff->new); + } + else if (!folder->ff->new) + optional = 0; + break; + } + snprintf (tmp, sizeof (tmp), "%%%sc", fmt); + snprintf (dest, destlen, tmp, folder->ff->new ? 'N' : ' '); + break; + + case 's': + if (folder->ff->st != NULL) { + snprintf (tmp, sizeof (tmp), "%%%sld", fmt); + snprintf (dest, destlen, tmp, (long) folder->ff->st->st_size); + } + else + mutt_format_s (dest, destlen, fmt, ""); + break; + + case 't': + snprintf (tmp, sizeof (tmp), "%%%sc", fmt); + snprintf (dest, destlen, tmp, folder->ff->tagged ? '*' : ' '); + break; + + case 'u': + if (folder->ff->st != NULL) { + if ((pw = getpwuid (folder->ff->st->st_uid))) + mutt_format_s (dest, destlen, fmt, pw->pw_name); + else { + snprintf (tmp, sizeof (tmp), "%%%sld", fmt); + snprintf (dest, destlen, tmp, folder->ff->st->st_uid); + } + } + else + mutt_format_s (dest, destlen, fmt, ""); + break; + + default: + snprintf (tmp, sizeof (tmp), "%%%sc", fmt); + snprintf (dest, destlen, tmp, op); + break; + } + + + if (flags & M_FORMAT_OPTIONAL) + m_strformat(dest, destlen, 0, optional ? ifstr : elstr, + folder_format_str, data, 0); + + return src; +} + + +static void add_folder (MUTTMENU * m, struct browser_state *state, + const char *name, const struct stat *s, int new) +{ + if (state->entrylen == state->entrymax) { + /* need to allocate more space */ + p_realloc(&state->entry, state->entrymax += 256); + p_clear(&state->entry[state->entrylen], 256); + if (m) + m->data = state->entry; + } + + if (s != NULL) { + (state->entry)[state->entrylen].mode = s->st_mode; + (state->entry)[state->entrylen].mtime = s->st_mtime; + (state->entry)[state->entrylen].size = s->st_size; + (state->entry)[state->entrylen].st = p_dup(s, 1); + } + + (state->entry)[state->entrylen].new = new; + (state->entry)[state->entrylen].name = m_strdup(name); + (state->entry)[state->entrylen].desc = m_strdup(name); + (state->entry)[state->entrylen].imap = 0; + (state->entrylen)++; +} + +static void init_state (struct browser_state *state, MUTTMENU * menu) +{ + state->entrylen = 0; + state->entrymax = 256; + state->entry = p_new(struct folder_file, state->entrymax); + state->imap_browse = 0; + if (menu) + menu->data = state->entry; +} + +/* get list of all files/newsgroups with mask */ +static int examine_directory (MUTTMENU * menu, struct browser_state *state, + char *d, const char *prefix) +{ + + struct stat s; + DIR *dp; + struct dirent *de; + char buffer[_POSIX_PATH_MAX + STRING]; + int i = -1; + + while (stat (d, &s) == -1) { + if (errno == ENOENT) { + /* The last used directory is deleted, try to use the parent dir. */ + char *c = strrchr (d, '/'); + + if (c && (c > d)) { + *c = 0; + continue; + } + } + mutt_perror (d); + return (-1); + } + + if (!S_ISDIR (s.st_mode)) { + mutt_error (_("%s is not a directory."), d); + return (-1); + } + + buffy_check (0); + + if ((dp = opendir (d)) == NULL) { + mutt_perror (d); + return (-1); + } + + init_state (state, menu); + + while ((de = readdir (dp)) != NULL) { + if (m_strcmp(de->d_name, ".") == 0) + continue; /* we don't need . */ + + if (m_strncmp(prefix, de->d_name, m_strlen(prefix)) != 0) + continue; + if (!((regexec (Mask.rx, de->d_name, 0, NULL, 0) == 0) ^ Mask.neg)) + continue; + + mutt_concat_path(buffer, sizeof(buffer), d, de->d_name); + if (lstat (buffer, &s) == -1) + continue; + + if ((!S_ISREG (s.st_mode)) && (!S_ISDIR (s.st_mode)) && + (!S_ISLNK (s.st_mode))) + continue; + + i = buffy_lookup (buffer); + add_folder (menu, state, de->d_name, &s, i >= 0 ? Incoming.arr[i]->new : 0); + } + closedir (dp); + sidebar_draw (); + browser_sort (state); + return 0; +} + +/* get list of mailboxes/subscribed newsgroups */ +static int examine_mailboxes (MUTTMENU * menu, struct browser_state *state) +{ + struct stat s; + char buffer[LONG_STRING]; + int i = 0; + BUFFY* tmp; + + if (!Incoming.len) + return (-1); + buffy_check (0); + + init_state (state, menu); + + for (i = 0; i < Incoming.len; i++) { + tmp = Incoming.arr[i]; + tmp->magic = mx_get_magic (tmp->path); + if (tmp->magic == M_IMAP) { + add_folder (menu, state, tmp->path, NULL, tmp->new); + continue; + } + if (tmp->magic == M_POP) { + add_folder (menu, state, tmp->path, NULL, tmp->new); + continue; + } + if (lstat (tmp->path, &s) == -1) + continue; + + if ((!S_ISREG (s.st_mode)) && (!S_ISDIR (s.st_mode)) && + (!S_ISLNK (s.st_mode))) + continue; + + m_strcpy(buffer, sizeof(buffer), NONULL(tmp->path)); + mutt_pretty_mailbox (buffer); + add_folder (menu, state, buffer, &s, tmp->new); + } + + browser_sort (state); + return 0; +} + +static int select_file_search (MUTTMENU * menu, regex_t * re, int n) +{ + return (regexec + (re, ((struct folder_file *) menu->data)[n].name, 0, NULL, 0)); +} + +static void folder_entry (char *s, ssize_t slen, MUTTMENU * menu, int num) +{ + FOLDER folder; + + folder.ff = &((struct folder_file *) menu->data)[num]; + folder.num = num; + + m_strformat(s, slen, getmaxx(main_w), FolderFormat, folder_format_str, + &folder, 0); +} + +static void init_menu (struct browser_state *state, MUTTMENU * menu, + char *title, ssize_t titlelen, int buffy) +{ + char path[_POSIX_PATH_MAX]; + + menu->max = state->entrylen; + + if (menu->current >= menu->max) + menu->current = menu->max - 1; + if (menu->current < 0) + menu->current = 0; + if (menu->top > menu->current) + menu->top = 0; + + menu->tagged = 0; + + if (buffy) + snprintf(title, titlelen, _("Mailboxes [%d]"), buffy_check(0)); + else { + m_strcpy(path, sizeof(path), LastDir); + mutt_pretty_mailbox (path); + if (state->imap_browse && option (OPTIMAPLSUB)) + snprintf (title, titlelen, _("Subscribed [%s], File mask: %s"), + path, NONULL (Mask.pattern)); + else + snprintf (title, titlelen, _("Directory [%s], File mask: %s"), + path, NONULL (Mask.pattern)); + } + menu->redraw = REDRAW_FULL; +} + +static int file_tag (MUTTMENU * menu, int n, int m) +{ + struct folder_file *ff = &(((struct folder_file *) menu->data)[n]); + int ot; + + if (S_ISDIR (ff->mode) + || (S_ISLNK (ff->mode) && link_is_dir (LastDir, ff->name))) { + mutt_error _("Can't attach a directory!"); + + return 0; + } + + ot = ff->tagged; + ff->tagged = (m >= 0 ? m : !ff->tagged); + + return ff->tagged - ot; +} + +void mutt_select_file (char *f, ssize_t flen, int flags, char ***files, + int *numfiles) +{ + char buf[_POSIX_PATH_MAX]; + char prefix[_POSIX_PATH_MAX] = ""; + char title[STRING]; + struct browser_state state; + MUTTMENU *menu; + struct stat st; + int i, killPrefix = 0; + int multiple = (flags & M_SEL_MULTI) ? 1 : 0; + int folder = (flags & M_SEL_FOLDER) ? 1 : 0; + int buffy = (flags & M_SEL_BUFFY) ? 1 : 0; + + buffy = buffy && folder; + + p_clear(&state, 1); + + if (!folder) + m_strcpy(LastDirBackup, sizeof(LastDirBackup), LastDir); + + if (*f) { + mutt_expand_path (f, flen); + if (imap_is_magic (f, NULL) == M_IMAP) { + init_state (&state, NULL); + state.imap_browse = 1; + if (!imap_browse (f, &state)) + m_strcpy(LastDir, sizeof(LastDir), state.folder); + } + else { + for (i = m_strlen(f) - 1; i > 0 && f[i] != '/'; i--); + if (i > 0) { + if (f[0] == '/') { + i = MIN(ssizeof(LastDir) - 1, i); + m_strcpy(LastDir, sizeof(LastDir), f); + } + else { + getcwd(LastDir, sizeof(LastDir)); + m_strcat(LastDir, sizeof(LastDir), "/"); + m_strncat(LastDir, sizeof(LastDir), f, i); + } + } + else { + if (f[0] == '/') + m_strcpy(LastDir, sizeof(LastDir), "/"); + else + getcwd (LastDir, sizeof (LastDir)); + } + + if (i <= 0 && f[0] != '/') + m_strcpy(prefix, sizeof(prefix), f); + else + m_strcpy(prefix, sizeof(prefix), f + i + 1); + killPrefix = 1; + } + } + else { + if (!folder) + getcwd (LastDir, sizeof (LastDir)); + else if (!LastDir[0]) + m_strcpy(LastDir, sizeof(LastDir), NONULL(Maildir)); + + if (!buffy && imap_is_magic (LastDir, NULL) == M_IMAP) { + init_state (&state, NULL); + state.imap_browse = 1; + imap_browse (LastDir, &state); + browser_sort (&state); + } + } + + *f = 0; + + if (buffy) { + if (examine_mailboxes (NULL, &state) == -1) + goto bail; + } + else + if (!state.imap_browse) + if (examine_directory (NULL, &state, LastDir, prefix) == -1) + goto bail; + + menu = mutt_new_menu (); + menu->menu = MENU_FOLDER; + menu->make_entry = folder_entry; + menu->search = select_file_search; + menu->title = title; + menu->data = state.entry; + if (multiple) + menu->tag = file_tag; + init_menu (&state, menu, title, sizeof (title), buffy); + + for (;;) { + switch (i = mutt_menuLoop (menu)) { + case OP_GENERIC_SELECT_ENTRY: + + if (!state.entrylen) { + mutt_error _("No files match the file mask"); + + break; + } + + if (S_ISDIR (state.entry[menu->current].mode) || + (S_ISLNK (state.entry[menu->current].mode) && + link_is_dir (LastDir, state.entry[menu->current].name)) + || state.entry[menu->current].inferiors + ) { + /* make sure this isn't a MH or maildir mailbox */ + if (buffy) { + m_strcpy(buf, sizeof(buf), state.entry[menu->current].name); + mutt_expand_path (buf, sizeof (buf)); + } + else if (state.imap_browse) { + m_strcpy(buf, sizeof(buf), state.entry[menu->current].name); + } + else + mutt_concat_path(buf, sizeof(buf), LastDir, + state.entry[menu->current].name); + + if ((mx_get_magic (buf) <= 0) + || state.entry[menu->current].inferiors) + { + char OldLastDir[_POSIX_PATH_MAX]; + + /* save the old directory */ + m_strcpy(OldLastDir, sizeof(OldLastDir), LastDir); + + if (m_strcmp(state.entry[menu->current].name, "..") == 0) { + if (m_strcmp("..", LastDir + m_strlen(LastDir) - 2) == 0) + m_strcat(LastDir, sizeof(LastDir), "/.."); + else { + char *p = strrchr (LastDir + 1, '/'); + + if (p) + *p = 0; + else { + if (LastDir[0] == '/') + LastDir[1] = 0; + else + m_strcat(LastDir, sizeof(LastDir), "/.."); + } + } + } + else if (buffy) { + m_strcpy(LastDir, sizeof(LastDir), + state.entry[menu->current].name); + mutt_expand_path (LastDir, sizeof (LastDir)); + } + else if (state.imap_browse) { + int n; + ciss_url_t url; + + m_strcpy(LastDir, sizeof(LastDir), + state.entry[menu->current].name); + /* tack on delimiter here */ + n = m_strlen(LastDir) + 1; + + /* special case "" needs no delimiter */ + url_parse_ciss (&url, state.entry[menu->current].name); + if (url.path && + (state.entry[menu->current].delim != '\0') && + (n < ssizeof (LastDir))) { + LastDir[n] = '\0'; + LastDir[n - 1] = state.entry[menu->current].delim; + } + } + else { + char tmp[_POSIX_PATH_MAX]; + + mutt_concat_path(tmp, sizeof(tmp), LastDir, + state.entry[menu->current].name); + m_strcpy(LastDir, sizeof(LastDir), tmp); + } + + destroy_state (&state); + if (killPrefix) { + prefix[0] = 0; + killPrefix = 0; + } + buffy = 0; + if (state.imap_browse) { + init_state (&state, NULL); + state.imap_browse = 1; + imap_browse (LastDir, &state); + browser_sort (&state); + menu->data = state.entry; + } + else + if (examine_directory (menu, &state, LastDir, prefix) == -1) { + /* try to restore the old values */ + m_strcpy(LastDir, sizeof(LastDir), OldLastDir); + if (examine_directory (menu, &state, LastDir, prefix) == -1) { + m_strcpy(LastDir, sizeof(LastDir), NONULL(mod_core.homedir)); + goto bail; + } + } + menu->current = 0; + menu->top = 0; + init_menu (&state, menu, title, sizeof (title), buffy); + break; + } + } + + if (buffy) { + m_strcpy(f, flen, state.entry[menu->current].name); + mutt_expand_path (f, flen); + } + else if (state.imap_browse) + m_strcpy(f, flen, state.entry[menu->current].name); + else + mutt_concat_path(f, flen, LastDir, state.entry[menu->current].name); + + /* Fall through to OP_EXIT */ + + case OP_EXIT: + + if (multiple) { + char **tfiles; + int j; + int h; + + if (menu->tagged) { + *numfiles = menu->tagged; + tfiles = p_new(char *, *numfiles); + for (h = 0, j = 0; h < state.entrylen; i++) { + struct folder_file ff = state.entry[i]; + char full[_POSIX_PATH_MAX]; + + if (ff.tagged) { + mutt_concat_path(full, sizeof(full), LastDir, ff.name); + mutt_expand_path (full, sizeof (full)); + tfiles[j++] = m_strdup(full); + } + } + *files = tfiles; + } + else if (f[0]) { /* no tagged entries. return selected entry */ + *numfiles = 1; + tfiles = p_new(char *, *numfiles); + mutt_expand_path (f, flen); + tfiles[0] = m_strdup(f); + *files = tfiles; + } + } + + destroy_state (&state); + mutt_menuDestroy (&menu); + goto bail; + + case OP_BROWSER_TELL: + if (state.entrylen) + mutt_message ("%s", state.entry[menu->current].name); + break; + + case OP_BROWSER_TOGGLE_LSUB: + if (option (OPTIMAPLSUB)) { + unset_option (OPTIMAPLSUB); + } + else { + set_option (OPTIMAPLSUB); + } + mutt_ungetch (0, OP_CHECK_NEW); + break; + + case OP_CREATE_MAILBOX: + if (!state.imap_browse) + mutt_error (_("Create is only supported for IMAP mailboxes")); + else { + imap_mailbox_create (LastDir); + /* TODO: find a way to detect if the new folder would appear in + * this window, and insert it without starting over. */ + destroy_state (&state); + init_state (&state, NULL); + state.imap_browse = 1; + imap_browse (LastDir, &state); + browser_sort (&state); + menu->data = state.entry; + menu->current = 0; + menu->top = 0; + init_menu (&state, menu, title, sizeof (title), buffy); + MAYBE_REDRAW (menu->redraw); + } + break; + + case OP_RENAME_MAILBOX: + if (!state.entry[menu->current].imap) + mutt_error (_("Rename is only supported for IMAP mailboxes")); + else { + int nentry = menu->current; + + if (imap_mailbox_rename (state.entry[nentry].name) >= 0) { + destroy_state (&state); + init_state (&state, NULL); + state.imap_browse = 1; + imap_browse (LastDir, &state); + browser_sort (&state); + menu->data = state.entry; + menu->current = 0; + menu->top = 0; + init_menu (&state, menu, title, sizeof (title), buffy); + MAYBE_REDRAW (menu->redraw); + } + } + break; + + case OP_DELETE_MAILBOX: + if (!state.entry[menu->current].imap) + mutt_error (_("Delete is only supported for IMAP mailboxes")); + else { + char msg[STRING]; + IMAP_MBOX mx; + int nentry = menu->current; + + imap_parse_path (state.entry[nentry].name, &mx); + snprintf (msg, sizeof (msg), _("Really delete mailbox \"%s\"?"), + mx.mbox); + if (mutt_yesorno (msg, M_NO) == M_YES) { + if (!imap_delete_mailbox (Context, mx)) { + /* free the mailbox from the browser */ + p_delete(&((state.entry)[nentry].name)); + p_delete(&((state.entry)[nentry].desc)); + /* and move all other entries up */ + if (nentry + 1 < state.entrylen) + memmove (state.entry + nentry, state.entry + nentry + 1, + sizeof (struct folder_file) * (state.entrylen - + (nentry + 1))); + state.entrylen--; + mutt_message _("Mailbox deleted."); + + init_menu (&state, menu, title, sizeof (title), buffy); + MAYBE_REDRAW (menu->redraw); + } + } + else + mutt_message _("Mailbox not deleted."); + p_delete(&mx.mbox); + } + break; + + case OP_CHANGE_DIRECTORY: + m_strcpy(buf, sizeof(buf), LastDir); + if (!state.imap_browse) + { + /* add '/' at the end of the directory name if not already there */ + ssize_t len = m_strlen(LastDir); + + if (len && LastDir[len - 1] != '/' && ssizeof(buf) > len) + buf[len] = '/'; + } + + if (mutt_get_field (_("Chdir to: "), buf, sizeof (buf), M_FILE) == 0 && + buf[0]) { + buffy = 0; + mutt_expand_path (buf, sizeof (buf)); + if (imap_is_magic (buf, NULL) == M_IMAP) { + m_strcpy(LastDir, sizeof(LastDir), buf); + destroy_state (&state); + init_state (&state, NULL); + state.imap_browse = 1; + imap_browse (LastDir, &state); + browser_sort (&state); + menu->data = state.entry; + menu->current = 0; + menu->top = 0; + init_menu (&state, menu, title, sizeof (title), buffy); + } + else + if (stat (buf, &st) == 0) { + if (S_ISDIR (st.st_mode)) { + destroy_state (&state); + if (examine_directory (menu, &state, buf, prefix) == 0) + m_strcpy(LastDir, sizeof(LastDir), buf); + else { + mutt_error _("Error scanning directory."); + + if (examine_directory (menu, &state, LastDir, prefix) == -1) { + mutt_menuDestroy (&menu); + goto bail; + } + } + menu->current = 0; + menu->top = 0; + init_menu (&state, menu, title, sizeof (title), buffy); + } + else + mutt_error (_("%s is not a directory."), buf); + } + else + mutt_perror (buf); + } + MAYBE_REDRAW (menu->redraw); + break; + + case OP_ENTER_MASK: + + m_strcpy(buf, sizeof(buf), NONULL(Mask.pattern)); + if (mutt_get_field (_("File Mask: "), buf, sizeof (buf), 0) == 0) { + regex_t *rx = p_new(regex_t, 1); + char *s = buf; + int neg = 0, err; + + buffy = 0; + /* assume that the user wants to see everything */ + if (!buf[0]) + m_strcpy(buf, sizeof(buf), "."); + s = vskipspaces(s); + if (*s == '!') { + s = vskipspaces(s + 1); + neg = 1; + } + + if ((err = REGCOMP (rx, s, REG_NOSUB)) != 0) { + regerror (err, rx, buf, sizeof (buf)); + regfree (rx); + p_delete(&rx); + mutt_error ("%s", buf); + } + else { + m_strreplace(&Mask.pattern, buf); + regfree (Mask.rx); + p_delete(&Mask.rx); + Mask.rx = rx; + Mask.neg = neg; + + destroy_state (&state); + if (state.imap_browse) { + init_state (&state, NULL); + state.imap_browse = 1; + imap_browse (LastDir, &state); + browser_sort (&state); + menu->data = state.entry; + init_menu (&state, menu, title, sizeof (title), buffy); + } + else + if (examine_directory (menu, &state, LastDir, NULL) == 0) + init_menu (&state, menu, title, sizeof (title), buffy); + else { + mutt_error _("Error scanning directory."); + + mutt_menuDestroy (&menu); + goto bail; + } + killPrefix = 0; + if (!state.entrylen) { + mutt_error _("No files match the file mask"); + + break; + } + } + } + MAYBE_REDRAW (menu->redraw); + break; + + case OP_SORT: + case OP_SORT_REVERSE: + + { + int resort = 1; + int reverse = (i == OP_SORT_REVERSE); + + switch (mutt_multi_choice ((reverse) ? + _ + ("Reverse sort by (d)ate, (a)lpha, si(z)e or do(n)'t sort? ") + : + _ + ("Sort by (d)ate, (a)lpha, si(z)e or do(n)'t sort? "), + _("dazn"))) { + case -1: /* abort */ + resort = 0; + break; + + case 1: /* (d)ate */ + BrowserSort = SORT_DATE; + break; + + case 2: /* (a)lpha */ + BrowserSort = SORT_SUBJECT; + break; + + case 3: /* si(z)e */ + BrowserSort = SORT_SIZE; + break; + + case 4: /* do(n)'t sort */ + BrowserSort = SORT_ORDER; + resort = 0; + break; + } + if (resort) { + BrowserSort |= reverse ? SORT_REVERSE : 0; + browser_sort (&state); + menu->redraw = REDRAW_FULL; + } + break; + } + + case OP_TOGGLE_MAILBOXES: + buffy = 1 - buffy; + + case OP_CHECK_NEW: + destroy_state (&state); + prefix[0] = 0; + killPrefix = 0; + + if (buffy) { + if (examine_mailboxes (menu, &state) == -1) + goto bail; + } + else if (imap_is_magic (LastDir, NULL) == M_IMAP) { + init_state (&state, NULL); + state.imap_browse = 1; + imap_browse (LastDir, &state); + browser_sort (&state); + menu->data = state.entry; + } + else if (examine_directory (menu, &state, LastDir, prefix) == -1) + goto bail; + init_menu (&state, menu, title, sizeof (title), buffy); + break; + + case OP_BUFFY_LIST: + if (option (OPTFORCEBUFFYCHECK)) + buffy_check (1); + buffy_list (); + break; + + case OP_BROWSER_NEW_FILE: + + snprintf (buf, sizeof (buf), "%s/", LastDir); + if (mutt_get_field (_("New file name: "), buf, sizeof (buf), M_FILE) == + 0) { + m_strcpy(f, flen, buf); + destroy_state (&state); + mutt_menuDestroy (&menu); + goto bail; + } + MAYBE_REDRAW (menu->redraw); + break; + + case OP_BROWSER_VIEW_FILE: + if (!state.entrylen) { + mutt_error _("No files match the file mask"); + + break; + } + + if (state.entry[menu->current].selectable) { + m_strcpy(f, flen, state.entry[menu->current].name); + destroy_state (&state); + mutt_menuDestroy (&menu); + goto bail; + } + else + if (S_ISDIR (state.entry[menu->current].mode) || + (S_ISLNK (state.entry[menu->current].mode) && + link_is_dir (LastDir, state.entry[menu->current].name))) { + mutt_error _("Can't view a directory"); + + break; + } + else { + BODY *b; + char nbuf[_POSIX_PATH_MAX]; + + mutt_concat_path(nbuf, sizeof(nbuf), LastDir, + state.entry[menu->current].name); + b = mutt_make_file_attach (nbuf); + if (b != NULL) { + mutt_view_attachment (NULL, b, M_REGULAR, NULL, NULL, 0); + body_list_wipe(&b); + menu->redraw = REDRAW_FULL; + } + else + mutt_error _("Error trying to view file"); + } + break; + + case OP_BROWSER_SUBSCRIBE: + case OP_BROWSER_UNSUBSCRIBE: + if (i == OP_BROWSER_SUBSCRIBE) + imap_subscribe (state.entry[menu->current].name, 1); + else + imap_subscribe (state.entry[menu->current].name, 0); + } + } + +bail: + + if (!folder) + m_strcpy(LastDir, sizeof(LastDir), LastDirBackup); + +}