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