| 1 | /* |
|---|
| 2 | * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org> |
|---|
| 3 | * |
|---|
| 4 | * This program is free software; you can redistribute it and/or modify |
|---|
| 5 | * it under the terms of the GNU General Public License as published by |
|---|
| 6 | * the Free Software Foundation; either version 2 of the License, or |
|---|
| 7 | * (at your option) any later version. |
|---|
| 8 | * |
|---|
| 9 | * This program is distributed in the hope that it will be useful, |
|---|
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 12 | * GNU General Public License for more details. |
|---|
| 13 | * |
|---|
| 14 | * You should have received a copy of the GNU General Public License |
|---|
| 15 | * along with this program; if not, write to the Free Software |
|---|
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|---|
| 17 | */ |
|---|
| 18 | |
|---|
| 19 | #if HAVE_CONFIG_H |
|---|
| 20 | # include "config.h" |
|---|
| 21 | #endif |
|---|
| 22 | |
|---|
| 23 | #include "mutt.h" |
|---|
| 24 | #ifdef USE_IMAP |
|---|
| 25 | #include "mailbox.h" |
|---|
| 26 | #include "imap.h" |
|---|
| 27 | #endif |
|---|
| 28 | |
|---|
| 29 | #include <dirent.h> |
|---|
| 30 | #include <string.h> |
|---|
| 31 | #include <sys/types.h> |
|---|
| 32 | #include <sys/stat.h> |
|---|
| 33 | #include <errno.h> |
|---|
| 34 | |
|---|
| 35 | /* given a partial pathname, this routine fills in as much of the rest of the |
|---|
| 36 | * path as is unique. |
|---|
| 37 | * |
|---|
| 38 | * return 0 if ok, -1 if no matches |
|---|
| 39 | */ |
|---|
| 40 | int mutt_complete (char *s, size_t slen) |
|---|
| 41 | { |
|---|
| 42 | char *p; |
|---|
| 43 | DIR *dirp = NULL; |
|---|
| 44 | struct dirent *de; |
|---|
| 45 | int i ,init=0; |
|---|
| 46 | size_t len; |
|---|
| 47 | char dirpart[_POSIX_PATH_MAX], exp_dirpart[_POSIX_PATH_MAX]; |
|---|
| 48 | char filepart[_POSIX_PATH_MAX]; |
|---|
| 49 | #ifdef USE_IMAP |
|---|
| 50 | char imap_path[LONG_STRING]; |
|---|
| 51 | |
|---|
| 52 | dprint (2, (debugfile, "mutt_complete: completing %s\n", s)); |
|---|
| 53 | |
|---|
| 54 | /* we can use '/' as a delimiter, imap_complete rewrites it */ |
|---|
| 55 | if (*s == '=' || *s == '+' || *s == '!') |
|---|
| 56 | { |
|---|
| 57 | if (*s == '!') |
|---|
| 58 | p = NONULL (Spoolfile); |
|---|
| 59 | else |
|---|
| 60 | p = NONULL (Maildir); |
|---|
| 61 | |
|---|
| 62 | mutt_concat_path (imap_path, p, s+1, sizeof (imap_path)); |
|---|
| 63 | } |
|---|
| 64 | else |
|---|
| 65 | strfcpy (imap_path, s, sizeof(imap_path)); |
|---|
| 66 | |
|---|
| 67 | if (mx_is_imap (imap_path)) |
|---|
| 68 | return imap_complete (s, slen, imap_path); |
|---|
| 69 | #endif |
|---|
| 70 | |
|---|
| 71 | if (*s == '=' || *s == '+' || *s == '!') |
|---|
| 72 | { |
|---|
| 73 | dirpart[0] = *s; |
|---|
| 74 | dirpart[1] = 0; |
|---|
| 75 | if (*s == '!') |
|---|
| 76 | strfcpy (exp_dirpart, NONULL (Spoolfile), sizeof (exp_dirpart)); |
|---|
| 77 | else |
|---|
| 78 | strfcpy (exp_dirpart, NONULL (Maildir), sizeof (exp_dirpart)); |
|---|
| 79 | if ((p = strrchr (s, '/'))) |
|---|
| 80 | { |
|---|
| 81 | char buf[_POSIX_PATH_MAX]; |
|---|
| 82 | if (mutt_concatn_path (buf, sizeof(buf), exp_dirpart, strlen(exp_dirpart), s + 1, (size_t)(p - s - 1)) == NULL) { |
|---|
| 83 | return -1; |
|---|
| 84 | } |
|---|
| 85 | strfcpy (exp_dirpart, buf, sizeof (exp_dirpart)); |
|---|
| 86 | mutt_substrcpy(dirpart, s, p+1, sizeof(dirpart)); |
|---|
| 87 | strfcpy (filepart, p + 1, sizeof (filepart)); |
|---|
| 88 | } |
|---|
| 89 | else |
|---|
| 90 | strfcpy (filepart, s + 1, sizeof (filepart)); |
|---|
| 91 | dirp = opendir (exp_dirpart); |
|---|
| 92 | } |
|---|
| 93 | else |
|---|
| 94 | { |
|---|
| 95 | if ((p = strrchr (s, '/'))) |
|---|
| 96 | { |
|---|
| 97 | if (p == s) /* absolute path */ |
|---|
| 98 | { |
|---|
| 99 | p = s + 1; |
|---|
| 100 | strfcpy (dirpart, "/", sizeof (dirpart)); |
|---|
| 101 | exp_dirpart[0] = 0; |
|---|
| 102 | strfcpy (filepart, p, sizeof (filepart)); |
|---|
| 103 | dirp = opendir (dirpart); |
|---|
| 104 | } |
|---|
| 105 | else |
|---|
| 106 | { |
|---|
| 107 | mutt_substrcpy(dirpart, s, p, sizeof(dirpart)); |
|---|
| 108 | strfcpy (filepart, p + 1, sizeof (filepart)); |
|---|
| 109 | strfcpy (exp_dirpart, dirpart, sizeof (exp_dirpart)); |
|---|
| 110 | mutt_expand_path (exp_dirpart, sizeof (exp_dirpart)); |
|---|
| 111 | dirp = opendir (exp_dirpart); |
|---|
| 112 | } |
|---|
| 113 | } |
|---|
| 114 | else |
|---|
| 115 | { |
|---|
| 116 | /* no directory name, so assume current directory. */ |
|---|
| 117 | dirpart[0] = 0; |
|---|
| 118 | strfcpy (filepart, s, sizeof (filepart)); |
|---|
| 119 | dirp = opendir ("."); |
|---|
| 120 | } |
|---|
| 121 | } |
|---|
| 122 | |
|---|
| 123 | if (dirp == NULL) |
|---|
| 124 | { |
|---|
| 125 | dprint (1, (debugfile, "mutt_complete(): %s: %s (errno %d).\n", exp_dirpart, strerror (errno), errno)); |
|---|
| 126 | return (-1); |
|---|
| 127 | } |
|---|
| 128 | |
|---|
| 129 | /* |
|---|
| 130 | * special case to handle when there is no filepart yet. find the first |
|---|
| 131 | * file/directory which is not ``.'' or ``..'' |
|---|
| 132 | */ |
|---|
| 133 | if ((len = mutt_strlen (filepart)) == 0) |
|---|
| 134 | { |
|---|
| 135 | while ((de = readdir (dirp)) != NULL) |
|---|
| 136 | { |
|---|
| 137 | if (mutt_strcmp (".", de->d_name) != 0 && mutt_strcmp ("..", de->d_name) != 0) |
|---|
| 138 | { |
|---|
| 139 | strfcpy (filepart, de->d_name, sizeof (filepart)); |
|---|
| 140 | init++; |
|---|
| 141 | break; |
|---|
| 142 | } |
|---|
| 143 | } |
|---|
| 144 | } |
|---|
| 145 | |
|---|
| 146 | while ((de = readdir (dirp)) != NULL) |
|---|
| 147 | { |
|---|
| 148 | if (mutt_strncmp (de->d_name, filepart, len) == 0) |
|---|
| 149 | { |
|---|
| 150 | if (init) |
|---|
| 151 | { |
|---|
| 152 | for (i=0; filepart[i] && de->d_name[i]; i++) |
|---|
| 153 | { |
|---|
| 154 | if (filepart[i] != de->d_name[i]) |
|---|
| 155 | { |
|---|
| 156 | filepart[i] = 0; |
|---|
| 157 | break; |
|---|
| 158 | } |
|---|
| 159 | } |
|---|
| 160 | filepart[i] = 0; |
|---|
| 161 | } |
|---|
| 162 | else |
|---|
| 163 | { |
|---|
| 164 | char buf[_POSIX_PATH_MAX]; |
|---|
| 165 | struct stat st; |
|---|
| 166 | |
|---|
| 167 | strfcpy (filepart, de->d_name, sizeof(filepart)); |
|---|
| 168 | |
|---|
| 169 | /* check to see if it is a directory */ |
|---|
| 170 | if (dirpart[0]) |
|---|
| 171 | { |
|---|
| 172 | strfcpy (buf, exp_dirpart, sizeof (buf)); |
|---|
| 173 | strfcpy (buf + strlen (buf), "/", sizeof (buf) - strlen (buf)); |
|---|
| 174 | } |
|---|
| 175 | else |
|---|
| 176 | buf[0] = 0; |
|---|
| 177 | strfcpy (buf + strlen (buf), filepart, sizeof (buf) - strlen (buf)); |
|---|
| 178 | if (stat (buf, &st) != -1 && (st.st_mode & S_IFDIR)) |
|---|
| 179 | strfcpy (filepart + strlen (filepart), "/", |
|---|
| 180 | sizeof (filepart) - strlen (filepart)); |
|---|
| 181 | init = 1; |
|---|
| 182 | } |
|---|
| 183 | } |
|---|
| 184 | } |
|---|
| 185 | closedir (dirp); |
|---|
| 186 | |
|---|
| 187 | if (dirpart[0]) |
|---|
| 188 | { |
|---|
| 189 | strfcpy (s, dirpart, slen); |
|---|
| 190 | if (mutt_strcmp ("/", dirpart) != 0 && dirpart[0] != '=' && dirpart[0] != '+') |
|---|
| 191 | strfcpy (s + strlen (s), "/", slen - strlen (s)); |
|---|
| 192 | strfcpy (s + strlen (s), filepart, slen - strlen (s)); |
|---|
| 193 | } |
|---|
| 194 | else |
|---|
| 195 | strfcpy (s, filepart, slen); |
|---|
| 196 | |
|---|
| 197 | return (init ? 0 : -1); |
|---|
| 198 | } |
|---|