NeoMutt  2021-02-05-89-gabe350
Teaching an old dog new tricks
DOXYGEN
complete.c
Go to the documentation of this file.
1 
29 #include "config.h"
30 #include <dirent.h>
31 #include <errno.h>
32 #include <string.h>
33 #include <sys/stat.h>
34 #include "mutt/lib.h"
35 #include "core/lib.h"
36 #include "mutt_globals.h"
37 #include "muttlib.h"
38 #include "options.h"
39 #include "protos.h" // IWYU pragma: keep
40 #ifdef USE_IMAP
41 #include "imap/lib.h"
42 #endif
43 #ifdef USE_NNTP
44 #include "nntp/lib.h"
45 #endif
46 
57 int mutt_complete(char *buf, size_t buflen)
58 {
59  char *p = NULL;
60  DIR *dirp = 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 #ifdef USE_IMAP
69  struct Buffer *imap_path = NULL;
70  int rc;
71 #endif
72 
73  mutt_debug(LL_DEBUG2, "completing %s\n", buf);
74 
75 #ifdef USE_NNTP
76  if (OptNews)
77  return nntp_complete(buf, buflen);
78 #endif
79 
80 #ifdef USE_IMAP
81  imap_path = mutt_buffer_pool_get();
82  /* we can use '/' as a delimiter, imap_complete rewrites it */
83  if ((*buf == '=') || (*buf == '+') || (*buf == '!'))
84  {
85  if (*buf == '!')
86  p = NONULL(C_SpoolFile);
87  else
88  p = NONULL(C_Folder);
89 
90  mutt_buffer_concat_path(imap_path, p, buf + 1);
91  }
92  else
93  mutt_buffer_strcpy(imap_path, buf);
94 
95  if (imap_path_probe(mutt_buffer_string(imap_path), NULL) == MUTT_IMAP)
96  {
97  rc = imap_complete(buf, buflen, mutt_buffer_string(imap_path));
98  mutt_buffer_pool_release(&imap_path);
99  return rc;
100  }
101 
102  mutt_buffer_pool_release(&imap_path);
103 #endif
104 
105  dirpart = mutt_buffer_pool_get();
106  exp_dirpart = mutt_buffer_pool_get();
107  filepart = mutt_buffer_pool_get();
108  tmp = mutt_buffer_pool_get();
109 
110  if ((*buf == '=') || (*buf == '+') || (*buf == '!'))
111  {
112  mutt_buffer_addch(dirpart, *buf);
113  if (*buf == '!')
114  mutt_buffer_strcpy(exp_dirpart, NONULL(C_SpoolFile));
115  else
116  mutt_buffer_strcpy(exp_dirpart, NONULL(C_Folder));
117  p = strrchr(buf, '/');
118  if (p)
119  {
121  mutt_buffer_len(exp_dirpart), buf + 1,
122  (size_t)(p - buf - 1));
123  mutt_buffer_copy(exp_dirpart, tmp);
124  mutt_buffer_substrcpy(dirpart, buf, p + 1);
125  mutt_buffer_strcpy(filepart, p + 1);
126  }
127  else
128  mutt_buffer_strcpy(filepart, buf + 1);
129  dirp = opendir(mutt_buffer_string(exp_dirpart));
130  }
131  else
132  {
133  p = strrchr(buf, '/');
134  if (p)
135  {
136  if (p == buf) /* absolute path */
137  {
138  p = buf + 1;
139  mutt_buffer_strcpy(dirpart, "/");
140  mutt_buffer_strcpy(filepart, p);
141  dirp = opendir(mutt_buffer_string(dirpart));
142  }
143  else
144  {
145  mutt_buffer_substrcpy(dirpart, buf, p);
146  mutt_buffer_strcpy(filepart, p + 1);
147  mutt_buffer_copy(exp_dirpart, dirpart);
148  mutt_buffer_expand_path(exp_dirpart);
149  dirp = opendir(mutt_buffer_string(exp_dirpart));
150  }
151  }
152  else
153  {
154  /* no directory name, so assume current directory. */
155  mutt_buffer_strcpy(filepart, buf);
156  dirp = opendir(".");
157  }
158  }
159 
160  if (!dirp)
161  {
162  mutt_debug(LL_DEBUG1, "%s: %s (errno %d)\n",
163  mutt_buffer_string(exp_dirpart), strerror(errno), errno);
164  goto cleanup;
165  }
166 
167  /* special case to handle when there is no filepart yet. find the first
168  * file/directory which is not "." or ".." */
169  len = mutt_buffer_len(filepart);
170  if (len == 0)
171  {
172  while ((de = readdir(dirp)))
173  {
174  if (!mutt_str_equal(".", de->d_name) && !mutt_str_equal("..", de->d_name))
175  {
176  mutt_buffer_strcpy(filepart, de->d_name);
177  init++;
178  break;
179  }
180  }
181  }
182 
183  while ((de = readdir(dirp)))
184  {
185  if (mutt_strn_equal(de->d_name, mutt_buffer_string(filepart), len))
186  {
187  if (init)
188  {
189  char *cp = filepart->data;
190 
191  for (int i = 0; (*cp != '\0') && (de->d_name[i] != '\0'); i++, cp++)
192  {
193  if (*cp != de->d_name[i])
194  break;
195  }
196  *cp = '\0';
197  mutt_buffer_fix_dptr(filepart);
198  }
199  else
200  {
201  struct stat st;
202 
203  mutt_buffer_strcpy(filepart, de->d_name);
204 
205  /* check to see if it is a directory */
206  if (mutt_buffer_is_empty(dirpart))
207  {
208  mutt_buffer_reset(tmp);
209  }
210  else
211  {
212  mutt_buffer_copy(tmp, exp_dirpart);
213  mutt_buffer_addch(tmp, '/');
214  }
215  mutt_buffer_addstr(tmp, mutt_buffer_string(filepart));
216  if ((stat(mutt_buffer_string(tmp), &st) != -1) && (st.st_mode & S_IFDIR))
217  mutt_buffer_addch(filepart, '/');
218  init = 1;
219  }
220  }
221  }
222  closedir(dirp);
223 
224  if (!mutt_buffer_is_empty(dirpart))
225  {
226  mutt_str_copy(buf, mutt_buffer_string(dirpart), buflen);
227  if (!mutt_str_equal("/", mutt_buffer_string(dirpart)) &&
228  (mutt_buffer_string(dirpart)[0] != '=') && (mutt_buffer_string(dirpart)[0] != '+'))
229  {
230  mutt_str_copy(buf + strlen(buf), "/", buflen - strlen(buf));
231  }
232  mutt_str_copy(buf + strlen(buf), mutt_buffer_string(filepart), buflen - strlen(buf));
233  }
234  else
235  mutt_str_copy(buf, mutt_buffer_string(filepart), buflen);
236 
237 cleanup:
238  mutt_buffer_pool_release(&dirpart);
239  mutt_buffer_pool_release(&exp_dirpart);
240  mutt_buffer_pool_release(&filepart);
242 
243  return init ? 0 : -1;
244 }
lib.h
NONULL
#define NONULL(x)
Definition: string2.h:37
mutt_strn_equal
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:593
Buffer
String manipulation buffer.
Definition: buffer.h:33
mutt_buffer_is_empty
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
mutt_globals.h
LL_DEBUG1
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
options.h
nntp_complete
int nntp_complete(char *buf, size_t buflen)
Auto-complete NNTP newsgroups.
Definition: complete.c:47
mutt_buffer_reset
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
mutt_buffer_pool_release
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
mutt_str_equal
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:871
protos.h
mutt_buffer_addch
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
mutt_buffer_pool_get
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
mutt_buffer_copy
size_t mutt_buffer_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition: buffer.c:445
lib.h
muttlib.h
C_Folder
WHERE char * C_Folder
Config: Base folder for a set of mailboxes.
Definition: mutt_globals.h:96
lib.h
mutt_complete
int mutt_complete(char *buf, size_t buflen)
Attempt to complete a partial pathname.
Definition: complete.c:57
MUTT_IMAP
@ MUTT_IMAP
'IMAP' Mailbox type
Definition: mailbox.h:53
mutt_buffer_concat_path
size_t mutt_buffer_concat_path(struct Buffer *buf, const char *dir, const char *fname)
Join a directory name and a filename.
Definition: buffer.c:374
imap_complete
int imap_complete(char *buf, size_t buflen, const char *path)
Try to complete an IMAP folder path.
Definition: imap.c:1327
mutt_debug
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
mutt_buffer_expand_path
void mutt_buffer_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:323
mutt_buffer_string
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
lib.h
mutt_buffer_fix_dptr
void mutt_buffer_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:181
C_SpoolFile
WHERE char * C_SpoolFile
Config: Inbox.
Definition: mutt_globals.h:108
mutt_buffer_substrcpy
size_t mutt_buffer_substrcpy(struct Buffer *buf, const char *beg, const char *end)
Copy a partial string into a Buffer.
Definition: buffer.c:342
imap_path_probe
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe()
Definition: imap.c:2372
mutt_buffer_len
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:356
mutt_buffer_addstr
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
Buffer::data
char * data
Pointer to data.
Definition: buffer.h:35
mutt_buffer_concatn_path
size_t mutt_buffer_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:411
mutt_buffer_strcpy
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
LL_DEBUG2
@ LL_DEBUG2
Log at debug level 2.
Definition: logging.h:41
OptNews
WHERE bool OptNews
(pseudo) used to change reader mode
Definition: options.h:45
mutt_str_copy
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:716