1 /**
2  * @file
3  * Private copy of the environment variables
4  *
5  * @authors
6  * Copyright (C) 2018 Richard Russon <rich@flatcap.org>
7  *
8  * @copyright
9  * This program is free software: you can redistribute it and/or modify it under
10  * the terms of the GNU General Public License as published by the Free Software
11  * Foundation, either version 2 of the License, or (at your option) any later
12  * version.
13  *
14  * This program is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
17  * details.
18  *
19  * You should have received a copy of the GNU General Public License along with
20  * this program.  If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 /**
24  * @page mutt_envlist Private copy of the environment variables
25  *
26  * Private copy of the environment variables
27  */
28 
29 #include "config.h"
30 #include <stdbool.h>
31 #include <stdio.h>
32 #include "envlist.h"
33 #include "memory.h"
34 #include "string2.h"
35 
36 char **EnvList = NULL; ///< Private copy of the environment variables
37 
38 /**
39  * mutt_envlist_free - Free the private copy of the environment
40  */
mutt_envlist_free(void)41 void mutt_envlist_free(void)
42 {
43   if (!EnvList)
44     return;
45 
46   for (char **p = EnvList; p && *p; p++)
47     FREE(p);
48 
49   FREE(&EnvList);
50 }
51 
52 /**
53  * mutt_envlist_init - Create a copy of the environment
54  * @param envp Environment variables
55  */
mutt_envlist_init(char * envp[])56 void mutt_envlist_init(char *envp[])
57 {
58   if (EnvList)
59     mutt_envlist_free();
60 
61   if (!envp)
62     return;
63 
64   char **src = NULL, **dst = NULL;
65   int count = 0;
66   for (src = envp; src && *src; src++)
67     count++;
68 
69   EnvList = mutt_mem_calloc(count + 1, sizeof(char *));
70   for (src = envp, dst = EnvList; src && *src; src++, dst++)
71     *dst = mutt_str_dup(*src);
72 }
73 
74 /**
75  * mutt_envlist_set - Set an environment variable
76  * @param name      Name of the variable
77  * @param value     New value
78  * @param overwrite Should the variable be overwritten?
79  * @retval true  Success: variable set, or overwritten
80  * @retval false Variable exists and overwrite was false
81  *
82  * It's broken out because some other parts of neomutt (filter.c) need to
83  * set/overwrite environment variables in EnvList before calling exec().
84  */
mutt_envlist_set(const char * name,const char * value,bool overwrite)85 bool mutt_envlist_set(const char *name, const char *value, bool overwrite)
86 {
87   if (!name)
88     return false;
89 
90   char **envp = EnvList;
91   char work[1024];
92 
93   /* Look for current slot to overwrite */
94   int count = 0;
95   while (envp && *envp)
96   {
97     size_t len = mutt_str_startswith(*envp, name);
98     if ((len != 0) && ((*envp)[len] == '='))
99     {
100       if (!overwrite)
101         return false;
102       break;
103     }
104     envp++;
105     count++;
106   }
107 
108   /* Format var=value string */
109   snprintf(work, sizeof(work), "%s=%s", name, NONULL(value));
110 
111   if (envp && *envp)
112   {
113     /* slot found, overwrite */
114     mutt_str_replace(envp, work);
115   }
116   else
117   {
118     /* not found, add new slot */
119     mutt_mem_realloc(&EnvList, sizeof(char *) * (count + 2));
120     EnvList[count] = mutt_str_dup(work);
121     EnvList[count + 1] = NULL;
122   }
123   return true;
124 }
125 
126 /**
127  * mutt_envlist_unset - Unset an environment variable
128  * @param name Variable to unset
129  * @retval true  Success: Variable unset
130  * @retval false Error: Variable doesn't exist
131  */
mutt_envlist_unset(const char * name)132 bool mutt_envlist_unset(const char *name)
133 {
134   if (!name || (name[0] == '\0'))
135     return false;
136 
137   char **envp = EnvList;
138 
139   int count = 0;
140   while (envp && *envp)
141   {
142     size_t len = mutt_str_startswith(*envp, name);
143     if ((len != 0) && ((*envp)[len] == '='))
144     {
145       FREE(envp);
146       /* shuffle down */
147       char **save = envp++;
148       while (*envp)
149       {
150         *save++ = *envp++;
151         count++;
152       }
153       *save = NULL;
154       mutt_mem_realloc(&EnvList, sizeof(char *) * (count + 1));
155       return true;
156     }
157     envp++;
158     count++;
159   }
160   return false;
161 }
162 
163 /**
164  * mutt_envlist_getlist - Get the private environment
165  * @retval ptr Array of strings
166  *
167  * @note The caller must not free the strings
168  */
mutt_envlist_getlist(void)169 char **mutt_envlist_getlist(void)
170 {
171   return EnvList;
172 }
173