/*
* Copyright notice from original mutt:
* Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org>
*
* This file is part of mutt-ng, see http://www.muttng.org/.
* It's licensed under the GNU General Public License,
* please see the file GPL in the top level source directory.
*/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include "mutt.h"
#ifdef USE_IMAP
#include "mx.h"
#include "imap.h"
#endif
#ifdef USE_NNTP
#include "nntp.h"
#endif
#include "lib/str.h"
#include "lib/debug.h"
#include <dirent.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
/* given a partial pathname, this routine fills in as much of the rest of the
* path as is unique.
*
* return 0 if ok, -1 if no matches
*/
int mutt_complete (char *s, size_t slen)
{
char *p;
DIR *dirp = NULL;
struct dirent *de;
int i, init = 0;
size_t len;
char dirpart[_POSIX_PATH_MAX], exp_dirpart[_POSIX_PATH_MAX];
char filepart[_POSIX_PATH_MAX];
#ifdef USE_IMAP
char imap_path[LONG_STRING];
#endif
debug_print (2, ("completing %s\n", s));
#ifdef USE_NNTP
if (option (OPTNEWS)) {
LIST *l = CurrentNewsSrv->list;
strfcpy (filepart, s, sizeof (filepart));
/*
* special case to handle when there is no filepart yet.
* find the first subscribed newsgroup
*/
if ((len = str_len (filepart)) == 0) {
for (; l; l = l->next) {
NNTP_DATA *data = (NNTP_DATA *) l->data;
if (data && data->subscribed) {
strfcpy (filepart, data->group, sizeof (filepart));
init++;
l = l->next;
break;
}
}
}
for (; l; l = l->next) {
NNTP_DATA *data = (NNTP_DATA *) l->data;
if (data && data->subscribed &&
str_ncmp (data->group, filepart, len) == 0) {
if (init) {
for (i = 0; filepart[i] && data->group[i]; i++) {
if (filepart[i] != data->group[i]) {
filepart[i] = 0;
break;
}
}
filepart[i] = 0;
}
else {
strfcpy (filepart, data->group, sizeof (filepart));
init = 1;
}
}
}
strcpy (s, filepart);
return (init ? 0 : -1);
}
#endif
#ifdef USE_IMAP
/* we can use '/' as a delimiter, imap_complete rewrites it */
if (*s == '=' || *s == '+' || *s == '!') {
if (*s == '!')
p = NONULL (Spoolfile);
else
p = NONULL (Maildir);
mutt_concat_path (imap_path, p, s + 1, sizeof (imap_path));
}
else
strfcpy (imap_path, s, sizeof (imap_path));
if (mx_get_magic (imap_path) == M_IMAP)
return imap_complete (s, slen, imap_path);
#endif
if (*s == '=' || *s == '+' || *s == '!') {
dirpart[0] = *s;
dirpart[1] = 0;
if (*s == '!')
strfcpy (exp_dirpart, NONULL (Spoolfile), sizeof (exp_dirpart));
else
strfcpy (exp_dirpart, NONULL (Maildir), sizeof (exp_dirpart));
if ((p = strrchr (s, '/'))) {
char buf[_POSIX_PATH_MAX];
*p++ = 0;
mutt_concat_path (buf, exp_dirpart, s + 1, sizeof (buf));
strfcpy (exp_dirpart, buf, sizeof (exp_dirpart));
snprintf (buf, sizeof (buf), "%s%s/", dirpart, s + 1);
strfcpy (dirpart, buf, sizeof (dirpart));
strfcpy (filepart, p, sizeof (filepart));
}
else
strfcpy (filepart, s + 1, sizeof (filepart));
dirp = opendir (exp_dirpart);
}
else {
if ((p = strrchr (s, '/'))) {
if (p == s) { /* absolute path */
p = s + 1;
strfcpy (dirpart, "/", sizeof (dirpart));
exp_dirpart[0] = 0;
strfcpy (filepart, p, sizeof (filepart));
dirp = opendir (dirpart);
}
else {
*p = 0;
len = (size_t) (p - s);
strncpy (dirpart, s, len);
dirpart[len] = 0;
p++;
strfcpy (filepart, p, sizeof (filepart));
strfcpy (exp_dirpart, dirpart, sizeof (exp_dirpart));
mutt_expand_path (exp_dirpart, sizeof (exp_dirpart));
dirp = opendir (exp_dirpart);
}
}
else {
/* no directory name, so assume current directory. */
dirpart[0] = 0;
strfcpy (filepart, s, sizeof (filepart));
dirp = opendir (".");
}
}
if (dirp == NULL) {
debug_print (1, ("%s: %s (errno %d).\n", exp_dirpart, strerror (errno), errno));
return (-1);
}
/*
* special case to handle when there is no filepart yet. find the first
* file/directory which is not ``.'' or ``..''
*/
if ((len = str_len (filepart)) == 0) {
while ((de = readdir (dirp)) != NULL) {
if (str_cmp (".", de->d_name) != 0
&& str_cmp ("..", de->d_name) != 0) {
strfcpy (filepart, de->d_name, sizeof (filepart));
init++;
break;
}
}
}
while ((de = readdir (dirp)) != NULL) {
if (str_ncmp (de->d_name, filepart, len) == 0) {
if (init) {
for (i = 0; filepart[i] && de->d_name[i]; i++) {
if (filepart[i] != de->d_name[i]) {
filepart[i] = 0;
break;
}
}
filepart[i] = 0;
}
else {
char buf[_POSIX_PATH_MAX];
struct stat st;
strfcpy (filepart, de->d_name, sizeof (filepart));
/* check to see if it is a directory */
if (dirpart[0]) {
strfcpy (buf, exp_dirpart, sizeof (buf));
strfcpy (buf + str_len (buf), "/", sizeof (buf) - str_len (buf));
}
else
buf[0] = 0;
strfcpy (buf + str_len (buf), filepart, sizeof (buf) - str_len (buf));
if (stat (buf, &st) != -1 && (st.st_mode & S_IFDIR))
strfcpy (filepart + str_len (filepart), "/",
sizeof (filepart) - str_len (filepart));
init = 1;
}
}
}
closedir (dirp);
if (dirpart[0]) {
strfcpy (s, dirpart, slen);
if (str_cmp ("/", dirpart) != 0 && dirpart[0] != '='
&& dirpart[0] != '+')
strfcpy (s + str_len (s), "/", slen - str_len (s));
strfcpy (s + str_len (s), filepart, slen - str_len (s));
}
else
strfcpy (s, filepart, slen);
return (init ? 0 : -1);
}
syntax highlighted by Code2HTML, v. 0.9.1