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