From 0c8ec9c530aff4442c0eba0c414374c05fe90aee Mon Sep 17 00:00:00 2001
From: Christoph Berg <myon@debian.org>
Date: Sun, 26 Apr 2020 22:58:37 +0200
Subject: [PATCH] Allow changing the current working directory

This add a "cd" command that changes Mutt's current working directory.
Use cases are saving attachments to some other place and others.
---
 PATCHES             |  1 +
 doc/manual.xml.head | 19 +++++++++++++++++++
 init.c              | 29 +++++++++++++++++++++++++++++
 init.h              |  2 ++
 4 files changed, 51 insertions(+)

diff --git a/PATCHES b/PATCHES
index e69de29b..3bc2a898 100644
--- a/PATCHES
+++ b/PATCHES
@@ -0,0 +1 @@
+patch-1.5.13.cb.chdir.1
diff --git a/doc/manual.xml.head b/doc/manual.xml.head
index 631692aa..d86b9dc1 100644
--- a/doc/manual.xml.head
+++ b/doc/manual.xml.head
@@ -2744,6 +2744,25 @@ specified key sequence.
 
 </sect1>
 
+<sect1 id="cd">
+<title>Changing the current working directory</title>
+
+<para>
+<literallayout>
+Usage: <literal>cd</literal> <emphasis>directory</emphasis>
+</literallayout>
+</para>
+
+<para>
+The <literal>cd</literal> command changes Mutt's current working directory.
+This affects commands and functions like <literal>source</literal>,
+<literal>change-folder</literal>, and <literal>save-entry</literal> that use
+relative paths. Using <literal>cd</literal> without directory changes to your
+home directory.
+</para>
+
+</sect1>
+
 <sect1 id="charset-hook">
 <title>Defining Aliases for Character Sets</title>
 
diff --git a/init.c b/init.c
index 26f8afcf..92f20eb8 100644
--- a/init.c
+++ b/init.c
@@ -2865,6 +2865,35 @@ int mutt_parse_rc_line (const char *line, BUFFER *err)
   return rc;
 }
 
+static int parse_cd (BUFFER *tmp, BUFFER *s, union pointer_long_t, BUFFER *err)
+{
+  char path[_POSIX_PATH_MAX];
+
+  if (mutt_extract_token (tmp, s, 0) != 0)
+  {
+    snprintf (err->data, err->dsize, _("cd: error at %s"), s->dptr);
+    return (-1);
+  }
+  if (MoreArgs (s))
+  {
+    strfcpy (err->data, _("cd: too many arguments"), err->dsize);
+    return (-1);
+  }
+  strfcpy (path, tmp->data, sizeof (path));
+  mutt_expand_path (path, sizeof (path));
+  if (!*path) {
+    char *home = getenv("HOME");
+    if (home)
+      strfcpy (path, home, sizeof (path));
+  }
+  if (chdir(path) != 0) {
+    snprintf (err->data, err->dsize, _("cd: %s"), strerror(errno));
+    return (-1);
+  }
+  return (0);
+}
+
+
 /* line		command to execute
 
    token	scratch buffer to be used by parser.
diff --git a/init.h b/init.h
index 6cbc30a3..d04a0d4b 100644
--- a/init.h
+++ b/init.h
@@ -4585,6 +4585,7 @@ static int parse_echo (BUFFER *, BUFFER *, union pointer_long_t, BUFFER *);
 static int parse_ignore (BUFFER *, BUFFER *, union pointer_long_t, BUFFER *);
 static int parse_unignore (BUFFER *, BUFFER *, union pointer_long_t, BUFFER *);
 static int parse_source (BUFFER *, BUFFER *, union pointer_long_t, BUFFER *);
+static int parse_cd (BUFFER *, BUFFER *, union pointer_long_t, BUFFER *);
 static int parse_set (BUFFER *, BUFFER *, union pointer_long_t, BUFFER *);
 static int parse_setenv (BUFFER *, BUFFER *, union pointer_long_t, BUFFER *);
 static int parse_my_hdr (BUFFER *, BUFFER *, union pointer_long_t, BUFFER *);
@@ -4625,6 +4626,7 @@ const struct command_t Commands[] = {
   { "auto_view",	parse_list,		{.p=&AutoViewList} },
   { "alternative_order",	parse_list,	{.p=&AlternativeOrderList} },
   { "bind",		mutt_parse_bind,	{.l=0} },
+  { "cd",		parse_cd,		{.l=0} },
   { "charset-hook",	mutt_parse_hook,	{.l=MUTT_CHARSETHOOK} },
 #ifdef HAVE_COLOR
   { "color",		mutt_parse_color,	{.l=0} },
-- 
2.26.1

