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