Make layout windows visible, makes the whole thing way simpler.
[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 #ifdef USE_NNTP
16 #include "nntp.h"
17 #endif
18
19 /* given a partial pathname, this routine fills in as much of the rest of the
20  * path as is unique.
21  *
22  * return 0 if ok, -1 if no matches
23  */
24 int mutt_complete (char *s, ssize_t slen)
25 {
26   char *p;
27   DIR *dirp = NULL;
28   struct dirent *de;
29   int i, init = 0;
30   ssize_t len;
31   char dirpart[_POSIX_PATH_MAX], exp_dirpart[_POSIX_PATH_MAX];
32   char filepart[_POSIX_PATH_MAX];
33
34   char imap_path[LONG_STRING];
35
36 #ifdef USE_NNTP
37   if (option (OPTNEWS)) {
38     nntp_data_t *l = CurrentNewsSrv->list;
39
40     m_strcpy(filepart, sizeof(filepart), s);
41
42     /*
43      * special case to handle when there is no filepart yet.
44      * find the first subscribed newsgroup
45      */
46     if ((len = m_strlen(filepart)) == 0) {
47       for (; l; l = l->next) {
48         if (l->subscribed) {
49           m_strcpy(filepart, sizeof(filepart), l->group);
50           init++;
51           l = l->next;
52           break;
53         }
54       }
55     }
56
57     for (; l; l = l->next) {
58       if (l->subscribed && m_strncmp(l->group, filepart, len) == 0) {
59         if (init) {
60           for (i = 0; filepart[i] && l->group[i]; i++) {
61             if (filepart[i] != l->group[i]) {
62               filepart[i] = 0;
63               break;
64             }
65           }
66           filepart[i] = 0;
67         } else {
68           m_strcpy(filepart, sizeof(filepart), l->group);
69           init = 1;
70         }
71       }
72     }
73
74     m_strcpy(s, slen, filepart);
75
76     return (init ? 0 : -1);
77   }
78 #endif
79
80   /* we can use '/' as a delimiter, imap_complete rewrites it */
81   if (*s == '=' || *s == '+' || *s == '!') {
82       const char *q = NONULL(*s == '!' ? Spoolfile : Maildir);
83       mutt_concat_path(imap_path, sizeof(imap_path), q, s + 1);
84   }
85   else
86     m_strcpy(imap_path, sizeof(imap_path), s);
87
88   if (mx_get_magic (imap_path) == M_IMAP)
89     return imap_complete (s, slen, imap_path);
90
91   if (*s == '=' || *s == '+' || *s == '!') {
92     dirpart[0] = *s;
93     dirpart[1] = 0;
94     if (*s == '!')
95       m_strcpy(exp_dirpart, sizeof(exp_dirpart), NONULL(Spoolfile));
96     else
97       m_strcpy(exp_dirpart, sizeof(exp_dirpart), NONULL(Maildir));
98     if ((p = strrchr (s, '/'))) {
99       char buf[_POSIX_PATH_MAX];
100
101       *p++ = 0;
102       mutt_concat_path(buf, sizeof(buf), exp_dirpart, s + 1);
103       m_strcpy(exp_dirpart, sizeof(exp_dirpart), buf);
104       snprintf (buf, sizeof (buf), "%s%s/", dirpart, s + 1);
105       m_strcpy(dirpart, sizeof(dirpart), buf);
106       m_strcpy(filepart, sizeof(filepart), p);
107     }
108     else
109       m_strcpy(filepart, sizeof(filepart), s + 1);
110     dirp = opendir (exp_dirpart);
111   }
112   else {
113     if ((p = strrchr (s, '/'))) {
114       if (p == s) {             /* absolute path */
115         p = s + 1;
116         m_strcpy(dirpart, sizeof(dirpart), "/");
117         exp_dirpart[0] = 0;
118         m_strcpy(filepart, sizeof(filepart), p);
119         dirp = opendir (dirpart);
120       }
121       else {
122         *p = 0;
123         len = p - s;
124         memcpy(dirpart, s, len);
125         dirpart[len] = 0;
126         p++;
127         m_strcpy(filepart, sizeof(filepart), p);
128         m_strcpy(exp_dirpart, sizeof(exp_dirpart), dirpart);
129         mutt_expand_path (exp_dirpart, sizeof (exp_dirpart));
130         dirp = opendir (exp_dirpart);
131       }
132     }
133     else {
134       /* no directory name, so assume current directory. */
135       dirpart[0] = 0;
136       m_strcpy(filepart, sizeof(filepart), s);
137       dirp = opendir (".");
138     }
139   }
140
141   if (dirp == NULL) {
142     return (-1);
143   }
144
145   /*
146    * special case to handle when there is no filepart yet.  find the first
147    * file/directory which is not ``.'' or ``..''
148    */
149   if ((len = m_strlen(filepart)) == 0) {
150     while ((de = readdir (dirp)) != NULL) {
151       if (m_strcmp(".", de->d_name) != 0
152           && m_strcmp("..", de->d_name) != 0) {
153         m_strcpy(filepart, sizeof(filepart), de->d_name);
154         init++;
155         break;
156       }
157     }
158   }
159
160   while ((de = readdir (dirp)) != NULL) {
161     if (m_strncmp(de->d_name, filepart, len) == 0) {
162       if (init) {
163         for (i = 0; filepart[i] && de->d_name[i]; i++) {
164           if (filepart[i] != de->d_name[i]) {
165             filepart[i] = 0;
166             break;
167           }
168         }
169         filepart[i] = 0;
170       }
171       else {
172         char buf[_POSIX_PATH_MAX];
173         struct stat st;
174
175         m_strcpy(filepart, sizeof(filepart), de->d_name);
176
177         /* check to see if it is a directory */
178         if (dirpart[0]) {
179           m_strcpy(buf, sizeof(buf), exp_dirpart);
180           m_strcpy(buf + m_strlen(buf), sizeof(buf) - m_strlen(buf), "/");
181         }
182         else
183           buf[0] = 0;
184         m_strcpy(buf + m_strlen(buf), sizeof(buf) - m_strlen(buf), filepart);
185         if (stat (buf, &st) != -1 && (st.st_mode & S_IFDIR))
186           m_strcpy(filepart + m_strlen(filepart),
187                    sizeof(filepart) - m_strlen(filepart), "/");
188         init = 1;
189       }
190     }
191   }
192   closedir (dirp);
193
194   if (dirpart[0]) {
195     m_strcpy(s, slen, dirpart);
196     if (m_strcmp("/", dirpart) != 0 && dirpart[0] != '='
197         && dirpart[0] != '+')
198       m_strcpy(s + m_strlen(s), slen - m_strlen(s), "/");
199     m_strcpy(s + m_strlen(s), slen - m_strlen(s), filepart);
200   }
201   else
202     m_strcpy(s, slen, filepart);
203
204   return (init ? 0 : -1);
205 }