mutt stable branch with some hacks
1/*
2 * Copyright (C) 1996-2000,2007 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 */
40int 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 BUFFER *dirpart = NULL;
48 BUFFER *exp_dirpart = NULL;
49 BUFFER *filepart = NULL;
50 BUFFER *buf = NULL;
51
52#ifdef USE_IMAP
53 BUFFER *imap_path = NULL;
54 int rc;
55
56 dprint (2, (debugfile, "mutt_complete: completing %s\n", s));
57
58 imap_path = mutt_buffer_pool_get ();
59 /* we can use '/' as a delimiter, imap_complete rewrites it */
60 if (*s == '=' || *s == '+' || *s == '!')
61 {
62 if (*s == '!')
63 p = NONULL (Spoolfile);
64 else
65 p = NONULL (Maildir);
66
67 mutt_buffer_concat_path (imap_path, p, s+1);
68 }
69 else
70 mutt_buffer_strcpy (imap_path, s);
71
72 if (mx_is_imap (mutt_b2s (imap_path)))
73 {
74 rc = imap_complete (s, slen, mutt_b2s (imap_path));
75 mutt_buffer_pool_release (&imap_path);
76 return rc;
77 }
78
79 mutt_buffer_pool_release (&imap_path);
80#endif
81
82 dirpart = mutt_buffer_pool_get ();
83 exp_dirpart = mutt_buffer_pool_get ();
84 filepart = mutt_buffer_pool_get ();
85 buf = mutt_buffer_pool_get ();
86
87 if (*s == '=' || *s == '+' || *s == '!')
88 {
89 mutt_buffer_addch (dirpart, *s);
90 if (*s == '!')
91 mutt_buffer_strcpy (exp_dirpart, NONULL (Spoolfile));
92 else
93 mutt_buffer_strcpy (exp_dirpart, NONULL (Maildir));
94 if ((p = strrchr (s, '/')))
95 {
96 mutt_buffer_concatn_path (buf,
97 mutt_b2s (exp_dirpart), mutt_buffer_len (exp_dirpart),
98 s + 1, (size_t)(p - s - 1));
99 mutt_buffer_strcpy (exp_dirpart, mutt_b2s (buf));
100 mutt_buffer_substrcpy (dirpart, s, p+1);
101 mutt_buffer_strcpy (filepart, p + 1);
102 }
103 else
104 mutt_buffer_strcpy (filepart, s + 1);
105 dirp = opendir (mutt_b2s (exp_dirpart));
106 }
107 else
108 {
109 if ((p = strrchr (s, '/')))
110 {
111 if (p == s) /* absolute path */
112 {
113 p = s + 1;
114 mutt_buffer_strcpy (dirpart, "/");
115 mutt_buffer_strcpy (filepart, p);
116 dirp = opendir (mutt_b2s (dirpart));
117 }
118 else
119 {
120 mutt_buffer_substrcpy (dirpart, s, p);
121 mutt_buffer_strcpy (filepart, p + 1);
122 mutt_buffer_strcpy (exp_dirpart, mutt_b2s (dirpart));
123 mutt_buffer_expand_path (exp_dirpart);
124 dirp = opendir (mutt_b2s (exp_dirpart));
125 }
126 }
127 else
128 {
129 /* no directory name, so assume current directory. */
130 mutt_buffer_strcpy (filepart, s);
131 dirp = opendir (".");
132 }
133 }
134
135 if (dirp == NULL)
136 {
137 dprint (1, (debugfile, "mutt_complete(): %s: %s (errno %d).\n",
138 mutt_b2s (exp_dirpart), strerror (errno), errno));
139 goto cleanup;
140 }
141
142 /*
143 * special case to handle when there is no filepart yet. find the first
144 * file/directory which is not ``.'' or ``..''
145 */
146 if ((len = mutt_buffer_len (filepart)) == 0)
147 {
148 while ((de = readdir (dirp)) != NULL)
149 {
150 if (mutt_strcmp (".", de->d_name) != 0 && mutt_strcmp ("..", de->d_name) != 0)
151 {
152 mutt_buffer_strcpy (filepart, de->d_name);
153 init++;
154 break;
155 }
156 }
157 }
158
159 while ((de = readdir (dirp)) != NULL)
160 {
161 if (mutt_strncmp (de->d_name, mutt_b2s (filepart), len) == 0)
162 {
163 if (init)
164 {
165 char *fpch;
166
167 for (i=0, fpch = filepart->data; *fpch && de->d_name[i]; i++, fpch++)
168 {
169 if (*fpch != de->d_name[i])
170 break;
171 }
172 *fpch = 0;
173 mutt_buffer_fix_dptr (filepart);
174 }
175 else
176 {
177 struct stat st;
178
179 mutt_buffer_strcpy (filepart, de->d_name);
180
181 /* check to see if it is a directory */
182 if (mutt_buffer_len (dirpart))
183 {
184 mutt_buffer_strcpy (buf, mutt_b2s (exp_dirpart));
185 mutt_buffer_addch (buf, '/');
186 }
187 else
188 mutt_buffer_clear (buf);
189 mutt_buffer_addstr (buf, mutt_b2s (filepart));
190 if (stat (mutt_b2s (buf), &st) != -1 && (st.st_mode & S_IFDIR))
191 mutt_buffer_addch (filepart, '/');
192 init = 1;
193 }
194 }
195 }
196 closedir (dirp);
197
198 if (mutt_buffer_len (dirpart))
199 {
200 strfcpy (s, mutt_b2s (dirpart), slen);
201 if (mutt_strcmp ("/", mutt_b2s (dirpart)) != 0 &&
202 mutt_b2s (dirpart)[0] != '=' &&
203 mutt_b2s (dirpart)[0] != '+')
204 strfcpy (s + strlen (s), "/", slen - strlen (s));
205 strfcpy (s + strlen (s), mutt_b2s (filepart), slen - strlen (s));
206 }
207 else
208 strfcpy (s, mutt_b2s (filepart), slen);
209
210cleanup:
211 mutt_buffer_pool_release (&dirpart);
212 mutt_buffer_pool_release (&exp_dirpart);
213 mutt_buffer_pool_release (&filepart);
214 mutt_buffer_pool_release (&buf);
215
216 return (init ? 0 : -1);
217}