Deep rework of nntp_data_t (ex-NNTP_DATA) to make it list-able.
[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 #include <lib-mx/mx.h>
12
13 #include "mutt.h"
14 #include "curses.h"
15 #include <imap/imap.h>
16 #ifdef USE_NNTP
17 #include "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     nntp_data_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         if (l->subscribed) {
50           m_strcpy(filepart, sizeof(filepart), l->group);
51           init++;
52           l = l->next;
53           break;
54         }
55       }
56     }
57
58     for (; l; l = l->next) {
59       if (l->subscribed && m_strncmp(l->group, filepart, len) == 0) {
60         if (init) {
61           for (i = 0; filepart[i] && l->group[i]; i++) {
62             if (filepart[i] != l->group[i]) {
63               filepart[i] = 0;
64               break;
65             }
66           }
67           filepart[i] = 0;
68         } else {
69           m_strcpy(filepart, sizeof(filepart), l->group);
70           init = 1;
71         }
72       }
73     }
74
75     m_strcpy(s, slen, filepart);
76
77     return (init ? 0 : -1);
78   }
79 #endif
80
81   /* we can use '/' as a delimiter, imap_complete rewrites it */
82   if (*s == '=' || *s == '+' || *s == '!') {
83       const char *q = NONULL(*s == '!' ? Spoolfile : Maildir);
84       mutt_concat_path(imap_path, sizeof(imap_path), q, s + 1);
85   }
86   else
87     m_strcpy(imap_path, sizeof(imap_path), s);
88
89   if (mx_get_magic (imap_path) == M_IMAP)
90     return imap_complete (s, slen, imap_path);
91
92   if (*s == '=' || *s == '+' || *s == '!') {
93     dirpart[0] = *s;
94     dirpart[1] = 0;
95     if (*s == '!')
96       m_strcpy(exp_dirpart, sizeof(exp_dirpart), NONULL(Spoolfile));
97     else
98       m_strcpy(exp_dirpart, sizeof(exp_dirpart), NONULL(Maildir));
99     if ((p = strrchr (s, '/'))) {
100       char buf[_POSIX_PATH_MAX];
101
102       *p++ = 0;
103       mutt_concat_path(buf, sizeof(buf), exp_dirpart, s + 1);
104       m_strcpy(exp_dirpart, sizeof(exp_dirpart), buf);
105       snprintf (buf, sizeof (buf), "%s%s/", dirpart, s + 1);
106       m_strcpy(dirpart, sizeof(dirpart), buf);
107       m_strcpy(filepart, sizeof(filepart), p);
108     }
109     else
110       m_strcpy(filepart, sizeof(filepart), s + 1);
111     dirp = opendir (exp_dirpart);
112   }
113   else {
114     if ((p = strrchr (s, '/'))) {
115       if (p == s) {             /* absolute path */
116         p = s + 1;
117         m_strcpy(dirpart, sizeof(dirpart), "/");
118         exp_dirpart[0] = 0;
119         m_strcpy(filepart, sizeof(filepart), p);
120         dirp = opendir (dirpart);
121       }
122       else {
123         *p = 0;
124         len = p - s;
125         memcpy(dirpart, s, len);
126         dirpart[len] = 0;
127         p++;
128         m_strcpy(filepart, sizeof(filepart), p);
129         m_strcpy(exp_dirpart, sizeof(exp_dirpart), dirpart);
130         mutt_expand_path (exp_dirpart, sizeof (exp_dirpart));
131         dirp = opendir (exp_dirpart);
132       }
133     }
134     else {
135       /* no directory name, so assume current directory. */
136       dirpart[0] = 0;
137       m_strcpy(filepart, sizeof(filepart), s);
138       dirp = opendir (".");
139     }
140   }
141
142   if (dirp == NULL) {
143     return (-1);
144   }
145
146   /*
147    * special case to handle when there is no filepart yet.  find the first
148    * file/directory which is not ``.'' or ``..''
149    */
150   if ((len = m_strlen(filepart)) == 0) {
151     while ((de = readdir (dirp)) != NULL) {
152       if (m_strcmp(".", de->d_name) != 0
153           && m_strcmp("..", de->d_name) != 0) {
154         m_strcpy(filepart, sizeof(filepart), de->d_name);
155         init++;
156         break;
157       }
158     }
159   }
160
161   while ((de = readdir (dirp)) != NULL) {
162     if (m_strncmp(de->d_name, filepart, len) == 0) {
163       if (init) {
164         for (i = 0; filepart[i] && de->d_name[i]; i++) {
165           if (filepart[i] != de->d_name[i]) {
166             filepart[i] = 0;
167             break;
168           }
169         }
170         filepart[i] = 0;
171       }
172       else {
173         char buf[_POSIX_PATH_MAX];
174         struct stat st;
175
176         m_strcpy(filepart, sizeof(filepart), de->d_name);
177
178         /* check to see if it is a directory */
179         if (dirpart[0]) {
180           m_strcpy(buf, sizeof(buf), exp_dirpart);
181           m_strcpy(buf + m_strlen(buf), sizeof(buf) - m_strlen(buf), "/");
182         }
183         else
184           buf[0] = 0;
185         m_strcpy(buf + m_strlen(buf), sizeof(buf) - m_strlen(buf), filepart);
186         if (stat (buf, &st) != -1 && (st.st_mode & S_IFDIR))
187           m_strcpy(filepart + m_strlen(filepart),
188                    sizeof(filepart) - m_strlen(filepart), "/");
189         init = 1;
190       }
191     }
192   }
193   closedir (dirp);
194
195   if (dirpart[0]) {
196     m_strcpy(s, slen, dirpart);
197     if (m_strcmp("/", dirpart) != 0 && dirpart[0] != '='
198         && dirpart[0] != '+')
199       m_strcpy(s + m_strlen(s), slen - m_strlen(s), "/");
200     m_strcpy(s + m_strlen(s), slen - m_strlen(s), filepart);
201   }
202   else
203     m_strcpy(s, slen, filepart);
204
205   return (init ? 0 : -1);
206 }