]> git.llucax.com Git - software/mutt-debian.git/blob - complete.c
Merge branch '1.5.20-1+fix533459'
[software/mutt-debian.git] / complete.c
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  */
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 }