/* GNU Mailutils -- a suite of utilities for electronic mail Copyright (C) 2008-2019 Free Software Foundation, Inc. GNU Mailutils is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNU Mailutils is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Mailutils. If not, see . */ /* Implementation of ID extension (RFC 2971) */ #include "imap4d.h" #include mu_list_t imap4d_id_list; static int eat_args (imap4d_tokbuf_t tok) { int n = IMAP4_ARG_1; char *p; p = imap4d_tokbuf_getarg (tok, n++); if (!p) return RESP_BAD; if (mu_c_strcasecmp (p, "NIL") == 0) { if (imap4d_tokbuf_getarg (tok, n)) return RESP_BAD; return RESP_OK; } else if (p[0] != '(') return RESP_BAD; mu_diag_init (); mu_stream_printf (mu_strerr, "\033s<%d>%s", MU_DIAG_INFO, _("client identification: ")); /* Collect arguments */ while ((p = imap4d_tokbuf_getarg (tok, n++))) { if (p[0] == ')') { mu_stream_printf (mu_strerr, "\n"); if (imap4d_tokbuf_getarg (tok, n)) return RESP_BAD; return RESP_OK; } mu_stream_printf (mu_strerr, "%s%c", p, (n % 2) ? ' ' : '='); } mu_stream_printf (mu_strerr, "\n"); return RESP_BAD; } struct id_value { char *name; char *value; const char *(*fun) (struct id_value *idv); }; static const char * get_os (struct id_value *idv) { struct utsname uts; uname(&uts); return idv->value = mu_strdup (uts.sysname); } static const char * get_os_version (struct id_value *idv) { struct utsname uts; uname(&uts); return idv->value = mu_strdup (uts.version); } static const char * get_command (struct id_value *idv MU_ARG_UNUSED) { return mu_program_name; } static char * build_str (char **argv) { size_t size = 0; int i, j; char *buf, *p; for (j = 0; argv[j]; j++) { size_t len = strlen (argv[j]); if (size + len + 1 > 1024) break; size += len + 1; } buf = mu_alloc (size); for (i = 0, p = buf; argv[i];) { strcpy (p, argv[i]); p += strlen (p); if (++i < j) *p++ = ' '; else break; } *p = 0; return buf; } static const char * get_arguments (struct id_value *idv) { return idv->value = build_str (imap4d_argv + 1); } static const char * get_environment (struct id_value *idv) { extern char **environ; return idv->value = build_str (environ); } static struct id_value id_tab[] = { { "name", PACKAGE_NAME }, { "version", PACKAGE_VERSION }, { "vendor", "GNU" }, { "support-url", "http://www.gnu.org/software/mailutils" }, { "address", "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA" }, #if 0 /* FIXME */ { "date", NULL }, #endif { "os", NULL, get_os }, { "os-version", NULL, get_os_version }, { "command", NULL, get_command }, { "arguments", NULL, get_arguments }, { "environment", NULL, get_environment }, { NULL } }; static const char * get_id_value (const char *name) { struct id_value *idv; const char *val = NULL; for (idv = id_tab; idv->name; idv++) { if (strcmp (idv->name, name) == 0) { if (idv->value) val = idv->value; else if (idv->fun) val = idv->fun (idv); break; } } return val; } int imap4d_id (struct imap4d_session *session, struct imap4d_command *command, imap4d_tokbuf_t tok) { int rc = eat_args (tok); if (rc != RESP_OK) return io_completion_response (command, rc, "Syntax error"); if (imap4d_id_list) { mu_iterator_t itr; int i; int outcnt = 0; mu_list_get_iterator (imap4d_id_list, &itr); for (i = 0, mu_iterator_first (itr); i < 30 && !mu_iterator_is_done (itr); i++, mu_iterator_next (itr)) { const char *p, *q; size_t len; mu_iterator_current (itr, (void**)&p); len = strcspn (p, "="); if (p[len]) q = p + len + 1; else q = get_id_value (p); if (q) { if (outcnt++ == 0) io_sendf ("* ID ("); else io_sendf (" "); io_sendf ("\"%*.*s\" \"%s\"", (int) len, (int) len, p, q); } } mu_iterator_destroy (&itr); if (outcnt) io_sendf (")\n"); } return io_completion_response (command, RESP_OK, "Completed"); }