NeoMutt  2024-12-12-14-g7b49f7
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
complete.c
Go to the documentation of this file.
1
31#include "config.h"
32#include <dirent.h>
33#include <errno.h>
34#include <string.h>
35#include <sys/stat.h>
36#include "mutt/lib.h"
37#include "config/lib.h"
38#include "core/lib.h"
39#include "lib.h"
40#include "imap/lib.h"
41#include "nntp/lib.h"
42#include "globals.h"
43#include "muttlib.h"
44
45struct CompletionData;
46
57int mutt_complete(struct CompletionData *cd, struct Buffer *buf)
58{
59 const char *p = NULL;
60 DIR *dir = NULL;
61 struct dirent *de = NULL;
62 int init = 0;
63 size_t len;
64 struct Buffer *dirpart = NULL;
65 struct Buffer *exp_dirpart = NULL;
66 struct Buffer *filepart = NULL;
67 struct Buffer *tmp = NULL;
68 struct Buffer *imap_path = NULL;
69 int rc;
70
71 mutt_debug(LL_DEBUG2, "completing %s\n", buf_string(buf));
72
73 if (OptNews)
74 return nntp_complete(buf);
75
76 const char *const c_spool_file = cs_subset_string(NeoMutt->sub, "spool_file");
77 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
78
79 imap_path = buf_pool_get();
80 /* we can use '/' as a delimiter, imap_complete rewrites it */
81 char ch = buf_at(buf, 0);
82 if ((ch == '=') || (ch == '+') || (ch == '!'))
83 {
84 if (ch == '!')
85 p = NONULL(c_spool_file);
86 else
87 p = NONULL(c_folder);
88
89 buf_concat_path(imap_path, p, buf_string(buf) + 1);
90 }
91 else
92 {
93 buf_copy(imap_path, buf);
94 }
95
96 if (imap_path_probe(buf_string(imap_path), NULL) == MUTT_IMAP)
97 {
98 rc = imap_complete(buf, buf_string(imap_path));
99 buf_pool_release(&imap_path);
100 return rc;
101 }
102
103 buf_pool_release(&imap_path);
104
105 dirpart = buf_pool_get();
106 exp_dirpart = buf_pool_get();
107 filepart = buf_pool_get();
108 tmp = buf_pool_get();
109
110 ch = buf_at(buf, 0);
111 if ((ch == '=') || (ch == '+') || (ch == '!'))
112 {
113 buf_addch(dirpart, ch);
114 if (ch == '!')
115 buf_strcpy(exp_dirpart, c_spool_file);
116 else
117 buf_strcpy(exp_dirpart, c_folder);
118 p = strrchr(buf_string(buf), '/');
119 if (p)
120 {
121 buf_concatn_path(tmp, buf_string(exp_dirpart), buf_len(exp_dirpart),
122 buf_string(buf) + 1, (size_t) (p - buf_string(buf) - 1));
123 buf_copy(exp_dirpart, tmp);
124 buf_substrcpy(dirpart, buf_string(buf), p + 1);
125 buf_strcpy(filepart, p + 1);
126 }
127 else
128 {
129 buf_strcpy(filepart, buf_string(buf) + 1);
130 }
132 }
133 else
134 {
135 p = strrchr(buf_string(buf), '/');
136 if (p)
137 {
138 if (p == buf_string(buf)) /* absolute path */
139 {
140 p = buf_string(buf) + 1;
141 buf_strcpy(dirpart, "/");
142 buf_strcpy(filepart, p);
144 }
145 else
146 {
147 buf_substrcpy(dirpart, buf_string(buf), p);
148 buf_strcpy(filepart, p + 1);
149 buf_copy(exp_dirpart, dirpart);
150 buf_expand_path(exp_dirpart);
152 }
153 }
154 else
155 {
156 /* no directory name, so assume current directory. */
157 buf_strcpy(filepart, buf_string(buf));
159 }
160 }
161
162 if (!dir)
163 {
164 mutt_debug(LL_DEBUG1, "%s: %s (errno %d)\n", buf_string(exp_dirpart),
165 strerror(errno), errno);
166 goto cleanup;
167 }
168
169 /* special case to handle when there is no filepart yet. find the first
170 * file/directory which is not "." or ".." */
171 len = buf_len(filepart);
172 if (len == 0)
173 {
174 while ((de = readdir(dir)))
175 {
176 if (!mutt_str_equal(".", de->d_name) && !mutt_str_equal("..", de->d_name))
177 {
178 buf_strcpy(filepart, de->d_name);
179 init++;
180 break;
181 }
182 }
183 }
184
185 while ((de = readdir(dir)))
186 {
187 if (mutt_strn_equal(de->d_name, buf_string(filepart), len))
188 {
189 if (init)
190 {
191 char *cp = filepart->data;
192
193 for (int i = 0; (*cp != '\0') && (de->d_name[i] != '\0'); i++, cp++)
194 {
195 if (*cp != de->d_name[i])
196 break;
197 }
198 *cp = '\0';
199 buf_fix_dptr(filepart);
200 }
201 else
202 {
203 struct stat st = { 0 };
204
205 buf_strcpy(filepart, de->d_name);
206
207 /* check to see if it is a directory */
208 if (buf_is_empty(dirpart))
209 {
210 buf_reset(tmp);
211 }
212 else
213 {
214 buf_copy(tmp, exp_dirpart);
215 buf_addch(tmp, '/');
216 }
217 buf_addstr(tmp, buf_string(filepart));
218 if ((stat(buf_string(tmp), &st) != -1) && (st.st_mode & S_IFDIR))
219 buf_addch(filepart, '/');
220 init = 1;
221 }
222 }
223 }
224 closedir(dir);
225
226 if (buf_is_empty(dirpart))
227 {
228 buf_copy(buf, filepart);
229 }
230 else
231 {
232 buf_copy(buf, dirpart);
233 if (!mutt_str_equal("/", buf_string(dirpart)) &&
234 (buf_string(dirpart)[0] != '=') && (buf_string(dirpart)[0] != '+'))
235 {
236 buf_addstr(buf, "/");
237 }
238 buf_addstr(buf, buf_string(filepart));
239 }
240
241cleanup:
242 buf_pool_release(&dirpart);
243 buf_pool_release(&exp_dirpart);
244 buf_pool_release(&filepart);
245 buf_pool_release(&tmp);
246
247 return init ? 0 : -1;
248}
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:491
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:76
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:291
void buf_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:182
char buf_at(const struct Buffer *buf, size_t offset)
Return the character at the given offset.
Definition: buffer.c:670
size_t buf_concatn_path(struct Buffer *buf, const char *dir, size_t dirlen, const char *fname, size_t fnamelen)
Join a directory name and a filename.
Definition: buffer.c:546
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:241
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:226
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:395
size_t buf_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition: buffer.c:601
size_t buf_concat_path(struct Buffer *buf, const char *dir, const char *fname)
Join a directory name and a filename.
Definition: buffer.c:509
size_t buf_substrcpy(struct Buffer *buf, const char *beg, const char *end)
Copy a partial string into a Buffer.
Definition: buffer.c:471
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:96
int mutt_complete(struct CompletionData *cd, struct Buffer *buf)
Attempt to complete a partial pathname.
Definition: complete.c:57
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:291
Convenience wrapper for the config headers.
Convenience wrapper for the core headers.
@ MUTT_IMAP
'IMAP' Mailbox type
Definition: mailbox.h:50
DIR * mutt_file_opendir(const char *path, enum MuttOpenDirMode mode)
Open a directory.
Definition: file.c:642
@ MUTT_OPENDIR_NONE
Plain opendir()
Definition: file.h:63
bool OptNews
(pseudo) used to change reader mode
Definition: globals.c:67
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe() -.
Definition: imap.c:2344
IMAP network mailbox.
int imap_complete(struct Buffer *buf, const char *path)
Try to complete an IMAP folder path.
Definition: imap.c:1274
@ LL_DEBUG2
Log at debug level 2.
Definition: logging2.h:44
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
Convenience wrapper for the library headers.
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:660
bool mutt_strn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings (to a maximum), safely.
Definition: string.c:425
void buf_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:315
Some miscellaneous functions.
int nntp_complete(struct Buffer *buf)
Auto-complete NNTP newsgroups.
Definition: complete.c:46
Usenet network mailbox type; talk to an NNTP server.
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:82
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:96
Key value store.
#define NONULL(x)
Definition: string2.h:37
String manipulation buffer.
Definition: buffer.h:36
char * data
Pointer to data.
Definition: buffer.h:37
State data for auto-completion.
Definition: data.h:33
Container for Accounts, Notifications.
Definition: neomutt.h:42
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:46