1 /**
2 * @file
3 * Display version and copyright about NeoMutt
4 *
5 * @authors
6 * Copyright (C) 1996-2007 Michael R. Elkins <me@mutt.org>
7 * Copyright (C) 1999-2007 Thomas Roessler <roessler@does-not-exist.org>
8 * Copyright (C) 2016-2017 Richard Russon <rich@flatcap.org>
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 neo_version Display version and copyright about NeoMutt
27 *
28 * Display version and copyright about NeoMutt
29 */
30
31 #include "config.h"
32 #include <errno.h>
33 #include <stdbool.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <sys/utsname.h>
37 #include <unistd.h>
38 #include "mutt/lib.h"
39 #include "gui/lib.h" // IWYU pragma: keep
40 #include "version.h"
41 #include "compress/lib.h"
42 #ifdef HAVE_LIBIDN
43 #include "address/lib.h"
44 #endif
45 #ifdef CRYPT_BACKEND_GPGME
46 #include "ncrypt/lib.h"
47 #endif
48 #ifdef HAVE_NOTMUCH
49 #include <notmuch.h>
50 #endif
51 #ifdef USE_SSL_OPENSSL
52 #include <openssl/opensslv.h>
53 #endif
54 #ifdef USE_SSL_GNUTLS
55 #include <gnutls/gnutls.h>
56 #endif
57 #ifdef HAVE_PCRE2
58 #define PCRE2_CODE_UNIT_WIDTH 8
59 #include <pcre2.h>
60 #endif
61
62 /* #include "muttlib.h" */
63 const char *mutt_make_version(void);
64 /* #include "store/lib.h" */
65 const char *store_backend_list(void);
66 const char *store_compress_list(void);
67
68 const int SCREEN_WIDTH = 80;
69
70 extern unsigned char cc_cflags[];
71 extern unsigned char configure_options[];
72
73 static const char *Copyright =
74 "Copyright (C) 1996-2020 Michael R. Elkins <me@mutt.org>\n"
75 "Copyright (C) 1996-2002 Brandon Long <blong@fiction.net>\n"
76 "Copyright (C) 1997-2009 Thomas Roessler <roessler@does-not-exist.org>\n"
77 "Copyright (C) 1998-2005 Werner Koch <wk@isil.d.shuttle.de>\n"
78 "Copyright (C) 1999-2017 Brendan Cully <brendan@kublai.com>\n"
79 "Copyright (C) 1999-2002 Tommi Komulainen <Tommi.Komulainen@iki.fi>\n"
80 "Copyright (C) 2000-2004 Edmund Grimley Evans <edmundo@rano.org>\n"
81 "Copyright (C) 2006-2009 Rocco Rutte <pdmef@gmx.net>\n"
82 "Copyright (C) 2014-2020 Kevin J. McCarthy <kevin@8t8.us>\n"
83 "Copyright (C) 2015-2020 Richard Russon <rich@flatcap.org>\n";
84
85 static const char *Thanks =
86 N_("Many others not mentioned here contributed code, fixes,\n"
87 "and suggestions.\n");
88
89 static const char *License = N_(
90 " This program is free software; you can redistribute it and/or modify\n"
91 " it under the terms of the GNU General Public License as published by\n"
92 " the Free Software Foundation; either version 2 of the License, or\n"
93 " (at your option) any later version.\n"
94 "\n"
95 " This program is distributed in the hope that it will be useful,\n"
96 " but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
97 " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
98 " GNU General Public License for more details.\n"
99 "\n"
100 " You should have received a copy of the GNU General Public License\n"
101 " along with this program; if not, write to the Free Software\n"
102 " Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA "
103 "02110-1301, USA.\n");
104
105 static const char *ReachingUs =
106 N_("To learn more about NeoMutt, visit: https://neomutt.org\n"
107 "If you find a bug in NeoMutt, please raise an issue at:\n"
108 " https://github.com/neomutt/neomutt/issues\n"
109 "or send an email to: <neomutt-devel@neomutt.org>\n");
110
111 // clang-format off
112 static const char *Notice =
113 N_("Copyright (C) 1996-2020 Michael R. Elkins and others.\n"
114 "NeoMutt comes with ABSOLUTELY NO WARRANTY; for details type 'neomutt -vv'.\n"
115 "NeoMutt is free software, and you are welcome to redistribute it\n"
116 "under certain conditions; type 'neomutt -vv' for details.\n");
117 // clang-format on
118
119 /**
120 * struct CompileOptions - List of built-in capabilities
121 */
122 struct CompileOptions
123 {
124 const char *name; ///< Option name
125 int enabled; ///< 0 Disabled, 1 Enabled, 2 Devel only
126 };
127
128 /* These are sorted by the display string */
129
130 static struct CompileOptions comp_opts_default[] = {
131 { "attach_headers_color", 1 },
132 { "compose_to_sender", 1 },
133 { "compress", 1 },
134 { "cond_date", 1 },
135 { "debug", 1 },
136 { "encrypt_to_self", 1 },
137 { "forgotten_attachments", 1 },
138 { "forwref", 1 },
139 { "ifdef", 1 },
140 { "imap", 1 },
141 { "index_color", 1 },
142 { "initials", 1 },
143 { "limit_current_thread", 1 },
144 { "multiple_fcc", 1 },
145 { "nested_if", 1 },
146 { "new_mail", 1 },
147 { "nntp", 1 },
148 { "pop", 1 },
149 { "progress", 1 },
150 { "quasi_delete", 1 },
151 { "regcomp", 1 },
152 { "reply_with_xorig", 1 },
153 { "sensible_browser", 1 },
154 { "sidebar", 1 },
155 { "skip_quoted", 1 },
156 { "smtp", 1 },
157 { "status_color", 1 },
158 { "timeout", 1 },
159 { "tls_sni", 1 },
160 { "trash", 1 },
161 { NULL, 0 },
162 };
163
164 static struct CompileOptions comp_opts[] = {
165 #ifdef USE_AUTOCRYPT
166 { "autocrypt", 1 },
167 #else
168 { "autocrypt", 0 },
169 #endif
170 #ifdef USE_FCNTL
171 { "fcntl", 1 },
172 #else
173 { "fcntl", 0 },
174 #endif
175 #ifdef USE_FLOCK
176 { "flock", 1 },
177 #else
178 { "flock", 0 },
179 #endif
180 #ifdef USE_FMEMOPEN
181 { "fmemopen", 1 },
182 #else
183 { "fmemopen", 0 },
184 #endif
185 #ifdef HAVE_FUTIMENS
186 { "futimens", 1 },
187 #else
188 { "futimens", 0 },
189 #endif
190 #ifdef HAVE_GETADDRINFO
191 { "getaddrinfo", 1 },
192 #else
193 { "getaddrinfo", 0 },
194 #endif
195 #ifdef USE_SSL_GNUTLS
196 { "gnutls", 1 },
197 #else
198 { "gnutls", 0 },
199 #endif
200 #ifdef CRYPT_BACKEND_GPGME
201 { "gpgme", 1 },
202 #else
203 { "gpgme", 0 },
204 #endif
205 #ifdef USE_GSS
206 { "gss", 1 },
207 #else
208 { "gss", 0 },
209 #endif
210 #ifdef USE_HCACHE
211 { "hcache", 1 },
212 #else
213 { "hcache", 0 },
214 #endif
215 #ifdef HOMESPOOL
216 { "homespool", 1 },
217 #else
218 { "homespool", 0 },
219 #endif
220 #ifdef HAVE_LIBIDN
221 { "idn", 1 },
222 #else
223 { "idn", 0 },
224 #endif
225 #ifdef USE_INOTIFY
226 { "inotify", 1 },
227 #else
228 { "inotify", 0 },
229 #endif
230 #ifdef LOCALES_HACK
231 { "locales_hack", 1 },
232 #else
233 { "locales_hack", 0 },
234 #endif
235 #ifdef USE_LUA
236 { "lua", 1 },
237 #else
238 { "lua", 0 },
239 #endif
240 #ifdef MIXMASTER
241 { "mixmaster", 1 },
242 #else
243 { "mixmaster", 0 },
244 #endif
245 #ifdef ENABLE_NLS
246 { "nls", 1 },
247 #else
248 { "nls", 0 },
249 #endif
250 #ifdef USE_NOTMUCH
251 { "notmuch", 1 },
252 #else
253 { "notmuch", 0 },
254 #endif
255 #ifdef USE_SSL_OPENSSL
256 { "openssl", 1 },
257 #else
258 { "openssl", 0 },
259 #endif
260 #ifdef HAVE_PCRE2
261 { "pcre2", 1 },
262 #endif
263 #ifdef CRYPT_BACKEND_CLASSIC_PGP
264 { "pgp", 1 },
265 #else
266 { "pgp", 0 },
267 #endif
268 #ifndef HAVE_PCRE2
269 { "regex", 1 },
270 #endif
271 #ifdef USE_SASL
272 { "sasl", 1 },
273 #else
274 { "sasl", 0 },
275 #endif
276 #ifdef CRYPT_BACKEND_CLASSIC_SMIME
277 { "smime", 1 },
278 #else
279 { "smime", 0 },
280 #endif
281 #ifdef USE_SQLITE
282 { "sqlite", 1 },
283 #else
284 { "sqlite", 0 },
285 #endif
286 #ifdef SUN_ATTACHMENT
287 { "sun_attachment", 1 },
288 #else
289 { "sun_attachment", 0 },
290 #endif
291 { NULL, 0 },
292 };
293
294 static struct CompileOptions debug_opts[] = {
295 #ifdef USE_ASAN
296 { "asan", 2 },
297 #endif
298 #ifdef HAVE_LIBUNWIND
299 { "backtrace", 2 },
300 #endif
301 #ifdef USE_DEBUG_GRAPHVIZ
302 { "graphviz", 2 },
303 #endif
304 #ifdef USE_DEBUG_NOTIFY
305 { "notify", 2 },
306 #endif
307 #ifdef USE_DEBUG_PARSE_TEST
308 { "parse-test", 2 },
309 #endif
310 #ifdef USE_DEBUG_WINDOW
311 { "window", 2 },
312 #endif
313 { NULL, 0 },
314 };
315
316 /**
317 * print_compile_options - Print a list of enabled/disabled features
318 * @param co Array of compile options
319 * @param fp file to write to
320 *
321 * Two lists are generated and passed to this function:
322 *
323 * One list which just uses the configure state of each feature.
324 * One list which just uses feature which are set to on directly in NeoMutt.
325 *
326 * The output is of the form: "+enabled_feature -disabled_feature" and is
327 * wrapped to SCREEN_WIDTH characters.
328 */
print_compile_options(struct CompileOptions * co,FILE * fp)329 static void print_compile_options(struct CompileOptions *co, FILE *fp)
330 {
331 if (!co || !fp)
332 return;
333
334 size_t used = 2;
335 bool tty = isatty(fileno(fp));
336
337 fprintf(fp, " ");
338 for (int i = 0; co[i].name; i++)
339 {
340 const size_t len = strlen(co[i].name) + 2; /* +/- and a space */
341 if ((used + len) > SCREEN_WIDTH)
342 {
343 used = 2;
344 fprintf(fp, "\n ");
345 }
346 used += len;
347 const char *fmt = "?%s ";
348 switch (co[i].enabled)
349 {
350 case 0: // Disabled
351 if (tty)
352 fmt = "\033[1;31m-%s\033[0m "; // Escape, red
353 else
354 fmt = "-%s ";
355 break;
356 case 1: // Enabled
357 if (tty)
358 fmt = "\033[1;32m+%s\033[0m "; // Escape, green
359 else
360 fmt = "+%s ";
361 break;
362 case 2: // Devel only
363 if (tty)
364 fmt = "\033[1;36m%s\033[0m "; // Escape, cyan
365 else
366 fmt = "%s ";
367 break;
368 }
369 fprintf(fp, fmt, co[i].name);
370 }
371 fprintf(fp, "\n");
372 }
373
374 /**
375 * rstrip_in_place - Strip a trailing carriage return
376 * @param s String to be modified
377 * @retval ptr The modified string
378 *
379 * The string has its last carriage return set to NUL.
380 */
rstrip_in_place(char * s)381 static char *rstrip_in_place(char *s)
382 {
383 if (!s)
384 return NULL;
385
386 char *p = &s[strlen(s)];
387 if (p == s)
388 return s;
389 p--;
390 while ((p >= s) && ((*p == '\n') || (*p == '\r')))
391 *p-- = '\0';
392 return s;
393 }
394
395 /**
396 * print_version - Print system and compile info to a file
397 * @param fp File to print to
398 * @retval true Text displayed
399 *
400 * Print information about the current system NeoMutt is running on.
401 * Also print a list of all the compile-time information.
402 */
print_version(FILE * fp)403 bool print_version(FILE *fp)
404 {
405 if (!fp)
406 return false;
407
408 struct utsname uts;
409 bool tty = isatty(fileno(fp));
410 const char *fmt = "%s\n";
411
412 if (tty)
413 fmt = "\033[1;36m%s\033[0m\n"; // Escape, cyan
414
415 fprintf(fp, fmt, mutt_make_version());
416 fprintf(fp, "%s\n", _(Notice));
417
418 uname(&uts);
419
420 #ifdef SCO
421 fprintf(fp, "System: SCO %s", uts.release);
422 #else
423 fprintf(fp, "System: %s %s", uts.sysname, uts.release);
424 #endif
425
426 fprintf(fp, " (%s)", uts.machine);
427
428 fprintf(fp, "\nncurses: %s (compiled with %s.%d)", curses_version(),
429 NCURSES_VERSION, NCURSES_VERSION_PATCH);
430
431 #ifdef _LIBICONV_VERSION
432 fprintf(fp, "\nlibiconv: %d.%d", _LIBICONV_VERSION >> 8, _LIBICONV_VERSION & 0xff);
433 #endif
434
435 #ifdef HAVE_LIBIDN
436 fprintf(fp, "\n%s", mutt_idna_print_version());
437 #endif
438
439 #ifdef CRYPT_BACKEND_GPGME
440 fprintf(fp, "\nGPGME: %s", mutt_gpgme_print_version());
441 #endif
442
443 #ifdef USE_SSL_OPENSSL
444 #ifdef LIBRESSL_VERSION_TEXT
445 fprintf(fp, "\nLibreSSL: %s", LIBRESSL_VERSION_TEXT);
446 #endif
447 #ifdef OPENSSL_VERSION_TEXT
448 fprintf(fp, "\nOpenSSL: %s", OPENSSL_VERSION_TEXT);
449 #endif
450 #endif
451
452 #ifdef USE_SSL_GNUTLS
453 fprintf(fp, "\nGnuTLS: %s", GNUTLS_VERSION);
454 #endif
455
456 #ifdef HAVE_NOTMUCH
457 fprintf(fp, "\nlibnotmuch: %d.%d.%d", LIBNOTMUCH_MAJOR_VERSION,
458 LIBNOTMUCH_MINOR_VERSION, LIBNOTMUCH_MICRO_VERSION);
459 #endif
460
461 #ifdef HAVE_PCRE2
462 {
463 char version[24];
464 pcre2_config(PCRE2_CONFIG_VERSION, version);
465 fprintf(fp, "\nPCRE2: %s", version);
466 }
467 #endif
468
469 #ifdef USE_HCACHE
470 const char *backends = store_backend_list();
471 fprintf(fp, "\nstorage: %s", backends);
472 FREE(&backends);
473 #ifdef USE_HCACHE_COMPRESSION
474 backends = compress_list();
475 fprintf(fp, "\ncompression: %s", backends);
476 FREE(&backends);
477 #endif
478 #endif
479
480 rstrip_in_place((char *) configure_options);
481 fprintf(fp, "\n\nConfigure options: %s\n", (char *) configure_options);
482
483 rstrip_in_place((char *) cc_cflags);
484 fprintf(fp, "\nCompilation CFLAGS: %s\n", (char *) cc_cflags);
485
486 fprintf(fp, "\n%s\n", _("Default options:"));
487 print_compile_options(comp_opts_default, fp);
488
489 fprintf(fp, "\n%s\n", _("Compile options:"));
490 print_compile_options(comp_opts, fp);
491
492 if (debug_opts[0].name)
493 {
494 fprintf(fp, "\n%s\n", _("Debug options:"));
495 print_compile_options(debug_opts, fp);
496 }
497
498 fprintf(fp, "\n");
499 #ifdef DOMAIN
500 fprintf(fp, "DOMAIN=\"%s\"\n", DOMAIN);
501 #endif
502 #ifdef ISPELL
503 fprintf(fp, "ISPELL=\"%s\"\n", ISPELL);
504 #endif
505 fprintf(fp, "MAILPATH=\"%s\"\n", MAILPATH);
506 #ifdef MIXMASTER
507 fprintf(fp, "MIXMASTER=\"%s\"\n", MIXMASTER);
508 #endif
509 fprintf(fp, "PKGDATADIR=\"%s\"\n", PKGDATADIR);
510 fprintf(fp, "SENDMAIL=\"%s\"\n", SENDMAIL);
511 fprintf(fp, "SYSCONFDIR=\"%s\"\n", SYSCONFDIR);
512
513 fprintf(fp, "\n");
514 fputs(_(ReachingUs), fp);
515
516 fflush(fp);
517 return !ferror(fp);
518 }
519
520 /**
521 * print_copyright - Print copyright message
522 * @retval true Text displayed
523 *
524 * Print the authors' copyright messages, the GPL license and some contact
525 * information for the NeoMutt project.
526 */
print_copyright(void)527 bool print_copyright(void)
528 {
529 puts(mutt_make_version());
530 puts(Copyright);
531 puts(_(Thanks));
532 puts(_(License));
533 puts(_(ReachingUs));
534
535 fflush(stdout);
536 return !ferror(stdout);
537 }
538
539 /**
540 * feature_enabled - Test if a compile-time feature is enabled
541 * @param name Compile-time symbol of the feature
542 * @retval true Feature enabled
543 * @retval false Feature not enabled, or not compiled in
544 *
545 * Many of the larger features of neomutt can be disabled at compile time.
546 * They define a symbol and use ifdef's around their code.
547 * The symbols are mirrored in "CompileOptions comp_opts[]" in this
548 * file.
549 *
550 * This function checks if one of these symbols is present in the code.
551 *
552 * These symbols are also seen in the output of "neomutt -v".
553 */
feature_enabled(const char * name)554 bool feature_enabled(const char *name)
555 {
556 if (!name)
557 return false;
558 for (int i = 0; comp_opts_default[i].name; i++)
559 {
560 if (mutt_str_equal(name, comp_opts_default[i].name))
561 {
562 return true;
563 }
564 }
565 for (int i = 0; comp_opts[i].name; i++)
566 {
567 if (mutt_str_equal(name, comp_opts[i].name))
568 {
569 return comp_opts[i].enabled;
570 }
571 }
572 return false;
573 }
574