well this makes things fail for people ...
[apps/madmutt.git] / lib-ui / complete.c
1 /*
2  * Copyright notice from original mutt:
3  * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org>
4  *
5  * This file is part of mutt-ng, see http://www.muttng.org/.
6  * It's licensed under the GNU General Public License,
7  * please see the file GPL in the top level source directory.
8  */
9
10 #include <lib-ui/lib-ui.h>
11 #include <lib-mx/mx.h>
12
13 #include "mutt.h"
14 #include <imap/imap.h>
15
16 /* given a partial pathname, this routine fills in as much of the rest of the
17  * path as is unique.
18  *
19  * return 0 if ok, -1 if no matches
20  */
21 int mutt_complete (char *s, ssize_t slen)
22 {
23   char *p;
24   DIR *dirp = NULL;
25   struct dirent *de;
26   int i, init = 0;
27   ssize_t len;
28   char dirpart[_POSIX_PATH_MAX], exp_dirpart[_POSIX_PATH_MAX];
29   char filepart[_POSIX_PATH_MAX];
30
31   char imap_path[LONG_STRING];
32
33   /* we can use '/' as a delimiter, imap_complete rewrites it */
34   if (*s == '=' || *s == '+' || *s == '!') {
35       const char *q = NONULL(*s == '!' ? Spoolfile : Maildir);
36       mutt_concat_path(imap_path, sizeof(imap_path), q, s + 1);
37   }
38   else
39     m_strcpy(imap_path, sizeof(imap_path), s);
40
41   if (mx_get_magic (imap_path) == M_IMAP)
42     return imap_complete (s, slen, imap_path);
43
44   if (*s == '=' || *s == '+' || *s == '!') {
45     dirpart[0] = *s;
46     dirpart[1] = 0;
47     if (*s == '!')
48       m_strcpy(exp_dirpart, sizeof(exp_dirpart), NONULL(Spoolfile));
49     else
50       m_strcpy(exp_dirpart, sizeof(exp_dirpart), NONULL(Maildir));
51     if ((p = strrchr (s, '/'))) {
52       char buf[_POSIX_PATH_MAX];
53
54       *p++ = 0;
55       mutt_concat_path(buf, sizeof(buf), exp_dirpart, s + 1);
56       m_strcpy(exp_dirpart, sizeof(exp_dirpart), buf);
57       snprintf (buf, sizeof (buf), "%s%s/", dirpart, s + 1);
58       m_strcpy(dirpart, sizeof(dirpart), buf);
59       m_strcpy(filepart, sizeof(filepart), p);
60     }
61     else
62       m_strcpy(filepart, sizeof(filepart), s + 1);
63     dirp = opendir (exp_dirpart);
64   }
65   else {
66     if ((p = strrchr (s, '/'))) {
67       if (p == s) {             /* absolute path */
68         p = s + 1;
69         m_strcpy(dirpart, sizeof(dirpart), "/");
70         exp_dirpart[0] = 0;
71         m_strcpy(filepart, sizeof(filepart), p);
72         dirp = opendir (dirpart);
73       }
74       else {
75         *p = 0;
76         len = p - s;
77         memcpy(dirpart, s, len);
78         dirpart[len] = 0;
79         p++;
80         m_strcpy(filepart, sizeof(filepart), p);
81         m_strcpy(exp_dirpart, sizeof(exp_dirpart), dirpart);
82         mutt_expand_path (exp_dirpart, sizeof (exp_dirpart));
83         dirp = opendir (exp_dirpart);
84       }
85     }
86     else {
87       /* no directory name, so assume current directory. */
88       dirpart[0] = 0;
89       m_strcpy(filepart, sizeof(filepart), s);
90       dirp = opendir (".");
91     }
92   }
93
94   if (dirp == NULL) {
95     return -1;
96   }
97
98   /*
99    * special case to handle when there is no filepart yet.  find the first
100    * file/directory which is not ``.'' or ``..''
101    */
102   if ((len = m_strlen(filepart)) == 0) {
103     while ((de = readdir (dirp)) != NULL) {
104       if (m_strcmp(".", de->d_name) != 0
105           && m_strcmp("..", de->d_name) != 0) {
106         m_strcpy(filepart, sizeof(filepart), de->d_name);
107         init++;
108         break;
109       }
110     }
111   }
112
113   while ((de = readdir (dirp)) != NULL) {
114     if (m_strncmp(de->d_name, filepart, len) == 0) {
115       if (init) {
116         for (i = 0; filepart[i] && de->d_name[i]; i++) {
117           if (filepart[i] != de->d_name[i]) {
118             filepart[i] = 0;
119             break;
120           }
121         }
122         filepart[i] = 0;
123       }
124       else {
125         char buf[_POSIX_PATH_MAX];
126         struct stat st;
127
128         m_strcpy(filepart, sizeof(filepart), de->d_name);
129
130         /* check to see if it is a directory */
131         if (dirpart[0]) {
132           m_strcpy(buf, sizeof(buf), exp_dirpart);
133           m_strcpy(buf + m_strlen(buf), sizeof(buf) - m_strlen(buf), "/");
134         }
135         else
136           buf[0] = 0;
137         m_strcpy(buf + m_strlen(buf), sizeof(buf) - m_strlen(buf), filepart);
138         if (stat (buf, &st) != -1 && (st.st_mode & S_IFDIR))
139           m_strcpy(filepart + m_strlen(filepart),
140                    sizeof(filepart) - m_strlen(filepart), "/");
141         init = 1;
142       }
143     }
144   }
145   closedir (dirp);
146
147   if (dirpart[0]) {
148     m_strcpy(s, slen, dirpart);
149     if (m_strcmp("/", dirpart) != 0 && dirpart[0] != '='
150         && dirpart[0] != '+')
151       m_strcpy(s + m_strlen(s), slen - m_strlen(s), "/");
152     m_strcpy(s + m_strlen(s), slen - m_strlen(s), filepart);
153   }
154   else
155     m_strcpy(s, slen, filepart);
156
157   return init ? 0 : -1;
158 }