Beispiel #1
0
/* enter a mutt command */
void mutt_enter_command (void)
{
  BUFFER err, token;
  char buffer[LONG_STRING];
  int r;

  buffer[0] = 0;
  if (mutt_get_field (":", buffer, sizeof (buffer), M_COMMAND) != 0 || !buffer[0])
    return;
  mutt_buffer_init (&err);
  err.dsize = STRING;
  err.data = safe_malloc(err.dsize);
  mutt_buffer_init (&token);
  r = mutt_parse_rc_line (buffer, &token, &err);
  FREE (&token.data);
  if (err.data[0])
  {
    /* since errbuf could potentially contain printf() sequences in it,
       we must call mutt_error() in this fashion so that vsprintf()
       doesn't expect more arguments that we passed */
    if (r == 0)
      mutt_message ("%s", err.data);
    else
      mutt_error ("%s", err.data);
  }

  FREE (&err.data);
}
Beispiel #2
0
void mutt_message_hook (CONTEXT *ctx, HEADER *hdr, int type)
{
  BUFFER err, token;
  HOOK *hook;

  current_hook_type = type;

  mutt_buffer_init (&err);
  err.dsize = STRING;
  err.data = safe_malloc (err.dsize);
  mutt_buffer_init (&token);
  for (hook = Hooks; hook; hook = hook->next)
  {
    if(!hook->command)
      continue;

    if (hook->type & type)
      if ((mutt_pattern_exec (hook->pattern, 0, ctx, hdr) > 0) ^ hook->rx.not)
	if (mutt_parse_rc_line (hook->command, &token, &err) != 0)
	{
	  FREE (&token.data);
	  mutt_error ("%s", err.data);
	  mutt_sleep (1);
	  current_hook_type = 0;
	  FREE (&err.data);

	  return;
	}
  }
  FREE (&token.data);
  FREE (&err.data);

  current_hook_type = 0;
}
Beispiel #3
0
void config_address(void)
{
  struct Buffer err;
  mutt_buffer_init(&err);
  err.dsize = 256;
  err.data = mutt_mem_calloc(1, err.dsize);
  mutt_buffer_reset(&err);

  struct ConfigSet *cs = cs_new(30);

  address_init(cs);
  dont_fail = true;
  if (!cs_register_variables(cs, Vars, 0))
    return;
  dont_fail = false;

  cs_add_listener(cs, log_listener);

  set_list(cs);

  TEST_CHECK(test_initial_values(cs, &err));
  TEST_CHECK(test_string_set(cs, &err));
  TEST_CHECK(test_string_get(cs, &err));
  TEST_CHECK(test_native_set(cs, &err));
  TEST_CHECK(test_native_get(cs, &err));
  TEST_CHECK(test_reset(cs, &err));
  TEST_CHECK(test_validator(cs, &err));
  TEST_CHECK(test_inherit(cs, &err));

  cs_free(&cs);
  FREE(&err.data);
}
Beispiel #4
0
/**
 * cs_inherit_variable - Create in inherited config item
 * @param cs     Config items
 * @param parent HashElem of parent config item
 * @param name   Name of account-specific config item
 * @retval ptr New HashElem representing the inherited config item
 */
struct HashElem *cs_inherit_variable(const struct ConfigSet *cs,
                                     struct HashElem *parent, const char *name)
{
  if (!cs || !parent)
    return NULL; /* LCOV_EXCL_LINE */

  struct Buffer err;
  mutt_buffer_init(&err);
  err.dsize = 256;
  err.data = calloc(1, err.dsize);

  struct Inheritance *i = mutt_mem_calloc(1, sizeof(*i));
  i->parent = parent;
  i->name = mutt_str_strdup(name);

  struct HashElem *he = mutt_hash_typed_insert(cs->hash, i->name, DT_INHERITED, i);
  if (!he)
  {
    FREE(&i->name);
    FREE(&i);
  }

  FREE(&err.data);
  return he;
}
Beispiel #5
0
void mutt_account_hook (const char* url)
{
  /* parsing commands with URLs in an account hook can cause a recursive
   * call. We just skip processing if this occurs. Typically such commands
   * belong in a folder-hook -- perhaps we should warn the user. */
  static int inhook = 0;

  HOOK* hook;
  BUFFER token;
  BUFFER err;

  if (inhook)
    return;

  mutt_buffer_init (&err);
  err.dsize = STRING;
  err.data = safe_malloc (err.dsize);
  mutt_buffer_init (&token);

  for (hook = Hooks; hook; hook = hook->next)
  {
    if (! (hook->command && (hook->type & M_ACCOUNTHOOK)))
      continue;

    if ((regexec (hook->rx.rx, url, 0, NULL, 0) == 0) ^ hook->rx.not)
    {
      inhook = 1;

      if (mutt_parse_rc_line (hook->command, &token, &err) == -1)
      {
	FREE (&token.data);
	mutt_error ("%s", err.data);
	FREE (&err.data);
	mutt_sleep (1);

        inhook = 0;
	return;
      }

      inhook = 0;
    }
  }

  FREE (&token.data);
  FREE (&err.data);
}
Beispiel #6
0
/**
 * mutt_parse_icommand - Parse an informational command
 * @param line Command to execute
 * @param err  Buffer for error messages
 * @retval #MUTT_CMD_SUCCESS Success
 * @retval #MUTT_CMD_ERROR   Error (no message): command not found
 * @retval #MUTT_CMD_ERROR   Error with message: command failed
 * @retval #MUTT_CMD_WARNING Warning with message: command failed
 */
enum CommandResult mutt_parse_icommand(/* const */ char *line, struct Buffer *err)
{
  if (!line || !*line || !err)
    return MUTT_CMD_ERROR;

  enum CommandResult rc = MUTT_CMD_ERROR;

  struct Buffer expn, token;

  mutt_buffer_init(&expn);
  mutt_buffer_init(&token);

  expn.data = expn.dptr = line;
  expn.dsize = mutt_str_strlen(line);

  mutt_buffer_reset(err);

  SKIPWS(expn.dptr);
  while (*expn.dptr)
  {
    mutt_extract_token(&token, &expn, 0);
    for (size_t i = 0; ICommandList[i].name; i++)
    {
      if (mutt_str_strcmp(token.data, ICommandList[i].name) != 0)
        continue;

      rc = ICommandList[i].func(&token, &expn, ICommandList[i].data, err);
      if (rc != 0)
        goto finish;

      break; /* Continue with next command */
    }
  }

finish:
  if (expn.destroy)
    FREE(&expn.data);
  return rc;
}
Beispiel #7
0
void mutt_folder_hook (char *path)
{
  HOOK *tmp = Hooks;
  BUFFER err, token;

  current_hook_type = M_FOLDERHOOK;

  mutt_buffer_init (&err);
  err.dsize = STRING;
  err.data = safe_malloc (err.dsize);
  mutt_buffer_init (&token);
  for (; tmp; tmp = tmp->next)
  {
    if(!tmp->command)
      continue;

    if (tmp->type & M_FOLDERHOOK)
    {
      if ((regexec (tmp->rx.rx, path, 0, NULL, 0) == 0) ^ tmp->rx.not)
      {
	if (mutt_parse_rc_line (tmp->command, &token, &err) == -1)
	{
	  mutt_error ("%s", err.data);
	  FREE (&token.data);
	  mutt_sleep (1);	/* pause a moment to let the user see the error */
	  current_hook_type = 0;
	  FREE (&err.data);

	  return;
	}
      }
    }
  }
  FREE (&token.data);
  FREE (&err.data);
  
  current_hook_type = 0;
}
Beispiel #8
0
/* imap_new_idata: Allocate and initialise a new IMAP_DATA structure.
 *   Returns NULL on failure (no mem) */
IMAP_DATA* imap_new_idata (void)
{
  IMAP_DATA* idata = safe_calloc (1, sizeof (IMAP_DATA));

  if (!idata)
    return NULL;

  if (!(idata->cmdbuf = mutt_buffer_init (NULL)))
    FREE (&idata);

  idata->cmdslots = ImapPipelineDepth + 2;
  if (!(idata->cmds = safe_calloc(idata->cmdslots, sizeof(*idata->cmds))))
  {
    mutt_buffer_free(&idata->cmdbuf);
    FREE (&idata);
  }

  return idata;
}
Beispiel #9
0
/**
 * cs_register_variables - Register a set of config items
 * @param cs    Config items
 * @param vars  Variable definition
 * @param flags Flags, e.g. #CS_REG_DISABLED
 * @retval bool True, if all variables were registered successfully
 */
bool cs_register_variables(const struct ConfigSet *cs, struct ConfigDef vars[], int flags)
{
  if (!cs || !vars)
    return CSR_ERR_CODE; /* LCOV_EXCL_LINE */

  struct Buffer err;
  mutt_buffer_init(&err);
  err.dsize = 256;
  err.data = calloc(1, err.dsize);

  bool rc = true;

  for (size_t i = 0; vars[i].name; i++)
  {
    if (!reg_one_var(cs, &vars[i], &err))
    {
      mutt_debug(LL_DEBUG1, "%s\n", err.data);
      rc = false;
    }
  }

  FREE(&err.data);
  return rc;
}
Beispiel #10
0
int mutt_parse_hook (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
{
  HOOK *ptr;
  BUFFER command, pattern;
  int rc, not = 0;
  regex_t *rx = NULL;
  pattern_t *pat = NULL;
  char path[_POSIX_PATH_MAX];

  mutt_buffer_init (&pattern);
  mutt_buffer_init (&command);

  if (*s->dptr == '!')
  {
    s->dptr++;
    SKIPWS (s->dptr);
    not = 1;
  }

  mutt_extract_token (&pattern, s, 0);

  if (!MoreArgs (s))
  {
    strfcpy (err->data, _("too few arguments"), err->dsize);
    goto error;
  }

  mutt_extract_token (&command, s, (data & (M_FOLDERHOOK | M_SENDHOOK | M_SEND2HOOK | M_ACCOUNTHOOK | M_REPLYHOOK)) ?  M_TOKEN_SPACE : 0);

  if (!command.data)
  {
    strfcpy (err->data, _("too few arguments"), err->dsize);
    goto error;
  }

  if (MoreArgs (s))
  {
    strfcpy (err->data, _("too many arguments"), err->dsize);
    goto error;
  }

  if (data & (M_FOLDERHOOK | M_MBOXHOOK))
  {
    strfcpy (path, pattern.data, sizeof (path));
    _mutt_expand_path (path, sizeof (path), 1);
    FREE (&pattern.data);
    memset (&pattern, 0, sizeof (pattern));
    pattern.data = safe_strdup (path);
  }
  else if (DefaultHook && !(data & (M_CHARSETHOOK | M_ICONVHOOK | M_ACCOUNTHOOK))
           && (!WithCrypto || !(data & M_CRYPTHOOK))
      )
  {
    char tmp[HUGE_STRING];

    /* At this stage remain only message-hooks, reply-hooks, send-hooks,
     * send2-hooks, save-hooks, and fcc-hooks: All those allowing full
     * patterns. If given a simple regexp, we expand $default_hook.
     */
    strfcpy (tmp, pattern.data, sizeof (tmp));
    mutt_check_simple (tmp, sizeof (tmp), DefaultHook);
    FREE (&pattern.data);
    memset (&pattern, 0, sizeof (pattern));
    pattern.data = safe_strdup (tmp);
  }

  if (data & (M_MBOXHOOK | M_SAVEHOOK | M_FCCHOOK))
  {
    strfcpy (path, command.data, sizeof (path));
    mutt_expand_path (path, sizeof (path));
    FREE (&command.data);
    memset (&command, 0, sizeof (command));
    command.data = safe_strdup (path);
  }

  /* check to make sure that a matching hook doesn't already exist */
  for (ptr = Hooks; ptr; ptr = ptr->next)
  {
    if (ptr->type == data &&
	ptr->rx.not == not &&
	!mutt_strcmp (pattern.data, ptr->rx.pattern))
    {
      if (data & (M_FOLDERHOOK | M_SENDHOOK | M_SEND2HOOK | M_MESSAGEHOOK | M_ACCOUNTHOOK | M_REPLYHOOK))
      {
	/* these hooks allow multiple commands with the same
	 * pattern, so if we've already seen this pattern/command pair, just
	 * ignore it instead of creating a duplicate */
	if (!mutt_strcmp (ptr->command, command.data))
	{
	  FREE (&command.data);
	  FREE (&pattern.data);
	  return 0;
	}
      }
      else
      {
	/* other hooks only allow one command per pattern, so update the
	 * entry with the new command.  this currently does not change the
	 * order of execution of the hooks, which i think is desirable since
	 * a common action to perform is to change the default (.) entry
	 * based upon some other information. */
	FREE (&ptr->command);
	ptr->command = command.data;
	FREE (&pattern.data);
	return 0;
      }
    }
    if (!ptr->next)
      break;
  }

  if (data & (M_SENDHOOK | M_SEND2HOOK | M_SAVEHOOK | M_FCCHOOK | M_MESSAGEHOOK | M_REPLYHOOK))
  {
    if ((pat = mutt_pattern_comp (pattern.data,
	   (data & (M_SENDHOOK | M_SEND2HOOK | M_FCCHOOK)) ? 0 : M_FULL_MSG,
				  err)) == NULL)
      goto error;
  }
  else
  {
    /* Hooks not allowing full patterns: Check syntax of regexp */
    rx = safe_malloc (sizeof (regex_t));
#ifdef M_CRYPTHOOK
    if ((rc = REGCOMP (rx, NONULL(pattern.data), ((data & (M_CRYPTHOOK|M_CHARSETHOOK|M_ICONVHOOK)) ? REG_ICASE : 0))) != 0)
#else
    if ((rc = REGCOMP (rx, NONULL(pattern.data), (data & (M_CHARSETHOOK|M_ICONVHOOK)) ? REG_ICASE : 0)) != 0)
#endif /* M_CRYPTHOOK */
    {
      regerror (rc, rx, err->data, err->dsize);
      FREE (&rx);
      goto error;
    }
  }

  if (ptr)
  {
    ptr->next = safe_calloc (1, sizeof (HOOK));
    ptr = ptr->next;
  }
  else
    Hooks = ptr = safe_calloc (1, sizeof (HOOK));
  ptr->type = data;
  ptr->command = command.data;
  ptr->pattern = pat;
  ptr->rx.pattern = pattern.data;
  ptr->rx.rx = rx;
  ptr->rx.not = not;
  return 0;

error:
  FREE (&pattern.data);
  FREE (&command.data);
  return (-1);
}
Beispiel #11
0
void config_set(void)
{
  log_line(__func__);

  struct Buffer err;
  mutt_buffer_init(&err);
  err.dsize = 256;
  err.data = mutt_mem_calloc(1, err.dsize);
  mutt_buffer_reset(&err);

  struct ConfigSet *cs = cs_new(30);
  if (!TEST_CHECK(cs != NULL))
    return;

  cs_add_listener(cs, log_listener);
  cs_add_listener(cs, log_listener); /* dupe */
  cs_remove_listener(cs, log_listener);
  cs_remove_listener(cs, log_listener); /* non-existant */

  const struct ConfigSetType cst_dummy = {
    "dummy", NULL, NULL, NULL, NULL, NULL, NULL,
  };

  if (TEST_CHECK(!cs_register_type(cs, DT_STRING, &cst_dummy)))
  {
    TEST_MSG("Expected error\n");
  }
  else
  {
    TEST_MSG("This test should have failed\n");
    return;
  }

  const struct ConfigSetType cst_dummy2 = {
    "dummy2",         dummy_string_set, dummy_string_get, dummy_native_set,
    dummy_native_get, dummy_reset,      dummy_destroy,
  };

  if (TEST_CHECK(!cs_register_type(cs, 25, &cst_dummy2)))
  {
    TEST_MSG("Expected error\n");
  }
  else
  {
    TEST_MSG("This test should have failed\n");
    return;
  }

  bool_init(cs);
  bool_init(cs); /* second one should fail */

  if (TEST_CHECK(!cs_register_variables(cs, Vars, 0)))
  {
    TEST_MSG("Expected error\n");
  }
  else
  {
    TEST_MSG("This test should have failed\n");
    return;
  }

  const char *name = "Unknown";
  int result = cs_str_string_set(cs, name, "hello", &err);
  if (TEST_CHECK(CSR_RESULT(result) == CSR_ERR_UNKNOWN))
  {
    TEST_MSG("Expected error: Unknown var '%s'\n", name);
  }
  else
  {
    TEST_MSG("This should have failed 1\n");
    return;
  }

  result = cs_str_string_get(cs, name, &err);
  if (TEST_CHECK(CSR_RESULT(result) == CSR_ERR_UNKNOWN))
  {
    TEST_MSG("Expected error: Unknown var '%s'\n", name);
  }
  else
  {
    TEST_MSG("This should have failed 2\n");
    return;
  }

  result = cs_str_native_set(cs, name, IP "hello", &err);
  if (TEST_CHECK(CSR_RESULT(result) == CSR_ERR_UNKNOWN))
  {
    TEST_MSG("Expected error: Unknown var '%s'\n", name);
  }
  else
  {
    TEST_MSG("This should have failed 3\n");
    return;
  }

  intptr_t native = cs_str_native_get(cs, name, &err);
  if (TEST_CHECK(native == INT_MIN))
  {
    TEST_MSG("Expected error: Unknown var '%s'\n", name);
  }
  else
  {
    TEST_MSG("This should have failed 4\n");
    return;
  }

  struct HashElem *he = cs_get_elem(cs, "Banana");
  if (!TEST_CHECK(he != NULL))
    return;

  set_list(cs);

  const struct ConfigSetType *cst = cs_get_type_def(cs, 15);
  if (!TEST_CHECK(!cst))
    return;

  cs_free(&cs);
  FREE(&err.data);
  log_line(__func__);
}
Beispiel #12
0
static bool test_initial_values(struct ConfigSet *cs, struct Buffer *err)
{
  log_line(__func__);
  TEST_MSG("Apple = '%s'\n", VarApple->mailbox);
  TEST_MSG("Banana = '%s'\n", VarBanana->mailbox);

  const char *apple_orig = "*****@*****.**";
  const char *banana_orig = "*****@*****.**";

  if (!TEST_CHECK(mutt_str_strcmp(VarApple->mailbox, apple_orig) == 0))
  {
    TEST_MSG("Error: initial values were wrong\n");
    return false;
  }

  if (!TEST_CHECK(mutt_str_strcmp(VarBanana->mailbox, banana_orig) == 0))
  {
    TEST_MSG("Error: initial values were wrong\n");
    return false;
  }

  cs_str_string_set(cs, "Apple", "*****@*****.**", err);
  cs_str_string_set(cs, "Banana", NULL, err);

  struct Buffer value;
  mutt_buffer_init(&value);
  value.dsize = 256;
  value.data = mutt_mem_calloc(1, value.dsize);
  mutt_buffer_reset(&value);

  int rc;

  mutt_buffer_reset(&value);
  rc = cs_str_initial_get(cs, "Apple", &value);
  if (!TEST_CHECK(CSR_RESULT(rc) == CSR_SUCCESS))
  {
    TEST_MSG("%s\n", value.data);
    FREE(&value.data);
    return false;
  }

  if (!TEST_CHECK(mutt_str_strcmp(value.data, apple_orig) == 0))
  {
    TEST_MSG("Apple's initial value is wrong: '%s'\n", value.data);
    FREE(&value.data);
    return false;
  }
  TEST_MSG("Apple = '%s'\n", VarApple->mailbox);
  TEST_MSG("Apple's initial value is '%s'\n", value.data);

  mutt_buffer_reset(&value);
  rc = cs_str_initial_get(cs, "Banana", &value);
  if (!TEST_CHECK(CSR_RESULT(rc) == CSR_SUCCESS))
  {
    TEST_MSG("%s\n", value.data);
    FREE(&value.data);
    return false;
  }

  if (!TEST_CHECK(mutt_str_strcmp(value.data, banana_orig) == 0))
  {
    TEST_MSG("Banana's initial value is wrong: '%s'\n", value.data);
    FREE(&value.data);
    return false;
  }
  TEST_MSG("Banana = '%s'\n", VarBanana ? VarBanana->mailbox : "");
  TEST_MSG("Banana's initial value is '%s'\n", NONULL(value.data));

  mutt_buffer_reset(&value);
  rc = cs_str_initial_set(cs, "Cherry", "*****@*****.**", &value);
  if (!TEST_CHECK(CSR_RESULT(rc) == CSR_SUCCESS))
  {
    TEST_MSG("%s\n", value.data);
    FREE(&value.data);
    return false;
  }

  mutt_buffer_reset(&value);
  rc = cs_str_initial_set(cs, "Cherry", "*****@*****.**", &value);
  if (!TEST_CHECK(CSR_RESULT(rc) == CSR_SUCCESS))
  {
    TEST_MSG("%s\n", value.data);
    FREE(&value.data);
    return false;
  }

  mutt_buffer_reset(&value);
  rc = cs_str_initial_get(cs, "Cherry", &value);
  if (!TEST_CHECK(CSR_RESULT(rc) == CSR_SUCCESS))
  {
    TEST_MSG("%s\n", value.data);
    FREE(&value.data);
    return false;
  }

  TEST_MSG("Cherry = '%s'\n", VarCherry ? VarCherry->mailbox : "");
  TEST_MSG("Cherry's initial value is '%s'\n", NONULL(value.data));

  FREE(&value.data);
  log_line(__func__);
  return true;
}
Beispiel #13
0
int mutt_parse_score (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
{
  SCORE *ptr, *last;
  char *pattern, *pc;
  struct pattern_t *pat;

  mutt_extract_token (buf, s, 0);
  if (!MoreArgs (s))
  {
    strfcpy (err->data, _("score: too few arguments"), err->dsize);
    return (-1);
  }
  pattern = buf->data;
  mutt_buffer_init (buf);
  mutt_extract_token (buf, s, 0);
  if (MoreArgs (s))
  {
    FREE (&pattern);
    strfcpy (err->data, _("score: too many arguments"), err->dsize);
    return (-1);
  }

  /* look for an existing entry and update the value, else add it to the end
     of the list */
  for (ptr = Score, last = NULL; ptr; last = ptr, ptr = ptr->next)
    if (mutt_strcmp (pattern, ptr->str) == 0)
      break;
  if (!ptr)
  {
    if ((pat = mutt_pattern_comp (pattern, 0, err)) == NULL)
    {
      FREE (&pattern);
      return (-1);
    }
    ptr = safe_calloc (1, sizeof (SCORE));
    if (last)
      last->next = ptr;
    else
      Score = ptr;
    ptr->pat = pat;
    ptr->str = pattern;
  } else
    /* 'buf' arg was cleared and 'pattern' holds the only reference;
     * as here 'ptr' != NULL -> update the value only in which case
     * ptr->str already has the string, so pattern should be freed.
     */
    FREE (&pattern);
  pc = buf->data;
  if (*pc == '=')
  {
    ptr->exact = 1;
    pc++;
  }
  if (mutt_atoi (pc, &ptr->val) < 0)
  {
    FREE (&pattern);
    strfcpy (err->data, _("Error: score: invalid number"), err->dsize);
    return (-1);
  }
  set_option (OPTNEEDRESCORE);
  return 0;
}