• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

neomutt / neomutt / 17538805566

06 Sep 2025 08:16PM UTC coverage: 50.104% (+0.005%) from 50.099%
17538805566

push

github

web-flow
Revamp the S/MIME docs (#4665)

* the smime.rc have been re-imported from the neomutt-contrib repo, since smime-notes.txt was referring to it
* all S/MIME related files have been placed in a new smime directory, to improve discoverability
* I have verified / modernized / clarified smime-notes.txt

9132 of 18226 relevant lines covered (50.1%)

272.39 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

22.48
/parse/extract.c
1
/**
2
 * @file
3
 * Text parser
4
 *
5
 * @authors
6
 * Copyright (C) 2019 Naveen Nathan <naveen@lastninja.net>
7
 * Copyright (C) 2019-2023 Richard Russon <rich@flatcap.org>
8
 * Copyright (C) 2020 Pietro Cerutti <gahr@gahr.ch>
9
 *
10
 * @copyright
11
 * This program is free software: you can redistribute it and/or modify it under
12
 * the terms of the GNU General Public License as published by the Free Software
13
 * Foundation, either version 2 of the License, or (at your option) any later
14
 * version.
15
 *
16
 * This program is distributed in the hope that it will be useful, but WITHOUT
17
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
19
 * details.
20
 *
21
 * You should have received a copy of the GNU General Public License along with
22
 * this program.  If not, see <http://www.gnu.org/licenses/>.
23
 */
24

25
/**
26
 * @page parse_extract Text parser
27
 *
28
 * Text parser
29
 */
30

31
#include "config.h"
32
#include <stdio.h>
33
#include <string.h>
34
#include <sys/types.h>
35
#include "mutt/lib.h"
36
#include "config/lib.h"
37
#include "core/lib.h"
38
#include "extract.h"
39

40
/**
41
 * parse_extract_token - Extract one token from a string
42
 * @param dest  Buffer for the result
43
 * @param tok   Buffer containing tokens
44
 * @param flags Flags, see #TokenFlags
45
 * @retval  0 Success
46
 * @retval -1 Error
47
 */
48
int parse_extract_token(struct Buffer *dest, struct Buffer *tok, TokenFlags flags)
1,205✔
49
{
50
  if (!dest || !tok)
1,205✔
51
    return -1;
52

53
  char ch;
54
  char qc = '\0'; /* quote char */
55
  char *pc = NULL;
56

57
  buf_reset(dest);
1,204✔
58

59
  SKIPWS(tok->dptr);
1,217✔
60
  while ((ch = *tok->dptr))
7,621✔
61
  {
62
    if (qc == '\0')
7,385✔
63
    {
64
      if (mutt_isspace(ch) && !(flags & TOKEN_SPACE))
7,384✔
65
        break;
66
      if ((ch == '#') && !(flags & TOKEN_COMMENT))
6,632✔
67
        break;
68
      if ((ch == '+') && (flags & TOKEN_PLUS))
6,632✔
69
        break;
70
      if ((ch == '-') && (flags & TOKEN_MINUS))
6,629✔
71
        break;
72
      if ((ch == '=') && (flags & TOKEN_EQUAL))
6,628✔
73
        break;
74
      if ((ch == '?') && (flags & TOKEN_QUESTION))
6,532✔
75
        break;
76
      if ((ch == ';') && !(flags & TOKEN_SEMICOLON))
6,418✔
77
        break;
78
      if ((flags & TOKEN_PATTERN) && strchr("~%=!|", ch))
6,418✔
79
        break;
80
    }
81

82
    tok->dptr++;
6,418✔
83

84
    if (ch == qc)
6,418✔
85
    {
86
      qc = 0; /* end of quote */
87
    }
88
    else if (!qc && ((ch == '\'') || (ch == '"')) && !(flags & TOKEN_QUOTE))
6,417✔
89
    {
90
      qc = ch;
91
    }
92
    else if ((ch == '\\') && (qc != '\''))
6,416✔
93
    {
94
      if (tok->dptr[0] == '\0')
×
95
        return -1; /* premature end of token */
96
      switch (ch = *tok->dptr++)
×
97
      {
98
        case 'c':
×
99
        case 'C':
100
          if (tok->dptr[0] == '\0')
×
101
            return -1; /* premature end of token */
102
          buf_addch(dest, (mutt_toupper(tok->dptr[0]) - '@') & 0x7f);
×
103
          tok->dptr++;
×
104
          break;
×
105
        case 'e':
×
106
          buf_addch(dest, '\033'); // Escape
×
107
          break;
×
108
        case 'f':
×
109
          buf_addch(dest, '\f');
×
110
          break;
×
111
        case 'n':
×
112
          buf_addch(dest, '\n');
×
113
          break;
×
114
        case 'r':
×
115
          buf_addch(dest, '\r');
×
116
          break;
×
117
        case 't':
×
118
          buf_addch(dest, '\t');
×
119
          break;
×
120
        default:
×
121
          if (mutt_isdigit(ch) && mutt_isdigit(tok->dptr[0]) && mutt_isdigit(tok->dptr[1]))
×
122
          {
123
            buf_addch(dest, (ch << 6) + (tok->dptr[0] << 3) + tok->dptr[1] - 3504);
×
124
            tok->dptr += 2;
×
125
          }
126
          else
127
          {
128
            buf_addch(dest, ch);
×
129
          }
130
      }
131
    }
132
    else if ((ch == '^') && (flags & TOKEN_CONDENSE))
6,416✔
133
    {
134
      if (tok->dptr[0] == '\0')
×
135
        return -1; /* premature end of token */
136
      ch = *tok->dptr++;
×
137
      if (ch == '^')
×
138
      {
139
        buf_addch(dest, ch);
×
140
      }
141
      else if (ch == '[')
×
142
      {
143
        buf_addch(dest, '\033'); // Escape
×
144
      }
145
      else if (mutt_isalpha(ch))
×
146
      {
147
        buf_addch(dest, mutt_toupper(ch) - '@');
×
148
      }
149
      else
150
      {
151
        buf_addch(dest, '^');
×
152
        buf_addch(dest, ch);
×
153
      }
154
    }
155
    else if ((ch == '`') && (!qc || (qc == '"')))
6,416✔
156
    {
×
157
      FILE *fp = NULL;
1✔
158
      pid_t pid;
159

160
      pc = tok->dptr;
161
      do
162
      {
163
        pc = strpbrk(pc, "\\`");
1✔
164
        if (pc)
1✔
165
        {
166
          /* skip any quoted chars */
167
          if (*pc == '\\')
×
168
          {
169
            if (*(pc + 1))
×
170
              pc += 2;
×
171
            else
172
              pc = NULL;
173
          }
174
        }
175
      } while (pc && (pc[0] != '`'));
×
176
      if (!pc)
1✔
177
      {
178
        mutt_debug(LL_DEBUG1, "mismatched backticks\n");
1✔
179
        return -1;
1✔
180
      }
181
      struct Buffer *cmd = buf_pool_get();
×
182
      *pc = '\0';
×
183
      if (flags & TOKEN_BACKTICK_VARS)
×
184
      {
185
        /* recursively extract tokens to interpolate variables */
186
        parse_extract_token(cmd, tok,
×
187
                            TOKEN_QUOTE | TOKEN_SPACE | TOKEN_COMMENT |
188
                                TOKEN_SEMICOLON | TOKEN_NOSHELL);
189
      }
190
      else
191
      {
192
        buf_strcpy(cmd, tok->dptr);
×
193
      }
194
      *pc = '`';
×
195
      pid = filter_create(buf_string(cmd), NULL, &fp, NULL, NeoMutt->env);
×
196
      if (pid < 0)
×
197
      {
198
        mutt_debug(LL_DEBUG1, "unable to fork command: %s\n", buf_string(cmd));
×
199
        buf_pool_release(&cmd);
×
200
        return -1;
×
201
      }
202

203
      tok->dptr = pc + 1;
×
204

205
      /* read line */
206
      char *expn = NULL;
×
207
      size_t expn_len = 0;
×
208
      expn = mutt_file_read_line(expn, &expn_len, fp, NULL, MUTT_RL_NO_FLAGS);
×
209
      mutt_file_fclose(&fp);
×
210
      int rc = filter_wait(pid);
×
211
      if (rc != 0)
×
212
      {
213
        mutt_debug(LL_DEBUG1, "backticks exited code %d for command: %s\n", rc,
×
214
                   buf_string(cmd));
215
      }
216
      buf_pool_release(&cmd);
×
217

218
      /* if we got output, make a new string consisting of the shell output
219
       * plus whatever else was left on the original line */
220
      /* BUT: If this is inside a quoted string, directly add output to
221
       * the token */
222
      if (expn)
×
223
      {
224
        if (qc)
×
225
        {
226
          buf_addstr(dest, expn);
×
227
        }
228
        else
229
        {
230
          struct Buffer *copy = buf_pool_get();
×
231
          buf_strcpy(copy, expn);
×
232
          buf_addstr(copy, tok->dptr);
×
233
          buf_copy(tok, copy);
×
234
          buf_seek(tok, 0);
×
235
          buf_pool_release(&copy);
×
236
        }
237
        FREE(&expn);
×
238
      }
239
    }
240
    else if ((ch == '$') && (!qc || (qc == '"')) &&
6,415✔
241
             ((tok->dptr[0] == '{') || mutt_isalpha(tok->dptr[0])))
×
242
    {
×
243
      const char *env = NULL;
244
      char *var = NULL;
×
245

246
      if (tok->dptr[0] == '{')
×
247
      {
248
        pc = strchr(tok->dptr, '}');
×
249
        if (pc)
×
250
        {
251
          var = mutt_strn_dup(tok->dptr + 1, pc - (tok->dptr + 1));
×
252
          tok->dptr = pc + 1;
×
253

254
          if ((flags & TOKEN_NOSHELL))
×
255
          {
256
            buf_addch(dest, ch);
×
257
            buf_addch(dest, '{');
×
258
            buf_addstr(dest, var);
×
259
            buf_addch(dest, '}');
×
260
            FREE(&var);
×
261
          }
262
        }
263
      }
264
      else
265
      {
266
        for (pc = tok->dptr; mutt_isalnum(*pc) || (pc[0] == '_'); pc++)
×
267
          ; // do nothing
268

269
        var = mutt_strn_dup(tok->dptr, pc - tok->dptr);
×
270
        tok->dptr = pc;
×
271
      }
272
      if (var)
×
273
      {
274
        struct Buffer *result = buf_pool_get();
×
275
        int rc = cs_subset_str_string_get(NeoMutt->sub, var, result);
×
276

277
        if (CSR_RESULT(rc) == CSR_SUCCESS)
×
278
        {
279
          buf_addstr(dest, buf_string(result));
×
280
        }
281
        else if (!(flags & TOKEN_NOSHELL) && (env = mutt_str_getenv(var)))
×
282
        {
283
          buf_addstr(dest, env);
×
284
        }
285
        else
286
        {
287
          buf_addch(dest, ch);
×
288
          buf_addstr(dest, var);
×
289
        }
290
        FREE(&var);
×
291
        buf_pool_release(&result);
×
292
      }
293
    }
294
    else
295
    {
296
      buf_addch(dest, ch);
6,415✔
297
    }
298
  }
299

300
  SKIPWS(tok->dptr);
1,955✔
301
  return 0;
302
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc