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