Exemplo n.º 1
0
static int
parse_color_name (const char *s, int *col, int *attr, int brite, BUFFER *err)
{
  char *eptr;

  if (ascii_strncasecmp (s, "bright", 6) == 0)
  {
    *attr |= brite;
    s += 6;
  }

  /* allow aliases for xterm color resources */
  if (ascii_strncasecmp (s, "color", 5) == 0)
  {
    s += 5;
    *col = strtol (s, &eptr, 10);
    if (!*s || *eptr || *col < 0 ||
	(*col >= COLORS && !option(OPTNOCURSES) && has_colors()))
    {
      snprintf (err->data, err->dsize, _("%s: color not supported by term"), s);
      return (-1);
    }
  }
  else if ((*col = mutt_getvaluebyname (s, Colors)) == -1)
  {
    snprintf (err->data, err->dsize, _("%s: no such color"), s);
    return (-1);
  }

  return 0;
}
Exemplo n.º 2
0
/* Parse CAPA output */
static int fetch_capa (char *line, void *data)
{
  POP_DATA *pop_data = (POP_DATA *)data;
  char *c;

  if (!ascii_strncasecmp (line, "SASL", 4))
  {
    FREE (&pop_data->auth_list);
    c = line + 4;
    SKIPWS (c);
    pop_data->auth_list = safe_strdup (c);
  }

  else if (!ascii_strncasecmp (line, "STLS", 4))
    pop_data->cmd_stls = 1;

  else if (!ascii_strncasecmp (line, "USER", 4))
    pop_data->cmd_user = 1;

  else if (!ascii_strncasecmp (line, "UIDL", 4))
    pop_data->cmd_uidl = 1;

  else if (!ascii_strncasecmp (line, "TOP", 3))
    pop_data->cmd_top = 1;

  return 0;
}
Exemplo n.º 3
0
Arquivo: url.c Projeto: Wuodan/mutt-kz
int url_parse_file (char *d, const char *src, size_t dl)
{
  if (ascii_strncasecmp (src, "file:", 5))
    return -1;
  else if (!ascii_strncasecmp (src, "file://", 7))	/* we don't support remote files */
    return -1;
  else
    strfcpy (d, src + 5, dl);

  return url_pct_decode (d);
}
Exemplo n.º 4
0
static void process_user_recips (ENVELOPE *env)
{
  LIST *uh = UserHeader;

  for (; uh; uh = uh->next)
  {
    if (ascii_strncasecmp ("to:", uh->data, 3) == 0)
      env->to = rfc822_parse_adrlist (env->to, uh->data + 3);
    else if (ascii_strncasecmp ("cc:", uh->data, 3) == 0)
      env->cc = rfc822_parse_adrlist (env->cc, uh->data + 3);
    else if (ascii_strncasecmp ("bcc:", uh->data, 4) == 0)
      env->bcc = rfc822_parse_adrlist (env->bcc, uh->data + 4);
  }
}
Exemplo n.º 5
0
void mutt_check_lookup_list (BODY *b, char *type, int len)
{
  LIST *t = MimeLookupList;
  int i;

  for (; t; t = t->next) {
    i = mutt_strlen (t->data) - 1;
    if ((i > 0 && t->data[i-1] == '/' && t->data[i] == '*' && 
	 ascii_strncasecmp (type, t->data, i) == 0) ||
	ascii_strcasecmp (type, t->data) == 0) {

    BODY tmp = {0};
    int n;
    if ((n = mutt_lookup_mime_type (&tmp, b->filename)) != TYPEOTHER) {
      snprintf (type, len, "%s/%s",
                n == TYPEAUDIO ? "audio" :
                n == TYPEAPPLICATION ? "application" :
                n == TYPEIMAGE ? "image" :
                n == TYPEMESSAGE ? "message" :
                n == TYPEMODEL ? "model" :
                n == TYPEMULTIPART ? "multipart" :
                n == TYPETEXT ? "text" :
                n == TYPEVIDEO ? "video" : "other",
                tmp.subtype);
      dprint(1, (debugfile, "mutt_check_lookup_list: \"%s\" -> %s\n", 
        b->filename, type));
    }
    if (tmp.subtype) 
      FREE (&tmp.subtype);
    if (tmp.xtype) 
      FREE (&tmp.xtype);
    }
  }
}
Exemplo n.º 6
0
int mutt_is_autoview (BODY *b, const char *type)
{
  LIST *t = AutoViewList;
  char _type[SHORT_STRING];
  int i;

  if (!type)
    snprintf (_type, sizeof (_type), "%s/%s", TYPE (b), b->subtype);
  else
    strncpy (_type, type, sizeof(_type));

  mutt_check_lookup_list (b, _type, sizeof(_type));
  type = _type;

  if (mutt_needs_mailcap (b))
  {
    if (option (OPTIMPLICITAUTOVIEW))
      return 1;
    
    if (is_mmnoask (type))
      return 1;
  }

  for (; t; t = t->next) {
    i = mutt_strlen (t->data) - 1;
    if ((i > 0 && t->data[i-1] == '/' && t->data[i] == '*' && 
	 ascii_strncasecmp (type, t->data, i) == 0) ||
	ascii_strcasecmp (type, t->data) == 0)
      return 1;
  }

  return 0;
}
Exemplo n.º 7
0
/* returns true if the header contained in "s" is in list "t" */
int mutt_matches_ignore (const char *s, LIST * t)
{
  for (; t; t = t->next) {
    if (!ascii_strncasecmp (s, t->data, str_len (t->data))
        || *t->data == '*')
      return 1;
  }
  return 0;
}
Exemplo n.º 8
0
int mutt_is_application_pgp (BODY *m)
{
  int t = 0;
  char *p;
  
  if (m->type == TYPEAPPLICATION)
  {
    if (!ascii_strcasecmp (m->subtype, "pgp") || !ascii_strcasecmp (m->subtype, "x-pgp-message"))
    {
      if ((p = mutt_get_parameter ("x-action", m->parameter))
	  && (!ascii_strcasecmp (p, "sign") || !ascii_strcasecmp (p, "signclear")))
	t |= PGPSIGN;

      if ((p = mutt_get_parameter ("format", m->parameter)) && 
	  !ascii_strcasecmp (p, "keys-only"))
	t |= PGPKEY;

      if(!t) t |= PGPENCRYPT;  /* not necessarily correct, but... */
    }

    if (!ascii_strcasecmp (m->subtype, "pgp-signed"))
      t |= PGPSIGN;

    if (!ascii_strcasecmp (m->subtype, "pgp-keys"))
      t |= PGPKEY;
  }
  else if (m->type == TYPETEXT && ascii_strcasecmp ("plain", m->subtype) == 0)
  {
    if (((p = mutt_get_parameter ("x-mutt-action", m->parameter))
	 || (p = mutt_get_parameter ("x-action", m->parameter)) 
	 || (p = mutt_get_parameter ("action", m->parameter)))
	 && !ascii_strncasecmp ("pgp-sign", p, 8))
      t |= PGPSIGN;
    else if (p && !ascii_strncasecmp ("pgp-encrypt", p, 11))
      t |= PGPENCRYPT;
    else if (p && !ascii_strncasecmp ("pgp-keys", p, 7))
      t |= PGPKEY;
  }
  if (t)
    t |= PGPINLINE;

  return t;
}
Exemplo n.º 9
0
static int expectWord(const char *zText, const char *zWord,
                      const char **pzContinue){
  const char *zWordStart, *zWordEnd;
  if( findWord(zText, &zWordStart, &zWordEnd) &&
      ascii_strncasecmp(zWord, zWordStart, zWordEnd - zWordStart)==0 ){
    *pzContinue = zWordEnd;
    return 1;
  }
  return 0;
}
Exemplo n.º 10
0
static void process_user_header (ENVELOPE *env)
{
  LIST *uh = UserHeader;
  LIST *last = env->userhdrs;

  if (last)
    while (last->next)
      last = last->next;

  for (; uh; uh = uh->next)
  {
    if (ascii_strncasecmp ("from:", uh->data, 5) == 0)
    {
      /* User has specified a default From: address.  Remove default address */
      rfc822_free_address (&env->from);
      env->from = rfc822_parse_adrlist (env->from, uh->data + 5);
    }
    else if (ascii_strncasecmp ("reply-to:", uh->data, 9) == 0)
    {
      rfc822_free_address (&env->reply_to);
      env->reply_to = rfc822_parse_adrlist (env->reply_to, uh->data + 9);
    }
    else if (ascii_strncasecmp ("message-id:", uh->data, 11) == 0)
    {
      char *tmp = mutt_extract_message_id (uh->data + 11, NULL);
      if (rfc822_valid_msgid (tmp) >= 0)
      {
	FREE(&env->message_id);
	env->message_id = tmp;
      } else
	FREE(&tmp);
    }
    else if (ascii_strncasecmp ("to:", uh->data, 3) != 0 &&
	     ascii_strncasecmp ("cc:", uh->data, 3) != 0 &&
	     ascii_strncasecmp ("bcc:", uh->data, 4) != 0 &&
	     ascii_strncasecmp ("subject:", uh->data, 8) != 0 &&
	     ascii_strncasecmp ("return-path:", uh->data, 12) != 0)
    {
      if (last)
      {
	last->next = mutt_new_list ();
	last = last->next;
      }
      else
	last = env->userhdrs = mutt_new_list ();
      last->data = safe_strdup (uh->data);
    }
  }
}
Exemplo n.º 11
0
/* Reads a command response from the SMTP server.
 * Returns:
 * 0	on success (2xx code) or continue (354 code)
 * -1	write error, or any other response code
 */
static int
smtp_get_resp (CONNECTION * conn)
{
        int n;
        char buf[1024];

        do {
                n = mutt_socket_readln (buf, sizeof (buf), conn);
                if (n < 4) {
/* read error, or no response code */
                        return smtp_err_read;
                }

                if (!ascii_strncasecmp ("8BITMIME", buf + 4, 8))
                        mutt_bit_set (Capabilities, EIGHTBITMIME);
                else if (!ascii_strncasecmp ("AUTH ", buf + 4, 5)) {
                        mutt_bit_set (Capabilities, AUTH);
                        FREE (&AuthMechs);
                        AuthMechs = safe_strdup (buf + 9);
                }
                else if (!ascii_strncasecmp ("DSN", buf + 4, 3))
                        mutt_bit_set (Capabilities, DSN);
                else if (!ascii_strncasecmp ("STARTTLS", buf + 4, 8))
                        mutt_bit_set (Capabilities, STARTTLS);

                if (smtp_code (buf, n, &n) < 0)
                        return smtp_err_code;

        } while (buf[3] == '-');

        if (smtp_success (n) || n == smtp_continue)
                return 0;

        mutt_error (_("SMTP session failed: %s"), buf);
        return -1;
}
Exemplo n.º 12
0
static int edit_envelope (ENVELOPE *en)
{
  char buf[HUGE_STRING];
  LIST *uh = UserHeader;

  if (edit_address (&en->to, "To: ") == -1 || en->to == NULL)
    return (-1);
  if (option (OPTASKCC) && edit_address (&en->cc, "Cc: ") == -1)
    return (-1);
  if (option (OPTASKBCC) && edit_address (&en->bcc, "Bcc: ") == -1)
    return (-1);

  if (en->subject)
  {
    if (option (OPTFASTREPLY))
      return (0);
    else
      strfcpy (buf, en->subject, sizeof (buf));
  }
  else
  {
    const char *p;

    buf[0] = 0;
    for (; uh; uh = uh->next)
    {
      if (ascii_strncasecmp ("subject:", uh->data, 8) == 0)
      {
	p = skip_email_wsp(uh->data + 8);
	strncpy (buf, p, sizeof (buf));
      }
    }
  }
  
  if (mutt_get_field ("Subject: ", buf, sizeof (buf), 0) != 0 ||
      (!buf[0] && query_quadoption (OPT_SUBJECT, _("No subject, abort?")) != M_NO))
  {
    mutt_message _("No subject, aborting.");
    return (-1);
  }
  mutt_str_replace (&en->subject, buf);

  return 0;
}
Exemplo n.º 13
0
static const struct dime_record *
dime_find_record(const GSList *records, const char *type, const char *id)
{
	size_t type_length, id_length;
	const GSList *iter;

	g_return_val_if_fail(type, NULL);

	type_length = type ? strlen(type) : 0;
	g_return_val_if_fail(type_length > 0, NULL);

	id_length = id ? strlen(id) : 0;
	
	for (iter = records; NULL != iter; iter = g_slist_next(iter)) {
		const struct dime_record *record;
		
		record = iter->data;
		g_assert(record);
		
		if (dime_record_type_length(record) != type_length)
			continue;
		if (0 != ascii_strncasecmp(dime_record_type(record), type, type_length))
			continue;
		if (id) {
			if (dime_record_id_length(record) != id_length)
				continue;
			if (0 != strncasecmp(dime_record_id(record), id, id_length))
				continue;
		}
		return record;
	}

	if (GNET_PROPERTY(tigertree_debug)) {
		g_debug("TTH could not find record (type=\"%s\", id=%s%s%s)",
			type,
			id ? "\"" : "",
			id ? id : "<none>",
			id ? "\"" : "");
		thex_dump_dime_records(records);
	}

	return NULL;
}
Exemplo n.º 14
0
static int check_idn (ADDRESS *ap)
{
  char *p = 0;

  if (!ap || !ap->mailbox)
    return 0;

  if (!ap->idn_checked)
  {
    ap->idn_checked = 1;
    for (p = strchr (ap->mailbox, '@'); p && *p; p = strchr (p, '.')) 
      if (ascii_strncasecmp (++p, "xn--", 4) == 0)
      {
	ap->is_idn = 1;
	break;
      }
  }
  
  return ap->is_idn;
}
Exemplo n.º 15
0
/* for compatibility with metamail */
static int is_mmnoask (const char *buf)
{
  char tmp[LONG_STRING], *p, *q;
  int lng;

  if ((p = getenv ("MM_NOASK")) != NULL && *p)
  {
    if (mutt_strcmp (p, "1") == 0)
      return (1);

    strfcpy (tmp, p, sizeof (tmp));
    p = tmp;

    while ((p = strtok (p, ",")) != NULL)
    {
      if ((q = strrchr (p, '/')) != NULL)
      {
	if (*(q+1) == '*')
	{
	  if (ascii_strncasecmp (buf, p, q-p) == 0)
	    return (1);
	}
	else
	{
	  if (ascii_strcasecmp (buf, p) == 0)
	    return (1);
	}
      }
      else
      {
	lng = mutt_strlen (p);
	if (buf[lng] == '/' && mutt_strncasecmp (buf, p, lng) == 0)
	  return (1);
      }

      p = NULL;
    }
  }

  return (0);
}
Exemplo n.º 16
0
int mutt_check_encoding (const char *c)
{
  if (ascii_strncasecmp ("7bit", c, sizeof ("7bit")-1) == 0)
    return (ENC7BIT);
  else if (ascii_strncasecmp ("8bit", c, sizeof ("8bit")-1) == 0)
    return (ENC8BIT);
  else if (ascii_strncasecmp ("binary", c, sizeof ("binary")-1) == 0)
    return (ENCBINARY);
  else if (ascii_strncasecmp ("quoted-printable", c, sizeof ("quoted-printable")-1) == 0)
    return (ENCQUOTEDPRINTABLE);
  else if (ascii_strncasecmp ("base64", c, sizeof("base64")-1) == 0)
    return (ENCBASE64);
  else if (ascii_strncasecmp ("x-uuencode", c, sizeof("x-uuencode")-1) == 0)
    return (ENCUUENCODED);
#ifdef SUN_ATTACHMENT
  else if (ascii_strncasecmp ("uuencode", c, sizeof("uuencode")-1) == 0)
    return (ENCUUENCODED);
#endif
  else
    return (ENCOTHER);
}
Exemplo n.º 17
0
/* Ok, the only reason for not merging this with mutt_copy_header()
 * below is to avoid creating a HEADER structure in message_handler().
 * Also, this one will wrap headers much more aggressively than the other one.
 */
int
mutt_copy_hdr (FILE *in, FILE *out, LOFF_T off_start, LOFF_T off_end, int flags,
	       const char *prefix)
{
  int from = 0;
  int this_is_from;
  int ignore = 0;
  char buf[LONG_STRING]; /* should be long enough to get most fields in one pass */
  char *nl;
  LIST *t;
  char **headers;
  int hdr_count;
  int x;
  char *this_one = NULL;
  size_t this_one_len = 0;
  int error;

  if (ftello (in) != off_start)
    fseeko (in, off_start, 0);

  buf[0] = '\n';
  buf[1] = 0;

  if ((flags & (CH_REORDER | CH_WEED | CH_MIME | CH_DECODE | CH_PREFIX | CH_WEED_DELIVERED)) == 0)
  {
    /* Without these flags to complicate things
     * we can do a more efficient line to line copying
     */
    while (ftello (in) < off_end)
    {
      nl = strchr (buf, '\n');

      if ((fgets (buf, sizeof (buf), in)) == NULL)
	break;

      /* Is it the beginning of a header? */
      if (nl && buf[0] != ' ' && buf[0] != '\t')
      {
	ignore = 1;
	if (!from && mutt_strncmp ("From ", buf, 5) == 0)
	{
	  if ((flags & CH_FROM) == 0)
	    continue;
	  from = 1;
	}
	else if (flags & (CH_NOQFROM) &&
			ascii_strncasecmp (">From ", buf, 6) == 0)
		continue;

	else if (buf[0] == '\n' || (buf[0] == '\r' && buf[1] == '\n'))
	  break; /* end of header */

	if ((flags & (CH_UPDATE | CH_XMIT | CH_NOSTATUS)) &&
	    (ascii_strncasecmp ("Status:", buf, 7) == 0 ||
	     ascii_strncasecmp ("X-Status:", buf, 9) == 0))
	  continue;
	if ((flags & (CH_UPDATE_LEN | CH_XMIT | CH_NOLEN)) &&
	    (ascii_strncasecmp ("Content-Length:", buf, 15) == 0 ||
	     ascii_strncasecmp ("Lines:", buf, 6) == 0))
	  continue;
	if ((flags & CH_UPDATE_REFS) &&
	    ascii_strncasecmp ("References:", buf, 11) == 0)
	  continue;
	if ((flags & CH_UPDATE_IRT) &&
	    ascii_strncasecmp ("In-Reply-To:", buf, 12) == 0)
	  continue;
	ignore = 0;
      }

      if (!ignore && fputs (buf, out) == EOF)
	return (-1);
    }
    return 0;
  }

  hdr_count = 1;
  x = 0;
  error = FALSE;

  /* We are going to read and collect the headers in an array
   * so we are able to do re-ordering.
   * First count the number of entries in the array
   */
  if (flags & CH_REORDER)
  {
    for (t = HeaderOrderList; t; t = t->next)
    {
      dprint(3, (debugfile, "Reorder list: %s\n", t->data));
      hdr_count++;
    }
  }

  dprint (1, (debugfile, "WEED is %s\n", (flags & CH_WEED) ? "Set" : "Not"));

  headers = safe_calloc (hdr_count, sizeof (char *));

  /* Read all the headers into the array */
  while (ftello (in) < off_end)
  {
    nl = strchr (buf, '\n');

    /* Read a line */
    if ((fgets (buf, sizeof (buf), in)) == NULL)
      break;

    /* Is it the beginning of a header? */
    if (nl && buf[0] != ' ' && buf[0] != '\t')
    {
      /* Do we have anything pending? */
      if (this_one)
      {
	if (flags & CH_DECODE) 
	{
	  if (!address_header_decode (&this_one))
	    rfc2047_decode (&this_one);
	  this_one_len = mutt_strlen (this_one);
	}

	if (!headers[x])
	  headers[x] = this_one;
	else 
	{
	  int hlen = mutt_strlen (headers[x]);

	  safe_realloc (&headers[x], hlen + this_one_len + sizeof (char));
	  strcat (headers[x] + hlen, this_one); /* __STRCAT_CHECKED__ */
	  FREE (&this_one);
	}

	this_one = NULL;
      }

      ignore = 1;
      this_is_from = 0;
      if (!from && mutt_strncmp ("From ", buf, 5) == 0)
      {
	if ((flags & CH_FROM) == 0)
	  continue;
	this_is_from = from = 1;
      }
      else if (buf[0] == '\n' || (buf[0] == '\r' && buf[1] == '\n'))
	break; /* end of header */

      /* note: CH_FROM takes precedence over header weeding. */
      if (!((flags & CH_FROM) && (flags & CH_FORCE_FROM) && this_is_from) &&
	  (flags & CH_WEED) &&
	  mutt_matches_ignore (buf, Ignore) &&
	  !mutt_matches_ignore (buf, UnIgnore))
	continue;
      if ((flags & CH_WEED_DELIVERED) &&
	  ascii_strncasecmp ("Delivered-To:", buf, 13) == 0)
	continue;
      if ((flags & (CH_UPDATE | CH_XMIT | CH_NOSTATUS)) &&
	  (ascii_strncasecmp ("Status:", buf, 7) == 0 ||
	   ascii_strncasecmp ("X-Status:", buf, 9) == 0))
	continue;
      if ((flags & (CH_UPDATE_LEN | CH_XMIT | CH_NOLEN)) &&
	  (ascii_strncasecmp ("Content-Length:", buf, 15) == 0 ||
	   ascii_strncasecmp ("Lines:", buf, 6) == 0))
	continue;
      if ((flags & CH_MIME) &&
	  ((ascii_strncasecmp ("content-", buf, 8) == 0 &&
	    (ascii_strncasecmp ("transfer-encoding:", buf + 8, 18) == 0 ||
	     ascii_strncasecmp ("type:", buf + 8, 5) == 0)) ||
	   ascii_strncasecmp ("mime-version:", buf, 13) == 0))
	continue;
      if ((flags & CH_UPDATE_REFS) &&
	  ascii_strncasecmp ("References:", buf, 11) == 0)
	continue;
      if ((flags & CH_UPDATE_IRT) &&
	  ascii_strncasecmp ("In-Reply-To:", buf, 12) == 0)
	continue;

      /* Find x -- the array entry where this header is to be saved */
      if (flags & CH_REORDER)
      {
	for (t = HeaderOrderList, x = 0 ; (t) ; t = t->next, x++)
	{
	  if (!ascii_strncasecmp (buf, t->data, mutt_strlen (t->data)))
	  {
	    dprint(2, (debugfile, "Reorder: %s matches %s\n", t->data, buf));
	    break;
	  }
	}
      }

      ignore = 0;
    } /* If beginning of header */

    if (!ignore)
    {
      dprint (2, (debugfile, "Reorder: x = %d; hdr_count = %d\n", x, hdr_count));
      if (!this_one) {
	this_one = safe_strdup (buf);
	this_one_len = mutt_strlen (this_one);
      } else {
	int blen = mutt_strlen (buf);

	safe_realloc (&this_one, this_one_len + blen + sizeof (char));
	strcat (this_one + this_one_len, buf); /* __STRCAT_CHECKED__ */
	this_one_len += blen;
      }
    }
  } /* while (ftello (in) < off_end) */

  /* Do we have anything pending?  -- XXX, same code as in above in the loop. */
  if (this_one)
  {
    if (flags & CH_DECODE) 
    {
      if (!address_header_decode (&this_one))
	rfc2047_decode (&this_one);
      this_one_len = mutt_strlen (this_one);
    }
    
    if (!headers[x])
      headers[x] = this_one;
    else 
    {
      int hlen = mutt_strlen (headers[x]);

      safe_realloc (&headers[x], hlen + this_one_len + sizeof (char));
      strcat (headers[x] + hlen, this_one); /* __STRCAT_CHECKED__ */
      FREE (&this_one);
    }

    this_one = NULL;
  }

  /* Now output the headers in order */
  for (x = 0; x < hdr_count; x++)
  {
    if (headers[x])
    {
#if 0
      if (flags & CH_DECODE)
	rfc2047_decode (&headers[x]);
#endif

      /* We couldn't do the prefixing when reading because RFC 2047
       * decoding may have concatenated lines.
       */
      
      if (flags & (CH_DECODE|CH_PREFIX))
      {
	if (mutt_write_one_header (out, 0, headers[x], 
				   flags & CH_PREFIX ? prefix : 0, mutt_term_width (Wrap) -
				   (flags & CH_PAGER_BUILTIN ? SidebarWidth : 0), flags) == -1)
	{
	  error = TRUE;
	  break;
	}
      }
      else
      {      
	if (fputs (headers[x], out) == EOF)
	{
	  error = TRUE;
	  break;
	}
      }
    }
  }

  /* Free in a separate loop to be sure that all headers are freed
   * in case of error. */
  for (x = 0; x < hdr_count; x++)
    FREE (&headers[x]);
  FREE (&headers);

  if (error)
    return (-1);
  return (0);
}
Exemplo n.º 18
0
Arquivo: ocsp.c Projeto: FMayzek/gnupg
/* Check whether the certificate either given by fingerprint CERT_FPR
   or directly through the CERT object is valid by running an OCSP
   transaction.  With FORCE_DEFAULT_RESPONDER set only the configured
   default responder is used. */
gpg_error_t
ocsp_isvalid (ctrl_t ctrl, ksba_cert_t cert, const char *cert_fpr,
              int force_default_responder)
{
  gpg_error_t err;
  ksba_ocsp_t ocsp = NULL;
  ksba_cert_t issuer_cert = NULL;
  ksba_sexp_t sigval = NULL;
  gcry_sexp_t s_sig = NULL;
  ksba_isotime_t current_time;
  ksba_isotime_t this_update, next_update, revocation_time, produced_at;
  ksba_isotime_t tmp_time;
  ksba_status_t status;
  ksba_crl_reason_t reason;
  char *url_buffer = NULL;
  const char *url;
  gcry_md_hd_t md = NULL;
  int i, idx;
  char *oid;
  ksba_name_t name;
  fingerprint_list_t default_signer = NULL;

  /* Get the certificate.  */
  if (cert)
    {
      ksba_cert_ref (cert);

      err = find_issuing_cert (ctrl, cert, &issuer_cert);
      if (err)
        {
          log_error (_("issuer certificate not found: %s\n"),
                     gpg_strerror (err));
          goto leave;
        }
    }
  else
    {
      cert = get_cert_local (ctrl, cert_fpr);
      if (!cert)
        {
          log_error (_("caller did not return the target certificate\n"));
          err = gpg_error (GPG_ERR_GENERAL);
          goto leave;
        }
      issuer_cert = get_issuing_cert_local (ctrl, NULL);
      if (!issuer_cert)
        {
          log_error (_("caller did not return the issuing certificate\n"));
          err = gpg_error (GPG_ERR_GENERAL);
          goto leave;
        }
    }

  /* Create an OCSP instance.  */
  err = ksba_ocsp_new (&ocsp);
  if (err)
    {
      log_error (_("failed to allocate OCSP context: %s\n"),
                 gpg_strerror (err));
      goto leave;
    }



  /* Figure out the OCSP responder to use.
     1. Try to get the reponder from the certificate.
        We do only take http and https style URIs into account.
     2. If this fails use the default responder, if any.
   */
  url = NULL;
  for (idx=0; !url && !opt.ignore_ocsp_service_url && !force_default_responder
         && !(err=ksba_cert_get_authority_info_access (cert, idx,
                                                       &oid, &name)); idx++)
    {
      if ( !strcmp (oid, oidstr_ocsp) )
        {
          for (i=0; !url && ksba_name_enum (name, i); i++)
            {
              char *p = ksba_name_get_uri (name, i);
              if (p && (!ascii_strncasecmp (p, "http:", 5)
                        || !ascii_strncasecmp (p, "https:", 6)))
                url = url_buffer = p;
              else
                xfree (p);
            }
        }
      ksba_name_release (name);
      ksba_free (oid);
    }
  if (err && gpg_err_code (err) != GPG_ERR_EOF)
    {
      log_error (_("can't get authorityInfoAccess: %s\n"), gpg_strerror (err));
      goto leave;
    }
  if (!url)
    {
      if (!opt.ocsp_responder || !*opt.ocsp_responder)
        {
          log_info (_("no default OCSP responder defined\n"));
          err = gpg_error (GPG_ERR_CONFIGURATION);
          goto leave;
        }
      if (!opt.ocsp_signer)
        {
          log_info (_("no default OCSP signer defined\n"));
          err = gpg_error (GPG_ERR_CONFIGURATION);
          goto leave;
        }
      url = opt.ocsp_responder;
      default_signer = opt.ocsp_signer;
      if (opt.verbose)
        log_info (_("using default OCSP responder '%s'\n"), url);
    }
  else
    {
      if (opt.verbose)
        log_info (_("using OCSP responder '%s'\n"), url);
    }

  /* Ask the OCSP responder. */
  err = gcry_md_open (&md, GCRY_MD_SHA1, 0);
  if (err)
    {
      log_error (_("failed to establish a hashing context for OCSP: %s\n"),
                 gpg_strerror (err));
      goto leave;
    }
  err = do_ocsp_request (ctrl, ocsp, md, url, cert, issuer_cert);
  if (err)
    goto leave;

  /* We got a useful answer, check that the answer has a valid signature. */
  sigval = ksba_ocsp_get_sig_val (ocsp, produced_at);
  if (!sigval || !*produced_at)
    {
      err = gpg_error (GPG_ERR_INV_OBJ);
      goto leave;
    }
  if ( (err = canon_sexp_to_gcry (sigval, &s_sig)) )
    goto leave;
  xfree (sigval);
  sigval = NULL;
  err = check_signature (ctrl, ocsp, s_sig, md, default_signer);
  if (err)
    goto leave;

  /* We only support one certificate per request.  Check that the
     answer matches the right certificate. */
  err = ksba_ocsp_get_status (ocsp, cert,
                              &status, this_update, next_update,
                              revocation_time, &reason);
  if (err)
    {
      log_error (_("error getting OCSP status for target certificate: %s\n"),
                 gpg_strerror (err));
      goto leave;
    }

  /* In case the certificate has been revoked, we better invalidate
     our cached validation status. */
  if (status == KSBA_STATUS_REVOKED)
    {
      time_t validated_at = 0; /* That is: No cached validation available. */
      err = ksba_cert_set_user_data (cert, "validated_at",
                                     &validated_at, sizeof (validated_at));
      if (err)
        {
          log_error ("set_user_data(validated_at) failed: %s\n",
                     gpg_strerror (err));
          err = 0; /* The certificate is anyway revoked, and that is a
                      more important message than the failure of our
                      cache. */
        }
    }


  if (opt.verbose)
    {
      log_info (_("certificate status is: %s  (this=%s  next=%s)\n"),
                status == KSBA_STATUS_GOOD? _("good"):
                status == KSBA_STATUS_REVOKED? _("revoked"):
                status == KSBA_STATUS_UNKNOWN? _("unknown"):
                status == KSBA_STATUS_NONE? _("none"): "?",
                this_update, next_update);
      if (status == KSBA_STATUS_REVOKED)
        log_info (_("certificate has been revoked at: %s due to: %s\n"),
                  revocation_time,
                  reason == KSBA_CRLREASON_UNSPECIFIED?   "unspecified":
                  reason == KSBA_CRLREASON_KEY_COMPROMISE? "key compromise":
                  reason == KSBA_CRLREASON_CA_COMPROMISE?   "CA compromise":
                  reason == KSBA_CRLREASON_AFFILIATION_CHANGED?
                                                      "affiliation changed":
                  reason == KSBA_CRLREASON_SUPERSEDED?   "superseeded":
                  reason == KSBA_CRLREASON_CESSATION_OF_OPERATION?
                                                  "cessation of operation":
                  reason == KSBA_CRLREASON_CERTIFICATE_HOLD?
                                                  "certificate on hold":
                  reason == KSBA_CRLREASON_REMOVE_FROM_CRL?
                                                  "removed from CRL":
                  reason == KSBA_CRLREASON_PRIVILEGE_WITHDRAWN?
                                                  "privilege withdrawn":
                  reason == KSBA_CRLREASON_AA_COMPROMISE? "AA compromise":
                  reason == KSBA_CRLREASON_OTHER?   "other":"?");

    }


  if (status == KSBA_STATUS_REVOKED)
    err = gpg_error (GPG_ERR_CERT_REVOKED);
  else if (status == KSBA_STATUS_UNKNOWN)
    err = gpg_error (GPG_ERR_NO_DATA);
  else if (status != KSBA_STATUS_GOOD)
    err = gpg_error (GPG_ERR_GENERAL);

  /* Allow for some clock skew. */
  gnupg_get_isotime (current_time);
  add_seconds_to_isotime (current_time, opt.ocsp_max_clock_skew);

  if (strcmp (this_update, current_time) > 0 )
    {
      log_error (_("OCSP responder returned a status in the future\n"));
      log_info ("used now: %s  this_update: %s\n", current_time, this_update);
      if (!err)
        err = gpg_error (GPG_ERR_TIME_CONFLICT);
    }

  /* Check that THIS_UPDATE is not too far back in the past. */
  gnupg_copy_time (tmp_time, this_update);
  add_seconds_to_isotime (tmp_time,
                          opt.ocsp_max_period+opt.ocsp_max_clock_skew);
  if (!*tmp_time || strcmp (tmp_time, current_time) < 0 )
    {
      log_error (_("OCSP responder returned a non-current status\n"));
      log_info ("used now: %s  this_update: %s\n",
                current_time, this_update);
      if (!err)
        err = gpg_error (GPG_ERR_TIME_CONFLICT);
    }

  /* Check that we are not beyound NEXT_UPDATE  (plus some extra time). */
  if (*next_update)
    {
      gnupg_copy_time (tmp_time, next_update);
      add_seconds_to_isotime (tmp_time,
                              opt.ocsp_current_period+opt.ocsp_max_clock_skew);
      if (!*tmp_time && strcmp (tmp_time, current_time) < 0 )
        {
          log_error (_("OCSP responder returned an too old status\n"));
          log_info ("used now: %s  next_update: %s\n",
                    current_time, next_update);
          if (!err)
            err = gpg_error (GPG_ERR_TIME_CONFLICT);
        }
    }


 leave:
  gcry_md_close (md);
  gcry_sexp_release (s_sig);
  xfree (sigval);
  ksba_cert_release (issuer_cert);
  ksba_cert_release (cert);
  ksba_ocsp_release (ocsp);
  xfree (url_buffer);
  return err;
}
Exemplo n.º 19
0
int
main(int argc,char *argv[])
{
  int arg,ret=KEYSERVER_INTERNAL_ERROR,try_srv=1;
  char line[MAX_LINE];
  int failed=0;
  struct keylist *keylist=NULL,*keyptr=NULL;
  char *proxy=NULL;
  struct curl_slist *headers=NULL;

  console=stderr;

  /* Kludge to implement standard GNU options.  */
  if (argc > 1 && !strcmp (argv[1], "--version"))
    {
      printf ("gpgkeys_hkp (GnuPG) %s\n", VERSION);
      printf ("Uses: %s\n", curl_version());
      return 0;
    }
  else if (argc > 1 && !strcmp (argv[1], "--help"))
    {
      show_help (stdout);
      return 0;
    }

  while((arg=getopt(argc,argv,"hVo:"))!=-1)
    switch(arg)
      {
      default:
      case 'h':
        show_help (console);
	return KEYSERVER_OK;

      case 'V':
	fprintf(stdout,"%d\n%s\n",KEYSERVER_PROTO_VERSION,VERSION);
	return KEYSERVER_OK;

      case 'o':
	output=fopen(optarg,"w");
	if(output==NULL)
	  {
	    fprintf(console,"gpgkeys: Cannot open output file `%s': %s\n",
		    optarg,strerror(errno));
	    return KEYSERVER_INTERNAL_ERROR;
	  }

	break;
      }

  if(argc>optind)
    {
      input=fopen(argv[optind],"r");
      if(input==NULL)
	{
	  fprintf(console,"gpgkeys: Cannot open input file `%s': %s\n",
		  argv[optind],strerror(errno));
	  return KEYSERVER_INTERNAL_ERROR;
	}
    }

  if(input==NULL)
    input=stdin;

  if(output==NULL)
    output=stdout;

  opt=init_ks_options();
  if(!opt)
    return KEYSERVER_NO_MEMORY;

  /* Get the command and info block */

  while(fgets(line,MAX_LINE,input)!=NULL)
    {
      int err;
      char option[MAX_OPTION+1];

      if(line[0]=='\n')
	break;

      err=parse_ks_options(line,opt);
      if(err>0)
	{
	  ret=err;
	  goto fail;
	}
      else if(err==0)
	continue;

      if(sscanf(line,"OPTION %" MKSTRING(MAX_OPTION) "s\n",option)==1)
	{
	  int no=0;
	  char *start=&option[0];

	  option[MAX_OPTION]='\0';

	  if(ascii_strncasecmp(option,"no-",3)==0)
	    {
	      no=1;
	      start=&option[3];
	    }

	  if(ascii_strncasecmp(start,"http-proxy",10)==0)
	    {
	      if(no)
		{
		  free(proxy);
		  proxy=strdup("");
		}
	      else if(start[10]=='=')
		{
		  if(strlen(&start[11])<MAX_PROXY)
		    {
		      free(proxy);
		      proxy=strdup(&start[11]);
		    }
		}
	    }
	  else if(ascii_strcasecmp(start,"try-dns-srv")==0)
	    {
	      if(no)
		try_srv=0;
	      else
		try_srv=1;
	    }

	  continue;
	}
    }


  if(!opt->scheme)
    {
      fprintf(console,"gpgkeys: no scheme supplied!\n");
      ret=KEYSERVER_SCHEME_NOT_FOUND;
      goto fail;
    }

  if(ascii_strcasecmp(opt->scheme,"hkps")==0)
    {
      proto="https";
      port="443";
    }
  else
    {
      proto="http";
      port="11371";
    }

  if(!opt->host)
    {
      fprintf(console,"gpgkeys: no keyserver host provided\n");
      goto fail;
    }

  if(opt->timeout && register_timeout()==-1)
    {
      fprintf(console,"gpgkeys: unable to register timeout handler\n");
      return KEYSERVER_INTERNAL_ERROR;
    }

  curl_global_init(CURL_GLOBAL_DEFAULT);
  curl=curl_easy_init();
  if(!curl)
    {
      fprintf(console,"gpgkeys: unable to initialize curl\n");
      ret=KEYSERVER_INTERNAL_ERROR;
      goto fail;
    }

  /* If the user gives a :port, then disable SRV.  The semantics of a
     specified port and SRV do not play well together. */
  if(opt->port)
    port=opt->port;
  else if(try_srv)
    {
      char *srvtag;

      if(ascii_strcasecmp(opt->scheme,"hkp")==0)
	srvtag="pgpkey-http";
      else if(ascii_strcasecmp(opt->scheme,"hkps")==0)
	srvtag="pgpkey-https";
      else
	srvtag=NULL;

#ifdef HAVE_LIBCURL
      /* We're using libcurl, so fake SRV support via our wrapper.
	 This isn't as good as true SRV support, as we do not try all
	 possible targets at one particular level and work our way
	 down the list, but it's better than nothing. */
      srv_replace(srvtag);
#else
      /* We're using our internal curl shim, so we can use its (true)
	 SRV support.  Obviously, CURLOPT_SRVTAG_GPG_HACK isn't a real
	 libcurl option.  It's specific to our shim. */
      curl_easy_setopt(curl,CURLOPT_SRVTAG_GPG_HACK,srvtag);
#endif
    }

  curl_easy_setopt(curl,CURLOPT_ERRORBUFFER,errorbuffer);

  if(opt->auth)
    curl_easy_setopt(curl,CURLOPT_USERPWD,opt->auth);

  if(opt->debug)
    {
      fprintf(console,"gpgkeys: curl version = %s\n",curl_version());
      curl_easy_setopt(curl,CURLOPT_STDERR,console);
      curl_easy_setopt(curl,CURLOPT_VERBOSE,1L);
    }

  curl_easy_setopt(curl,CURLOPT_SSL_VERIFYPEER,(long)opt->flags.check_cert);
  curl_easy_setopt(curl,CURLOPT_CAINFO,opt->ca_cert_file);

  /* Avoid caches to get the most recent copy of the key.  This is bug
     #1061.  In pre-curl versions of the code, we didn't do it.  Then
     we did do it (as a curl default) until curl changed the default.
     Now we're doing it again, but in such a way that changing
     defaults in the future won't impact us.  We set both the Pragma
     and Cache-Control versions of the header, so we're good with both
     HTTP 1.0 and 1.1. */
  headers=curl_slist_append(headers,"Pragma: no-cache");
  if(headers)
    headers=curl_slist_append(headers,"Cache-Control: no-cache");

  if(!headers)
    {
      fprintf(console,"gpgkeys: out of memory when building HTTP headers\n");
      ret=KEYSERVER_NO_MEMORY;
      goto fail;
    }

  curl_easy_setopt(curl,CURLOPT_HTTPHEADER,headers);

  if(proxy)
    curl_easy_setopt(curl,CURLOPT_PROXY,proxy);

  /* If it's a GET or a SEARCH, the next thing to come in is the
     keyids.  If it's a SEND, then there are no keyids. */

  if(opt->action==KS_SEND)
    while(fgets(line,MAX_LINE,input)!=NULL && line[0]!='\n');
  else if(opt->action==KS_GET
	  || opt->action==KS_GETNAME || opt->action==KS_SEARCH)
    {
      for(;;)
	{
	  struct keylist *work;

	  if(fgets(line,MAX_LINE,input)==NULL)
	    break;
	  else
	    {
	      if(line[0]=='\n' || line[0]=='\0')
		break;

	      work=xtrymalloc(sizeof(struct keylist));
	      if(work==NULL)
		{
		  fprintf(console,"gpgkeys: out of memory while "
			  "building key list\n");
		  ret=KEYSERVER_NO_MEMORY;
		  goto fail;
		}

	      strcpy(work->str,line);

	      /* Trim the trailing \n */
	      work->str[strlen(line)-1]='\0';

	      work->next=NULL;

	      /* Always attach at the end to keep the list in proper
                 order for searching */
	      if(keylist==NULL)
		keylist=work;
	      else
		keyptr->next=work;

	      keyptr=work;
	    }
	}
    }
  else
    {
      fprintf(console,"gpgkeys: no keyserver command specified\n");
      goto fail;
    }

  /* Send the response */

  fprintf(output,"VERSION %d\n",KEYSERVER_PROTO_VERSION);
  fprintf(output,"PROGRAM %s %s\n\n",VERSION,curl_version());

  if(opt->verbose>1)
    {
      fprintf(console,"Host:\t\t%s\n",opt->host);
      if(opt->port)
	fprintf(console,"Port:\t\t%s\n",opt->port);
      if(strcmp(opt->path,"/")!=0)
	fprintf(console,"Path:\t\t%s\n",opt->path);
      fprintf(console,"Command:\t%s\n",ks_action_to_string(opt->action));
    }

  if(opt->action==KS_GET)
    {
      keyptr=keylist;

      while(keyptr!=NULL)
	{
	  set_timeout(opt->timeout);

	  if(get_key(keyptr->str)!=KEYSERVER_OK)
	    failed++;

	  keyptr=keyptr->next;
	}
    }
  else if(opt->action==KS_GETNAME)
    {
      keyptr=keylist;

      while(keyptr!=NULL)
	{
	  set_timeout(opt->timeout);

	  if(get_name(keyptr->str)!=KEYSERVER_OK)
	    failed++;

	  keyptr=keyptr->next;
	}
    }
  else if(opt->action==KS_SEND)
    {
      int eof=0;

      do
	{
	  set_timeout(opt->timeout);

	  if(send_key(&eof)!=KEYSERVER_OK)
	    failed++;
	}
      while(!eof);
    }
  else if(opt->action==KS_SEARCH)
    {
      char *searchkey=NULL;
      int len=0;

      set_timeout(opt->timeout);

      /* To search, we stick a space in between each key to search
	 for. */

      keyptr=keylist;
      while(keyptr!=NULL)
	{
	  len+=strlen(keyptr->str)+1;
	  keyptr=keyptr->next;
	}

      searchkey=xtrymalloc(len+1);
      if(searchkey==NULL)
	{
	  ret=KEYSERVER_NO_MEMORY;
	  fail_all(keylist,KEYSERVER_NO_MEMORY);
	  goto fail;
	}

      searchkey[0]='\0';

      keyptr=keylist;
      while(keyptr!=NULL)
	{
	  strcat(searchkey,keyptr->str);
	  strcat(searchkey," ");
	  keyptr=keyptr->next;
	}

      /* Nail that last space */
      if(*searchkey)
	searchkey[strlen(searchkey)-1]='\0';

      if(search_key(searchkey)!=KEYSERVER_OK)
	failed++;

      free(searchkey);
    }
  else
    abort();

  if(!failed)
    ret=KEYSERVER_OK;

 fail:
  while(keylist!=NULL)
    {
      struct keylist *current=keylist;
      keylist=keylist->next;
      free(current);
    }

  if(input!=stdin)
    fclose(input);

  if(output!=stdout)
    fclose(output);

  free_ks_options(opt);

  curl_slist_free_all(headers);

  if(curl)
    curl_easy_cleanup(curl);

  free(proxy);

  return ret;
}
Exemplo n.º 20
0
int imap_fetch_message (CONTEXT *ctx, MESSAGE *msg, int msgno)
{
  IMAP_DATA* idata;
  HEADER* h;
  ENVELOPE* newenv;
  char buf[LONG_STRING];
  char path[_POSIX_PATH_MAX];
  char *pc;
  long bytes;
  progress_t progressbar;
  int uid;
  int cacheno;
  IMAP_CACHE *cache;
  int read;
  int rc;
  /* Sam's weird courier server returns an OK response even when FETCH
   * fails. Thanks Sam. */
  short fetched = 0;

  idata = (IMAP_DATA*) ctx->data;
  h = ctx->hdrs[msgno];

  if ((msg->fp = msg_cache_get (idata, h)))
  {
    if (HEADER_DATA(h)->parsed)
      return 0;
    else
      goto parsemsg;
  }

  /* we still do some caching even if imap_cachedir is unset */
  /* see if we already have the message in our cache */
  cacheno = HEADER_DATA(h)->uid % IMAP_CACHE_LEN;
  cache = &idata->cache[cacheno];

  if (cache->path)
  {
    /* don't treat cache errors as fatal, just fall back. */
    if (cache->uid == HEADER_DATA(h)->uid &&
        (msg->fp = fopen (cache->path, "r")))
      return 0;
    else
    {
      unlink (cache->path);
      FREE (&cache->path);
    }
  }

  if (!isendwin())
    mutt_message _("Fetching message...");

  if (!(msg->fp = msg_cache_put (idata, h)))
  {
    cache->uid = HEADER_DATA(h)->uid;
    mutt_mktemp (path, sizeof (path));
    cache->path = safe_strdup (path);
    if (!(msg->fp = safe_fopen (path, "w+")))
    {
      FREE (&cache->path);
      return -1;
    }
  }

  /* mark this header as currently inactive so the command handler won't
   * also try to update it. HACK until all this code can be moved into the
   * command handler */
  h->active = 0;

  snprintf (buf, sizeof (buf), "UID FETCH %u %s", HEADER_DATA(h)->uid,
	    (mutt_bit_isset (idata->capabilities, IMAP4REV1) ?
	     (option (OPTIMAPPEEK) ? "BODY.PEEK[]" : "BODY[]") :
	     "RFC822"));

  imap_cmd_start (idata, buf);
  do
  {
    if ((rc = imap_cmd_step (idata)) != IMAP_CMD_CONTINUE)
      break;

    pc = idata->buf;
    pc = imap_next_word (pc);
    pc = imap_next_word (pc);

    if (!ascii_strncasecmp ("FETCH", pc, 5))
    {
      while (*pc)
      {
	pc = imap_next_word (pc);
	if (pc[0] == '(')
	  pc++;
	if (ascii_strncasecmp ("UID", pc, 3) == 0)
	{
	  pc = imap_next_word (pc);
	  uid = atoi (pc);
	  if (uid != HEADER_DATA(h)->uid)
	    mutt_error (_("The message index is incorrect. Try reopening the mailbox."));
	}
	else if ((ascii_strncasecmp ("RFC822", pc, 6) == 0) ||
		 (ascii_strncasecmp ("BODY[]", pc, 6) == 0))
	{
	  pc = imap_next_word (pc);
	  if (imap_get_literal_count(pc, &bytes) < 0)
	  {
	    imap_error ("imap_fetch_message()", buf);
	    goto bail;
	  }
	  mutt_progress_init (&progressbar, _("Fetching message..."),
			      MUTT_PROGRESS_SIZE, NetInc, bytes);
	  if (imap_read_literal (msg->fp, idata, bytes, &progressbar) < 0)
	    goto bail;
	  /* pick up trailing line */
	  if ((rc = imap_cmd_step (idata)) != IMAP_CMD_CONTINUE)
	    goto bail;
	  pc = idata->buf;

	  fetched = 1;
	}
	/* UW-IMAP will provide a FLAGS update here if the FETCH causes a
	 * change (eg from \Unseen to \Seen).
	 * Uncommitted changes in mutt take precedence. If we decide to
	 * incrementally update flags later, this won't stop us syncing */
	else if ((ascii_strncasecmp ("FLAGS", pc, 5) == 0) && !h->changed)
	{
	  if ((pc = imap_set_flags (idata, h, pc)) == NULL)
	    goto bail;
	}
      }
    }
  }
  while (rc == IMAP_CMD_CONTINUE);

  /* see comment before command start. */
  h->active = 1;

  fflush (msg->fp);
  if (ferror (msg->fp))
  {
    mutt_perror (cache->path);
    goto bail;
  }

  if (rc != IMAP_CMD_OK)
    goto bail;

  if (!fetched || !imap_code (idata->buf))
    goto bail;

  msg_cache_commit (idata, h);

  parsemsg:
  /* Update the header information.  Previously, we only downloaded a
   * portion of the headers, those required for the main display.
   */
  rewind (msg->fp);
  /* It may be that the Status header indicates a message is read, but the
   * IMAP server doesn't know the message has been \Seen. So we capture
   * the server's notion of 'read' and if it differs from the message info
   * picked up in mutt_read_rfc822_header, we mark the message (and context
   * changed). Another possibility: ignore Status on IMAP?*/
  read = h->read;
  newenv = mutt_read_rfc822_header (msg->fp, h, 0, 0);
  mutt_merge_envelopes(h->env, &newenv);

  /* see above. We want the new status in h->read, so we unset it manually
   * and let mutt_set_flag set it correctly, updating context. */
  if (read != h->read)
  {
    h->read = read;
    mutt_set_flag (ctx, h, MUTT_NEW, read);
  }

  h->lines = 0;
  fgets (buf, sizeof (buf), msg->fp);
  while (!feof (msg->fp))
  {
    h->lines++;
    fgets (buf, sizeof (buf), msg->fp);
  }

  h->content->length = ftell (msg->fp) - h->content->offset;

  /* This needs to be done in case this is a multipart message */
#if defined(HAVE_PGP) || defined(HAVE_SMIME)
  h->security = crypt_query (h->content);
#endif

  mutt_clear_error();
  rewind (msg->fp);
  HEADER_DATA(h)->parsed = 1;

  return 0;

bail:
  safe_fclose (&msg->fp);
  imap_cache_del (idata, h);
  if (cache->path)
  {
    unlink (cache->path);
    FREE (&cache->path);
  }

  return -1;
}
Exemplo n.º 21
0
int rfc3676_handler (BODY * a, STATE * s)
{
  char *buf = NULL, *t = NULL;
  unsigned int quotelevel = 0, newql = 0, sigsep = 0;
  int buf_off = 0, delsp = 0, fixed = 0;
  size_t buf_len = 0, sz = 0;
  flowed_state_t fst;

  memset (&fst, 0, sizeof (fst));

  /* respect DelSp of RfC3676 only with f=f parts */
  if ((t = (char *) mutt_get_parameter ("delsp", a->parameter)))
  {
    delsp = mutt_strlen (t) == 3 && ascii_strncasecmp (t, "yes", 3) == 0;
    t = NULL;
    fst.delsp = 1;
  }

  dprint (4, (debugfile, "f=f: DelSp: %s\n", delsp ? "yes" : "no"));

  while ((buf = mutt_read_line (buf, &sz, s->fpin, NULL, 0)))
  {
    buf_len = mutt_strlen (buf);
    newql = get_quote_level (buf);

    /* end flowed paragraph (if we're within one) if quoting level
     * changes (should not but can happen, see RFC 3676, sec. 4.5.)
     */
    if (newql != quotelevel)
      flush_par (s, &fst);

    quotelevel = newql;
    buf_off = newql;

    /* respect sender's space-stuffing by removing one leading space */
    if (buf[buf_off] == ' ')
      buf_off++;

    /* test for signature separator */
    sigsep = ascii_strcmp (buf + buf_off, "-- ") == 0;

    /* a fixed line either has no trailing space or is the
     * signature separator */
    fixed = buf_len == buf_off || buf[buf_len - 1] != ' ' || sigsep;

    /* print fixed-and-standalone, fixed-and-empty and sigsep lines as
     * fixed lines */
    if ((fixed && (!fst.width || !buf_len)) || sigsep)
    {
      /* if we're within a flowed paragraph, terminate it */
      flush_par (s, &fst);
      print_fixed_line (buf + buf_off, s, quotelevel, &fst);
      continue;
    }

    /* for DelSp=yes, we need to strip one SP prior to CRLF on flowed lines */
    if (delsp && !fixed)
      buf[--buf_len] = '\0';

    print_flowed_line (buf + buf_off, s, quotelevel, &fst, fixed);
  }

  flush_par (s, &fst);

  FREE (&buf);
  return (0);
}
Exemplo n.º 22
0
static int rfc1524_mailcap_parse (BODY *a,
				  char *filename,
				  char *type, 
				  rfc1524_entry *entry,
				  int opt)
{
  FILE *fp;
  char *buf = NULL;
  size_t buflen;
  char *ch;
  char *field;
  int found = FALSE;
  int copiousoutput;
  int composecommand;
  int editcommand;
  int printcommand;
  int btlen;
  int line = 0;

  /* rfc1524 mailcap file is of the format:
   * base/type; command; extradefs
   * type can be * for matching all
   * base with no /type is an implicit wild
   * command contains a %s for the filename to pass, default to pipe on stdin
   * extradefs are of the form:
   *  def1="definition"; def2="define \;";
   * line wraps with a \ at the end of the line
   * # for comments
   */

  /* find length of basetype */
  if ((ch = strchr (type, '/')) == NULL)
    return FALSE;
  btlen = ch - type;

  if ((fp = fopen (filename, "r")) != NULL)
  {
    while (!found && (buf = mutt_read_line (buf, &buflen, fp, &line, M_CONT)) != NULL)
    {
      /* ignore comments */
      if (*buf == '#')
	continue;
      dprint (2, (debugfile, "mailcap entry: %s\n", buf));

      /* check type */
      ch = get_field (buf);
      if (ascii_strcasecmp (buf, type) &&
	  (ascii_strncasecmp (buf, type, btlen) ||
	   (buf[btlen] != 0 &&			/* implicit wild */
	    mutt_strcmp (buf + btlen, "/*"))))	/* wildsubtype */
	continue;

      /* next field is the viewcommand */
      field = ch;
      ch = get_field (ch);
      if (entry)
	entry->command = safe_strdup (field);

      /* parse the optional fields */
      found = TRUE;
      copiousoutput = FALSE;
      composecommand = FALSE;
      editcommand = FALSE;
      printcommand = FALSE;

      while (ch)
      {
	field = ch;
	ch = get_field (ch);
	dprint (2, (debugfile, "field: %s\n", field));

	if (!ascii_strcasecmp (field, "needsterminal"))
	{
	  if (entry)
	    entry->needsterminal = TRUE;
	}
	else if (!ascii_strcasecmp (field, "copiousoutput"))
	{
	  copiousoutput = TRUE;
	  if (entry)
	    entry->copiousoutput = TRUE;
	}
	else if (!ascii_strncasecmp (field, "composetyped", 12))
	{
	  /* this compare most occur before compose to match correctly */
	  if (get_field_text (field + 12, entry ? &entry->composetypecommand : NULL,
			      type, filename, line))
	    composecommand = TRUE;
	}
	else if (!ascii_strncasecmp (field, "compose", 7))
	{
	  if (get_field_text (field + 7, entry ? &entry->composecommand : NULL,
			      type, filename, line))
	    composecommand = TRUE;
	}
	else if (!ascii_strncasecmp (field, "print", 5))
	{
	  if (get_field_text (field + 5, entry ? &entry->printcommand : NULL,
			      type, filename, line))
	    printcommand = TRUE;
	}
	else if (!ascii_strncasecmp (field, "edit", 4))
	{
	  if (get_field_text (field + 4, entry ? &entry->editcommand : NULL,
			      type, filename, line))
	    editcommand = TRUE;
	}
	else if (!ascii_strncasecmp (field, "nametemplate", 12))
	{
	  get_field_text (field + 12, entry ? &entry->nametemplate : NULL,
			  type, filename, line);
	}
	else if (!ascii_strncasecmp (field, "x-convert", 9))
	{
	  get_field_text (field + 9, entry ? &entry->convert : NULL,
			  type, filename, line);
	}
	else if (!ascii_strncasecmp (field, "test", 4))
	{
	  /* 
	   * This routine executes the given test command to determine
	   * if this is the right entry.
	   */
	  char *test_command = NULL;
	  size_t len;

	  if (get_field_text (field + 4, &test_command, type, filename, line)
	      && test_command)
	  {
	    len = mutt_strlen (test_command) + STRING;
	    safe_realloc (&test_command, len);
	    rfc1524_expand_command (a, a->filename, type, test_command, len);
	    if (mutt_system (test_command))
	    {
	      /* a non-zero exit code means test failed */
	      found = FALSE;
	    }
	    FREE (&test_command);
	  }
	}
      } /* while (ch) */

      if (opt == M_AUTOVIEW)
      {
	if (!copiousoutput)
	  found = FALSE;
      }
      else if (opt == M_COMPOSE)
      {
	if (!composecommand)
	  found = FALSE;
      }
      else if (opt == M_EDIT)
      {
	if (!editcommand)
	  found = FALSE;
      }
      else if (opt == M_PRINT)
      {
	if (!printcommand)
	  found = FALSE;
      }
      
      if (!found)
      {
	/* reset */
	if (entry)
	{
	  FREE (&entry->command);
	  FREE (&entry->composecommand);
	  FREE (&entry->composetypecommand);
	  FREE (&entry->editcommand);
	  FREE (&entry->printcommand);
	  FREE (&entry->nametemplate);
	  FREE (&entry->convert);
	  entry->needsterminal = 0;
	  entry->copiousoutput = 0;
	}
      }
    } /* while (!found && (buf = mutt_read_line ())) */
    safe_fclose (&fp);
  } /* if ((fp = fopen ())) */
  FREE (&buf);
  return found;
}
Exemplo n.º 23
0
Arquivo: browse.c Projeto: hww3/pexts
static int browse_get_namespace (IMAP_DATA* idata, char* nsbuf, int nsblen,
  IMAP_NAMESPACE_INFO* nsi, int nsilen, int* nns)
{
  char *s;
  int n;
  char ns[LONG_STRING];
  char delim = '/';
  int type;
  int nsbused = 0;
  int rc;

  *nns = 0;
  nsbuf[nsblen-1] = '\0';

  imap_cmd_start (idata, "NAMESPACE");
  
  do 
  {
    if ((rc = imap_cmd_step (idata)) != IMAP_CMD_CONTINUE)
      break;

    s = imap_next_word (idata->cmd.buf);
    if (ascii_strncasecmp ("NAMESPACE", s, 9) == 0)
    {
      /* There are three sections to the response, User, Other, Shared,
       * and maybe more by extension */
      for (type = IMAP_NS_PERSONAL; *s; type++)
      {
	s = imap_next_word (s);
	if (*s && ascii_strncmp (s, "NIL", 3))
	{
	  s++;
	  while (*s && *s != ')')
	  {
	    s++; /* skip ( */
	    /* copy namespace */
	    n = 0;
	    delim = '\0';

	    if (*s == '\"')
	    {
	      s++;
	      while (*s && *s != '\"') 
	      {
		if (*s == '\\')
		  s++;
		ns[n++] = *s;
		s++;
	      }
	      /* skip trailing ", if we found one, otherwise
	       * imap_next_word will get confused */
	      if (*s)
		s++;
	    }
	    else
	      while (*s && !ISSPACE (*s)) 
	      {
		ns[n++] = *s;
		s++;
	      }
	    ns[n] = '\0';
	    /* delim? */
	    s = imap_next_word (s);
	    /* delimiter is meaningless if namespace is "". Why does
	     * Cyrus provide one?! */
	    if (n && *s && *s == '\"')
	    {
	      if (s[1] && s[2] == '\"')
		delim = s[1];
	      else if (s[1] && s[1] == '\\' && s[2] && s[3] == '\"')
		delim = s[2];
	    }
	    /* skip "" namespaces, they are already listed at the root */
	    if ((ns[0] != '\0') && (nsbused < nsblen) && (*nns < nsilen))
	    {
	      dprint (3, (debugfile, "browse_get_namespace: adding %s\n", ns));
	      nsi->type = type;
	      /* Cyrus doesn't append the delimiter to the namespace,
	       * but UW-IMAP does. We'll strip it here and add it back
	       * as if it were a normal directory, from the browser */
	      if (n && (ns[n-1] == delim))
		ns[--n] = '\0';
	      strncpy (nsbuf+nsbused,ns,nsblen-nsbused-1);
	      nsi->prefix = nsbuf+nsbused;
	      nsbused += n+1;
	      nsi->delim = delim;
	      nsi++;
	      (*nns)++;
	    }
	    while (*s && *s != ')')
	      s++;
	    if (*s)
	      s++;
	  }
	}
      }
    }
  }
  while (rc == IMAP_CMD_CONTINUE);

  if (rc != IMAP_CMD_OK)
    return -1;

  return 0;
}
Exemplo n.º 24
0
int is_from (const char *s, char *path, size_t pathlen, time_t *tp)
{
  struct tm tm;
  int yr;

  if (path)
    *path = 0;

  if (mutt_strncmp ("From ", s, 5) != 0)
    return 0;

  s = next_word (s); /* skip over the From part. */
  if (!*s)
    return 0;

  dprint (3, (debugfile, "\nis_from(): parsing: %s", s));

  if (!is_day_name (s))
  {
    const char *p;
    size_t len;
    short q = 0;

    for (p = s; *p && (q || !ISSPACE (*p)); p++)
    {
      if (*p == '\\')
      {
	if (*++p == '\0') 
	  return 0;
      }
      else if (*p == '"')
      {
	q = !q;
      }
    }

    if (q || !*p) return 0;

    /* pipermail archives have the return_path obscured such as "me at mutt.org" */
    if (ascii_strncasecmp(p, " at ", 4) == 0)
    {
      p = strchr(p + 4, ' ');
      if (!p)
      {
	dprint (1, (debugfile, "is_from(): error parsing what appears to be a pipermail-style obscured return_path: %s\n", s));
	return 0;
      }
    }
    
    if (path)
    {
      len = (size_t) (p - s);
      if (len + 1 > pathlen)
	len = pathlen - 1;
      memcpy (path, s, len);
      path[len] = 0;
      dprint (3, (debugfile, "is_from(): got return path: %s\n", path));
    }
    
    s = p + 1;
    SKIPWS (s);
    if (!*s)
      return 0;

    if (!is_day_name (s))
    {
      dprint(1, (debugfile, "is_from():  expected weekday, got: %s\n", s));
      return 0;
    }
  }

  s = next_word (s);
  if (!*s) return 0;

  /* do a quick check to make sure that this isn't really the day of the week.
   * this could happen when receiving mail from a local user whose login name
   * is the same as a three-letter abbreviation of the day of the week.
   */
  if (is_day_name (s))
  {
    s = next_word (s);
    if (!*s) return 0;
  }

  /* now we should be on the month. */
  if ((tm.tm_mon = mutt_check_month (s)) < 0) return 0;

  /* day */
  s = next_word (s);
  if (!*s) return 0;
  if (sscanf (s, "%d", &tm.tm_mday) != 1) return 0;

  /* time */
  s = next_word (s);
  if (!*s) return 0;

  /* Accept either HH:MM or HH:MM:SS */
  if (sscanf (s, "%d:%d:%d", &tm.tm_hour, &tm.tm_min, &tm.tm_sec) == 3);
  else if (sscanf (s, "%d:%d", &tm.tm_hour, &tm.tm_min) == 2)
    tm.tm_sec = 0;
  else
    return 0;

  s = next_word (s);
  if (!*s) return 0;

  /* timezone? */
  if (isalpha ((unsigned char) *s) || *s == '+' || *s == '-')
  {
    s = next_word (s);
    if (!*s) return 0;

    /*
     * some places have two timezone fields after the time, e.g.
     *      From [email protected] Wed Aug  2 00:39:12 MET DST 1995
     */
    if (isalpha ((unsigned char) *s))
    {
      s = next_word (s);
      if (!*s) return 0;
    }
  }

  /* year */
  if (sscanf (s, "%d", &yr) != 1) return 0;
  tm.tm_year = yr > 1900 ? yr - 1900 : (yr < 70 ? yr + 100 : yr);
  
  dprint (3,(debugfile, "is_from(): month=%d, day=%d, hr=%d, min=%d, sec=%d, yr=%d.\n",
	     tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_year));

  tm.tm_isdst = -1;

  if (tp) *tp = mutt_mktime (&tm, 0);
  return 1;
}
Exemplo n.º 25
0
/* Take a time string and convert it into an ebus style time.  Ebus
   time is the number of 10 second intervals since Monday 0:00 local
   time. (uint16_t)(-1) is returned on error.

   Supported formats are:

     hh:mm[:sx]    - Hour, minute and 10 seconds on Monday
     w hh:mm[:sx]  - Ditto with weekday specified
     ndhh:mm[:sx]  - Ditto with weekday give as Monday (0) to  Sunday (6)

   with

     hh = Hour
     mm = Minutes
     sx = Seconds with the lower digit ignored
     w  = Weekday name (mo,tu,we,th,fr,sa,su)
                    or (mon,tue,wed,thu,fri,sat,sun)
          in any capitalization.
 */
uint16_t
timestr_to_ebustime (char const *string, char **r_endp)
{
  int i, n;
  int weekday = 0;
  int hour = 0;
  int minute = 0;
  int second = 0;
  char const *s;
  char *endp;

  if (!string)
    return INVALID_TIME;

  for (; *string && ascii_isspace (*string); string++)
    ;

  if (*string >= '0' && *string <= '6' && string[1] == 'd')
    {
      weekday = *string - '0';
      string += 2;
    }
  else if ((*string >= 'a' && *string < 'z')
           || (*string >= 'A' && *string < 'Z'))
    {
      static struct { char no; char const * const name; } tbl[] = {
        { 0, "mo" }, { 0, "mon" }, { 0, "monday" },
        { 1, "tu" }, { 1, "tue" }, { 1, "tuesday" },
        { 2, "we" }, { 2, "wed" }, { 2, "wednesday" },
        { 3, "th" }, { 3, "thu" }, { 3, "thursday" },
        { 4, "fr" }, { 4, "fri" }, { 4, "friday" },
        { 5, "sa" }, { 5, "sat" }, { 5, "saturday" },
        { 6, "su" }, { 6, "sun" }, { 6, "sunday" }};

      for (s=string+1; *s; s++)
        if (ascii_isspace (*s))
          break;
      n = s - string;
      for (i=0; i < DIM (tbl); i++)
        if (strlen (tbl[i].name) == n
            && !ascii_strncasecmp (string, tbl[i].name, n))
          break;
      if (!(i < DIM (tbl)))
        return INVALID_TIME;
      weekday = tbl[i].no;
      for (; *s && ascii_isspace (*s); s++)
        ;
      string = s;
    }

  if (!digitp (string))
    return INVALID_TIME;
  hour = strtol (string, &endp, 10);
  if (hour < 0 || hour > 23 || *endp != ':')
    return INVALID_TIME;
  string = endp + 1;
  minute = strtol (string, &endp, 10);
  if (!digitp (string) || !digitp (string+1) || minute < 0 || minute > 59)
    return INVALID_TIME;
  if (*endp == ':')
    {
      string = endp + 1;
      second = strtol (string, &endp, 10);
      /* Note: We don't care about leap seconds.  */
      if (!digitp (string) || !digitp (string+1) || second < 0 || second > 59)
        return INVALID_TIME;
    }

  if (!*endp)
    string = endp;
  else if (ascii_isspace (*endp))
    string = endp + 1;
  else
    return INVALID_TIME;

  if (r_endp)
    *r_endp = (char *)string;

  return (weekday * 24 * 60 * 6
          + hour * 60 * 6
          + minute * 6
          + second / 10);
}
Exemplo n.º 26
0
double str_to_double(tokenizer_t *self, char *str)
{
    char *tmp;
    double val;
    errno = 0;

    if (self->use_fast_converter)
    {
        val = xstrtod(str, &tmp, '.', self->expchar, ',', 1);

        if (*tmp)
        {
            goto conversion_error;
        }
        else if (errno == ERANGE)
        {
            self->code = OVERFLOW_ERROR;
        }
        else if (errno == EDOM)        // xstrtod signalling invalid exponents
        {
            self->code = CONVERSION_ERROR;
        }

        return val;
    }

    else
    {
        val = strtod(str, &tmp);

        if (errno == EINVAL || tmp == str || *tmp != '\0')
        {
            goto conversion_error;
        }
        else if (errno == ERANGE)
        {
            self->code = OVERFLOW_ERROR;
        }
        else if (errno == EDOM)
        {
            self->code = CONVERSION_ERROR;
        }

        return val;
    }

conversion_error:
    // Handle inf and nan values for xstrtod and platforms whose strtod
    // doesn't support this
    val = 1.0;
    tmp = str;

    if (*tmp == '+')
    {
        tmp++;
    }
    else if (*tmp == '-')
    {
        tmp++;
        val = -1.0;
    }

    if (0 == ascii_strncasecmp(tmp, "nan", 3))
    {
        // Handle optional nan type specifier; this is ignored
        tmp += 3;
        val = NAN;
    }
    else if (0 == ascii_strncasecmp(tmp, "inf", 3))
    {
        tmp += 3;
        if (0 == ascii_strncasecmp(tmp, "inity", 5))
        {
            tmp += 5;
        }
        val *= INFINITY;
    }

    if (tmp == str || *tmp != '\0')
    {
        self->code = CONVERSION_ERROR;
        val = 0;
    }

    return val;
}
Exemplo n.º 27
0
static int address_header_decode (char **h)
{
  char *s = *h;
  int l, rp = 0;

  ADDRESS *a = NULL;
  ADDRESS *cur = NULL;

  switch (tolower ((unsigned char) *s))
  {
    case 'r': 
    {
      if (ascii_strncasecmp (s, "return-path:", 12) == 0)
      {
	l = 12;
	rp = 1;
	break;
      }
      else if (ascii_strncasecmp (s, "reply-to:", 9) == 0)
      {
	l = 9;
	break;
      }
      return 0;
    }
    case 'f': 
    {
      if (ascii_strncasecmp (s, "from:", 5)) 
	return 0; 
      l = 5;
      break;
    }
    case 'c':
    {
      if (ascii_strncasecmp (s, "cc:", 3))
	return 0;
      l = 3;
      break;
      
    }
    case 'b':
    {
      if (ascii_strncasecmp (s, "bcc:", 4))
	return 0;
      l = 4;
      break;
    }
    case 's':
    {
      if (ascii_strncasecmp (s, "sender:", 7))
	return 0;
      l = 7;
      break;
    }
    case 't':
    {
      if (ascii_strncasecmp (s, "to:", 3))
	return 0;
      l = 3;
      break;
    }
    case 'm':
    {
      if (ascii_strncasecmp (s, "mail-followup-to:", 17))
	return 0;
      l = 17;
      break;
    }
    default: return 0;    
  }

  if ((a = rfc822_parse_adrlist (a, s + l)) == NULL)
    return 0;
  
  mutt_addrlist_to_local (a);
  rfc2047_decode_adrlist (a);
  for (cur = a; cur; cur = cur->next)
    if (cur->personal)
      rfc822_dequote_comment (cur->personal);

  /* angle brackets for return path are mandated by RfC5322,
   * so leave Return-Path as-is */
  if (rp)
    *h = safe_strdup (s);
  else
  {
    *h = safe_calloc (1, l + 2);
    strfcpy (*h, s, l + 1);
    format_address_header (h, a);
  }

  rfc822_free_address (&a);

  FREE (&s);
  return 1;
}
Exemplo n.º 28
0
/* args:
 *      ctx	Context info, used when recalling a message to which
 *              we reply.
 *	hdr	envelope/attachment info for recalled message
 *	cur	if message was a reply, `cur' is set to the message which
 *		`hdr' is in reply to
 *	fcc	fcc for the recalled message
 *	fcclen	max length of fcc
 *
 * return vals:
 *	-1		error/no messages
 *	0		normal exit
 *	SENDREPLY	recalled message is a reply
 */
int mutt_get_postponed (CONTEXT * ctx, HEADER * hdr, HEADER ** cur, char *fcc,
                        size_t fcclen)
{
  HEADER *h;
  int code = SENDPOSTPONED;
  LIST *tmp;
  LIST *last = NULL;
  LIST *next;
  char *p;
  int opt_delete;

  if (!Postponed)
    return (-1);

  if ((PostContext = mx_open_mailbox (Postponed, M_NOSORT, NULL)) == NULL) {
    PostCount = 0;
    mutt_error _("No postponed messages.");

    return (-1);
  }

  if (!PostContext->msgcount) {
    PostCount = 0;
    mx_close_mailbox (PostContext, NULL);
    mem_free (&PostContext);
    mutt_error _("No postponed messages.");

    return (-1);
  }

  if (PostContext->msgcount == 1) {
    /* only one message, so just use that one. */
    h = PostContext->hdrs[0];
  }
  else if ((h = select_msg ()) == NULL) {
    mx_close_mailbox (PostContext, NULL);
    mem_free (&PostContext);
    return (-1);
  }

  if (mutt_prepare_template (NULL, PostContext, hdr, h, 0) < 0) {
    mx_fastclose_mailbox (PostContext);
    mem_free (&PostContext);
    return (-1);
  }

  /* finished with this message, so delete it. */
  mutt_set_flag (PostContext, h, M_DELETE, 1);

  /* and consider it saved, so that it won't be moved to the trash folder */
  mutt_set_flag (PostContext, h, M_APPENDED, 1);

  /* update the count for the status display */
  PostCount = PostContext->msgcount - PostContext->deleted;

  /* avoid the "purge deleted messages" prompt */
  opt_delete = quadoption (OPT_DELETE);
  set_quadoption (OPT_DELETE, M_YES);
  mx_close_mailbox (PostContext, NULL);
  set_quadoption (OPT_DELETE, opt_delete);

  mem_free (&PostContext);

  for (tmp = hdr->env->userhdrs; tmp;) {
    if (ascii_strncasecmp ("X-Mutt-References:", tmp->data, 18) == 0) {
      if (ctx) {
        /* if a mailbox is currently open, look to see if the orignal message
           the user attempted to reply to is in this mailbox */
        p = tmp->data + 18;
        SKIPWS (p);
        if (!ctx->id_hash)
          ctx->id_hash = mutt_make_id_hash (ctx);
        *cur = hash_find (ctx->id_hash, p);
      }

      /* Remove the X-Mutt-References: header field. */
      next = tmp->next;
      if (last)
        last->next = tmp->next;
      else
        hdr->env->userhdrs = tmp->next;
      tmp->next = NULL;
      mutt_free_list (&tmp);
      tmp = next;
      if (*cur)
        code |= SENDREPLY;
    }
    else if (ascii_strncasecmp ("X-Mutt-Fcc:", tmp->data, 11) == 0) {
      p = tmp->data + 11;
      SKIPWS (p);
      strfcpy (fcc, p, fcclen);
      mutt_pretty_mailbox (fcc);

      /* remove the X-Mutt-Fcc: header field */
      next = tmp->next;
      if (last)
        last->next = tmp->next;
      else
        hdr->env->userhdrs = tmp->next;
      tmp->next = NULL;
      mutt_free_list (&tmp);
      tmp = next;
    }
    else if ((WithCrypto & APPLICATION_PGP)
             && (str_ncmp ("Pgp:", tmp->data, 4) == 0       /* this is generated
                                                                 * by old mutt versions
                                                                 */
                 || str_ncmp ("X-Mutt-PGP:", tmp->data, 11) == 0)) {
      hdr->security = mutt_parse_crypt_hdr (strchr (tmp->data, ':') + 1, 1);
      hdr->security |= APPLICATION_PGP;

      /* remove the pgp field */
      next = tmp->next;
      if (last)
        last->next = tmp->next;
      else
        hdr->env->userhdrs = tmp->next;
      tmp->next = NULL;
      mutt_free_list (&tmp);
      tmp = next;
    }
    else if ((WithCrypto & APPLICATION_SMIME)
             && str_ncmp ("X-Mutt-SMIME:", tmp->data, 13) == 0) {
      hdr->security = mutt_parse_crypt_hdr (strchr (tmp->data, ':') + 1, 1);
      hdr->security |= APPLICATION_SMIME;

      /* remove the smime field */
      next = tmp->next;
      if (last)
        last->next = tmp->next;
      else
        hdr->env->userhdrs = tmp->next;
      tmp->next = NULL;
      mutt_free_list (&tmp);
      tmp = next;
    }

#ifdef MIXMASTER
    else if (str_ncmp ("X-Mutt-Mix:", tmp->data, 11) == 0) {
      char *t;

      mutt_free_list (&hdr->chain);

      t = strtok (tmp->data + 11, " \t\n");
      while (t) {
        hdr->chain = mutt_add_list (hdr->chain, t);
        t = strtok (NULL, " \t\n");
      }

      next = tmp->next;
      if (last)
        last->next = tmp->next;
      else
        hdr->env->userhdrs = tmp->next;
      tmp->next = NULL;
      mutt_free_list (&tmp);
      tmp = next;
    }
#endif

    else {
      last = tmp;
      tmp = tmp->next;
    }
  }
  return (code);
}
Exemplo n.º 29
0
/* args:
 *      ctx	Context info, used when recalling a message to which
 *              we reply.
 *	hdr	envelope/attachment info for recalled message
 *	cur	if message was a reply, `cur' is set to the message which
 *		`hdr' is in reply to
 *	fcc	fcc for the recalled message
 *	fcclen	max length of fcc
 *
 * return vals:
 *	-1		error/no messages
 *	0		normal exit
 *	SENDREPLY	recalled message is a reply
 */
int mutt_get_postponed (CONTEXT *ctx, HEADER *hdr, HEADER **cur, char *fcc, size_t fcclen)
{
  HEADER *h;
  int code = SENDPOSTPONED;
  LIST *tmp;
  LIST *last = NULL;
  LIST *next;
  const char *p;
  int opt_delete;

  if (!Postponed)
    return (-1);

  if ((PostContext = mx_open_mailbox (Postponed, M_NOSORT, NULL)) == NULL)
  {
    PostCount = 0;
    mutt_error _("No postponed messages.");
    return (-1);
  }

  if (! PostContext->msgcount)
  {
    PostCount = 0;
    mx_close_mailbox (PostContext, NULL);
    FREE (&PostContext);
    mutt_error _("No postponed messages.");
    return (-1);
  }

  if (PostContext->msgcount == 1)
  {
    /* only one message, so just use that one. */
    h = PostContext->hdrs[0];
  }
  else if ((h = select_msg ()) == NULL)
  {
    mx_close_mailbox (PostContext, NULL);
    FREE (&PostContext);
    return (-1);
  }

  if (mutt_prepare_template (NULL, PostContext, hdr, h, 0) < 0)
  {
    mx_fastclose_mailbox (PostContext);
    FREE (&PostContext);
    return (-1);
  }

  /* finished with this message, so delete it. */
  mutt_set_flag (PostContext, h, M_DELETE, 1);

  /* update the count for the status display */
  PostCount = PostContext->msgcount - PostContext->deleted;

  /* avoid the "purge deleted messages" prompt */
  opt_delete = quadoption (OPT_DELETE);
  set_quadoption (OPT_DELETE, M_YES);
  mx_close_mailbox (PostContext, NULL);
  set_quadoption (OPT_DELETE, opt_delete);

  FREE (&PostContext);

  for (tmp = hdr->env->userhdrs; tmp; )
  {
    if (ascii_strncasecmp ("X-Mutt-References:", tmp->data, 18) == 0)
    {
      if (ctx)
      {
	/* if a mailbox is currently open, look to see if the orignal message
	   the user attempted to reply to is in this mailbox */
	p = skip_email_wsp(tmp->data + 18);
	if (!ctx->id_hash)
	  ctx->id_hash = mutt_make_id_hash (ctx);
	*cur = hash_find (ctx->id_hash, p);
      }

      /* Remove the X-Mutt-References: header field. */
      next = tmp->next;
      if (last)
	last->next = tmp->next;
      else
	hdr->env->userhdrs = tmp->next;
      tmp->next = NULL;
      mutt_free_list (&tmp);
      tmp = next;
      if (*cur)
	code |= SENDREPLY;
    }
    else if (ascii_strncasecmp ("X-Mutt-Fcc:", tmp->data, 11) == 0)
    {
      p = skip_email_wsp(tmp->data + 11);
      strfcpy (fcc, p, fcclen);
      mutt_pretty_mailbox (fcc, fcclen);

      /* remove the X-Mutt-Fcc: header field */
      next = tmp->next;
      if (last)
	last->next = tmp->next;
      else
	hdr->env->userhdrs = tmp->next;
      tmp->next = NULL;
      mutt_free_list (&tmp);
      tmp = next;
     /* note that x-mutt-fcc was present.  we do this because we want to add a
      * default fcc if the header was missing, but preserve the request of the
      * user to not make a copy if the header field is present, but empty.
      * see http://dev.mutt.org/trac/ticket/3653
      */
      code |= SENDPOSTPONEDFCC;
    }
    else if ((WithCrypto & APPLICATION_PGP)
             && (mutt_strncmp ("Pgp:", tmp->data, 4) == 0 /* this is generated
						       * by old mutt versions
						       */
                 || mutt_strncmp ("X-Mutt-PGP:", tmp->data, 11) == 0))
    {
      hdr->security = mutt_parse_crypt_hdr (strchr (tmp->data, ':') + 1, 1,
					    APPLICATION_PGP);
      hdr->security |= APPLICATION_PGP;

      /* remove the pgp field */
      next = tmp->next;
      if (last)
	last->next = tmp->next;
      else
	hdr->env->userhdrs = tmp->next;
      tmp->next = NULL;
      mutt_free_list (&tmp);
      tmp = next;
    }
    else if ((WithCrypto & APPLICATION_SMIME)
             && mutt_strncmp ("X-Mutt-SMIME:", tmp->data, 13) == 0)
    {
      hdr->security = mutt_parse_crypt_hdr (strchr (tmp->data, ':') + 1, 1,
					    APPLICATION_SMIME);
      hdr->security |= APPLICATION_SMIME;

      /* remove the smime field */
      next = tmp->next;
      if (last)
	last->next = tmp->next;
      else
	hdr->env->userhdrs = tmp->next;
      tmp->next = NULL;
      mutt_free_list (&tmp);
      tmp = next;
    }

#ifdef MIXMASTER
    else if (mutt_strncmp ("X-Mutt-Mix:", tmp->data, 11) == 0)
    {
      char *t;
      mutt_free_list (&hdr->chain);

      t = strtok (tmp->data + 11, " \t\n");
      while (t)
      {
	hdr->chain = mutt_add_list (hdr->chain, t);
	t = strtok (NULL, " \t\n");
      }

      next = tmp->next;
      if (last)
	last->next = tmp->next;
      else
	hdr->env->userhdrs = tmp->next;
      tmp->next = NULL;
      mutt_free_list (&tmp);
      tmp = next;
    }
#endif

    else
    {
      last = tmp;
      tmp = tmp->next;
    }
  }

  if (option (OPTCRYPTOPPORTUNISTICENCRYPT))
    crypt_opportunistic_encrypt (hdr);

  return (code);
}
Exemplo n.º 30
0
int
main(int argc,char *argv[])
{
  int arg,ret=KEYSERVER_INTERNAL_ERROR,i;
  char line[MAX_LINE];
  char *thekey=NULL;
  long follow_redirects=5;
  char *proxy=NULL;
  curl_version_info_data *curldata;
  struct curl_slist *headers=NULL;

  console=stderr;

  /* Kludge to implement standard GNU options.  */
  if (argc > 1 && !strcmp (argv[1], "--version"))
    {
      printf ("gpgkeys_curl (GnuPG) %s\n", VERSION);
      printf ("Uses: %s\n", curl_version());
      return 0;
    }
  else if (argc > 1 && !strcmp (argv[1], "--help"))
    {
      show_help (stdout);
      return 0;
    }

  while((arg=getopt(argc,argv,"hVo:"))!=-1)
    switch(arg)
      {
      default:
      case 'h':
        show_help (console);
	return KEYSERVER_OK;

      case 'V':
	fprintf(stdout,"%d\n%s\n",KEYSERVER_PROTO_VERSION,VERSION);
	return KEYSERVER_OK;

      case 'o':
	output=fopen(optarg,"wb");
	if(output==NULL)
	  {
	    fprintf(console,"gpgkeys: Cannot open output file `%s': %s\n",
		    optarg,strerror(errno));
	    return KEYSERVER_INTERNAL_ERROR;
	  }

	break;
      }

  if(argc>optind)
    {
      input=fopen(argv[optind],"r");
      if(input==NULL)
	{
	  fprintf(console,"gpgkeys: Cannot open input file `%s': %s\n",
		  argv[optind],strerror(errno));
	  return KEYSERVER_INTERNAL_ERROR;
	}
    }

  if(input==NULL)
    input=stdin;

  if(output==NULL)
    output=stdout;

  opt=init_ks_options();
  if(!opt)
    return KEYSERVER_NO_MEMORY;

  /* Get the command and info block */

  while(fgets(line,MAX_LINE,input)!=NULL)
    {
      int err;
      char option[MAX_OPTION+1];

      if(line[0]=='\n')
	break;

      err=parse_ks_options(line,opt);
      if(err>0)
	{
	  ret=err;
	  goto fail;
	}
      else if(err==0)
	continue;

      if(sscanf(line,"OPTION %" MKSTRING(MAX_OPTION) "s\n",option)==1)
	{
	  int no=0;
	  char *start=&option[0];

	  option[MAX_OPTION]='\0';

	  if(ascii_strncasecmp(option,"no-",3)==0)
	    {
	      no=1;
	      start=&option[3];
	    }

	  if(ascii_strncasecmp(start,"http-proxy",10)==0)
	    {
	      /* Safe to not check the return code of strdup() here.
		 If it fails, we simply won't use a proxy. */
	      if(no)
		{
		  free(proxy);
		  proxy=strdup("");
		}
	      else if(start[10]=='=')
		{
		  if(strlen(&start[11])<MAX_PROXY)
		    {
		      free(proxy);
		      proxy=strdup(&start[11]);
		    }
		}
	    }
	  else if(ascii_strncasecmp(start,"follow-redirects",16)==0)
	    {
	      if(no)
		follow_redirects=0;
	      else if(start[16]=='=')
		follow_redirects=atoi(&start[17]);
	      else if(start[16]=='\0')
		follow_redirects=-1;
	    }

	  continue;
	}
    }

  if(!opt->scheme)
    {
      fprintf(console,"gpgkeys: no scheme supplied!\n");
      ret=KEYSERVER_SCHEME_NOT_FOUND;
      goto fail;
    }

  if(!opt->host)
    {
      fprintf(console,"gpgkeys: no keyserver host provided\n");
      goto fail;
    }

  if(opt->timeout && register_timeout()==-1)
    {
      fprintf(console,"gpgkeys: unable to register timeout handler\n");
      return KEYSERVER_INTERNAL_ERROR;
    }

  curl_global_init(CURL_GLOBAL_DEFAULT);

  curl=curl_easy_init();
  if(!curl)
    {
      fprintf(console,"gpgkeys: unable to initialize curl\n");
      ret=KEYSERVER_INTERNAL_ERROR;
      goto fail;
    }

  /* Make sure we have the protocol the user is asking for so we can
     print a nicer error message. */
  curldata=curl_version_info(CURLVERSION_NOW);
  for(i=0;curldata->protocols[i];i++)
    if(ascii_strcasecmp(curldata->protocols[i],opt->scheme)==0)
      break;

  if(curldata->protocols[i]==NULL)
    {
      fprintf(console,"gpgkeys: protocol `%s' not supported\n",opt->scheme);
      ret=KEYSERVER_SCHEME_NOT_FOUND;
      goto fail;
    }

  if(follow_redirects)
    {
      curl_easy_setopt(curl,CURLOPT_FOLLOWLOCATION,1L);
      if(follow_redirects>0)
	curl_easy_setopt(curl,CURLOPT_MAXREDIRS,follow_redirects);
    }

  if(opt->auth)
    curl_easy_setopt(curl,CURLOPT_USERPWD,opt->auth);

  if(opt->debug)
    {
      fprintf(console,"gpgkeys: curl version = %s\n",curl_version());
      curl_easy_setopt(curl,CURLOPT_STDERR,console);
      curl_easy_setopt(curl,CURLOPT_VERBOSE,1L);
    }

  curl_easy_setopt(curl,CURLOPT_SSL_VERIFYPEER,(long)opt->flags.check_cert);
  if (opt->ca_cert_file)
    curl_easy_setopt (curl, CURLOPT_CAINFO, opt->ca_cert_file);

  /* Avoid caches to get the most recent copy of the key.  This is bug
     #1061.  In pre-curl versions of the code, we didn't do it.  Then
     we did do it (as a curl default) until curl changed the default.
     Now we're doing it again, but in such a way that changing
     defaults in the future won't impact us.  We set both the Pragma
     and Cache-Control versions of the header, so we're good with both
     HTTP 1.0 and 1.1. */
  headers=curl_slist_append(headers,"Pragma: no-cache");
  if(headers)
    headers=curl_slist_append(headers,"Cache-Control: no-cache");

  if(!headers)
    {
      fprintf(console,"gpgkeys: out of memory when building HTTP headers\n");
      ret=KEYSERVER_NO_MEMORY;
      goto fail;
    }

  curl_easy_setopt(curl,CURLOPT_HTTPHEADER,headers);

  if(proxy)
    curl_easy_setopt(curl,CURLOPT_PROXY,proxy);

  /* If it's a GET or a SEARCH, the next thing to come in is the
     keyids.  If it's a SEND, then there are no keyids. */

  if(opt->action==KS_GET)
    {
      /* Eat the rest of the file */
      for(;;)
	{
	  if(fgets(line,MAX_LINE,input)==NULL)
	    break;
	  else
	    {
	      if(line[0]=='\n' || line[0]=='\0')
		break;

	      if(!thekey)
		{
		  thekey=strdup(line);
		  if(!thekey)
		    {
		      fprintf(console,"gpgkeys: out of memory while "
			      "building key list\n");
		      ret=KEYSERVER_NO_MEMORY;
		      goto fail;
		    }

		  /* Trim the trailing \n */
		  thekey[strlen(line)-1]='\0';
		}
	    }
	}
    }
  else
    {
      fprintf(console,
	      "gpgkeys: this keyserver type only supports key retrieval\n");
      goto fail;
    }

  if(!thekey)
    {
      fprintf(console,"gpgkeys: invalid keyserver instructions\n");
      goto fail;
    }

  /* Send the response */

  fprintf(output,"VERSION %d\n",KEYSERVER_PROTO_VERSION);
  fprintf(output,"PROGRAM %s\n\n",VERSION);

  if(opt->verbose)
    {
      fprintf(console,"Scheme:\t\t%s\n",opt->scheme);
      fprintf(console,"Host:\t\t%s\n",opt->host);
      if(opt->port)
	fprintf(console,"Port:\t\t%s\n",opt->port);
      if(opt->path)
	fprintf(console,"Path:\t\t%s\n",opt->path);
      fprintf(console,"Command:\tGET\n");
    }

  set_timeout(opt->timeout);

  ret=get_key(thekey);

 fail:

  free(thekey);

  if(input!=stdin)
    fclose(input);

  if(output!=stdout)
    fclose(output);

  free_ks_options(opt);

  curl_slist_free_all(headers);

  if(curl)
    curl_easy_cleanup(curl);

  free(proxy);

  curl_global_cleanup();

  return ret;
}