Beispiel #1
0
static int
test_and_update_prop (mu_property_t prop, const char *from,
		      time_t now, unsigned int days,
		      mu_sieve_machine_t mach)
{
  const char *result;
  char *timebuf;
  time_t last;
  
  int rc = mu_property_sget_value (prop, from, &result);
  switch (rc)
    {
    case MU_ERR_NOENT:
      break;
      
    case 0:
      if (days == 0)
	return 1;
      last = (time_t) strtoul (result, NULL, 0);
      if (last + (24 * 60 * 60 * days) > now)
	return 1;
      break;
      
    default:
      mu_sieve_error (mach, "%lu: mu_property_sget_value: %s",
		      (unsigned long) mu_sieve_get_message_num (mach),
		      mu_strerror (rc));
      return -1;
    }

  rc = mu_asprintf (&timebuf, "%lu", (unsigned long) now);
  if (rc)
    {
      mu_sieve_error (mach, "%lu: mu_asprintf: %s",
		      (unsigned long) mu_sieve_get_message_num (mach),
		      mu_strerror (rc));
      return -1;
    } 
     
  rc = mu_property_set_value (prop, from, timebuf, 1);
  free (timebuf);
  if (rc)
    {
      mu_sieve_error (mach, "%lu: mu_property_set_value: %s",
		      (unsigned long) mu_sieve_get_message_num (mach),
		      mu_strerror (rc));
      return -1;
    }
  
  rc = mu_property_save (prop);
  if (rc)
    {
      mu_sieve_error (mach, "%lu: mu_property_save: %s",
		      (unsigned long) mu_sieve_get_message_num (mach),
		      mu_strerror (rc));
      return -1;
    }
  return 0;
}
Beispiel #2
0
/* Syntax: addheader [:last] <field-name: string> <value: string>
 */
int
sieve_addheader (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags)
{
  mu_sieve_value_t *val;
  const char *field_name;
  const char *field_value;
  mu_message_t msg;
  mu_header_t hdr;
  int rc;
  
  val = mu_sieve_value_get (args, 0);
  if (!val)
    {
      mu_sieve_error (mach, "%lu: %s",
		      (unsigned long) mu_sieve_get_message_num (mach),
		      _("cannot get field name"));
      mu_sieve_abort (mach);
    }
  field_name = val->v.string;

  val = mu_sieve_value_get (args, 1);
  if (!val)
    {
      mu_sieve_error (mach, "%lu: %s",
		      (unsigned long) mu_sieve_get_message_num (mach),
		      _("cannot get field value"));
      mu_sieve_abort (mach);
    }
  field_value = val->v.string;

  mu_sieve_log_action (mach, "ADDHEADER", "%s: %s", field_name, field_value);

  if (mu_sieve_is_dry_run (mach))
    return 0;

  msg = mu_sieve_get_message (mach);
  rc = mu_message_get_header (msg, &hdr);
  if (rc)
    {
      mu_sieve_error (mach, "%lu: %s: %s",
		      (unsigned long) mu_sieve_get_message_num (mach),
		      _("cannot get message header"),
		      mu_strerror (rc));
      mu_sieve_abort (mach);
    }

  rc = (mu_sieve_tag_lookup (tags, "last", NULL) ?
	mu_header_append : mu_header_prepend) (hdr, field_name, field_value);
  if (rc)
    {
      mu_sieve_error (mach, "%lu: %s: %s",
		      (unsigned long) mu_sieve_get_message_num (mach),
		      _("cannot append message header"),
		      mu_strerror (rc));
      mu_sieve_abort (mach);
    }
  return 0;
}
Beispiel #3
0
/* Add a reply prefix to the subject. *PSUBJECT points to the
   original subject, which must be allocated using malloc. Before
   returning its value is freed and replaced with the new one.
   Default reply prefix is "Re: ", unless overridden by
   "reply_prefix" tag.
 */
static void
re_subject (mu_sieve_machine_t mach, mu_list_t tags, char **psubject)
{
  char *subject;
  mu_sieve_value_t *arg;
  char *prefix = "Re";
  
  if (mu_sieve_tag_lookup (tags, "reply_prefix", &arg))
    {
      prefix = arg->v.string;
    }

  subject = malloc (strlen (*psubject) + strlen (prefix) + 3);
  if (!subject)
    {
      mu_sieve_error (mach,
		      _("%lu: not enough memory"),
		      (unsigned long) mu_sieve_get_message_num (mach));
      return;
    }
  
  strcpy (subject, prefix);
  strcat (subject, ": ");
  strcat (subject, *psubject);
  free (*psubject);
  *psubject = subject;
}
Beispiel #4
0
static int
regex_comparator (void *item, void *data)
{
  regex_t preg;
  int rc;
  struct regex_data *d = data;
  
  if (regcomp (&preg, item,
	       REG_EXTENDED | REG_NOSUB | REG_NEWLINE | REG_ICASE))
    {
      mu_sieve_error (d->mach,
		      _("%lu: cannot compile regular expression \"%s\""),
		      (unsigned long) mu_sieve_get_message_num (d->mach),
		      (char*) item);
      return 0;
    }
  rc = regexec (&preg, d->email, 0, NULL, 0) == 0;
  regfree (&preg);
  return rc;
}
Beispiel #5
0
static int
moderator_action (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags)
{
  mu_message_t msg, orig;
  int rc;
  size_t nparts = 0;
  int discard = 0;
  int ismime;
  
  if (mu_sieve_get_debug_level (mach) & MU_SIEVE_DEBUG_TRACE)
    {
      mu_sieve_debug (mach, "moderator_test %lu",
		      (unsigned long) mu_sieve_get_message_num (mach));
    }

  msg = mu_sieve_get_message (mach);
  mu_message_is_multipart (msg, &ismime);

  if (!ismime)
    {
      mu_sieve_error (mach, _("message is not multipart"));
      mu_sieve_abort (mach);
    }

  mu_message_get_num_parts (msg, &nparts);

  if (nparts != 3) /* Mailman moderation requests have three parts */
    {
      mu_sieve_error (mach, _("expected 3 parts, but found %lu"),
		      (unsigned long) nparts);
      mu_sieve_abort (mach);
    }

  if ((rc = moderator_message_get_part (mach, msg, 2, &orig)))
    mu_sieve_abort (mach);

  rc = moderator_filter_message (mach, tags, orig, &discard);
  mu_message_unref (orig);
  if (rc)
    mu_sieve_abort (mach);

  if (discard && !mu_sieve_is_dry_run (mach))
    {
      mu_message_t request;
      char *from = NULL;
      mu_sieve_value_t *arg;
      
      if ((rc = moderator_message_get_part (mach, msg, 3, &request)))
	{
	  mu_sieve_error (mach, _("cannot get message part #3: %s"),
			  mu_strerror (rc));
	  mu_sieve_abort (mach);
	}

      if (mu_sieve_tag_lookup (tags, "address", &arg))
	from = arg->v.string;
      
      if (moderator_discard_message (mach, request, from))
	discard = 0;
      else
	{
	  if (!mu_sieve_tag_lookup (tags, "keep", NULL))
	    {
	      mu_attribute_t attr = 0;

	      if (mu_message_get_attribute (msg, &attr) == 0)
		mu_attribute_set_deleted (attr);
	    }
	  else
	    discard = 0;
	}
      mu_message_unref (request);
    }

  mu_sieve_log_action (mach, "MODERATOR", 
		       discard ? _("discarding message") :
		       _("keeping message"));
  return 0;
}
Beispiel #6
0
int
sieve_action_vacation (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags)
{
  int rc;
  char *text, *from;
  mu_sieve_value_t *val;
  mu_message_t msg;
  mu_header_t hdr;
  char *my_address = mu_sieve_get_daemon_email (mach);
  
  if (diag (mach))
    return 0;
  
  val = mu_sieve_value_get (args, 0);
  if (!val)
    {
      mu_sieve_error (mach, _("cannot get text!"));
      mu_sieve_abort (mach);
    }
  else
    text = val->v.string;

  msg = mu_sieve_get_message (mach);
  mu_message_get_header (msg, &hdr);

  if (mu_sieve_tag_lookup (tags, "sender", &val))
    {
      /* Debugging hook: :sender sets fake reply address */
      from = strdup (val->v.string);
      if (!from)
        {
          mu_sieve_error (mach, "%lu: %s",
                          (unsigned long) mu_sieve_get_message_num (mach),
                          mu_strerror (ENOMEM));
          mu_sieve_abort (mach);
        }
    }
  else if (mu_sieve_get_message_sender (msg, &from))
    {
      mu_sieve_error (mach,
		      _("%lu: cannot get sender address"),
		      (unsigned long) mu_sieve_get_message_num (mach));
      mu_sieve_abort (mach);
    }

  if (mu_sieve_tag_lookup (tags, "aliases", &val)
      && match_addresses (hdr, val, &my_address) == 0)
    return 0;

  if (noreply_address_p (mach, tags, from)
      || bulk_precedence_p (hdr)
      || check_db (mach, tags, from))
    {
      free (from);
      return 0;
    }

  rc = vacation_reply (mach, tags, msg, text, from, my_address);
  free (from);
  if (rc == -1)
    mu_sieve_abort (mach);
  return rc;
}
Beispiel #7
0
/* Generate and send the reply message */
static int
vacation_reply (mu_sieve_machine_t mach, mu_list_t tags, mu_message_t msg,
		char *text, char *to, char *from)
{
  mu_mime_t mime = NULL;
  mu_message_t newmsg;
  mu_header_t newhdr;
  mu_address_t to_addr = NULL, from_addr = NULL;
  char *value;
  mu_mailer_t mailer;
  int rc;

  if (mu_sieve_tag_lookup (tags, "file", NULL))
    {
      mu_stream_t instr;
      
      rc = mu_mapfile_stream_create (&instr, text, MU_STREAM_READ);
      if (rc)
	{
	  mu_sieve_error (mach,
			  _("%lu: cannot open message file %s: %s"),
			  (unsigned long) mu_sieve_get_message_num (mach),
			  text,
			  mu_strerror (rc));
	  return -1;
	}
      rc = mu_stream_to_message (instr, &newmsg);
      mu_stream_unref (instr);
      if (rc)
	{
	  mu_sieve_error (mach,
			  _("%lu: cannot read message from file %s: %s"),
			  (unsigned long) mu_sieve_get_message_num (mach),
			  text,
			  mu_strerror (rc));
	  return -1;
	} 
    }
  else
    {
      if (build_mime (mach, tags, &mime, msg, text))
	return -1;
      mu_mime_get_message (mime, &newmsg);
      mu_message_unref (newmsg);
      mu_message_get_header (newmsg, &newhdr);
    }
  
  rc = mu_address_create (&to_addr, to);
  if (rc)
    {
      mu_sieve_error (mach,
		      _("%lu: cannot create recipient address <%s>: %s"),
		      (unsigned long) mu_sieve_get_message_num (mach),
		      from, mu_strerror (rc));
    }
  else
    {
      mu_header_set_value (newhdr, MU_HEADER_TO, to, 0);
      
      vacation_subject (mach, tags, msg, newhdr);
      
      if (from)
        {
          if (mu_address_create (&from_addr, from))
	    from_addr = NULL;
        }
      else
        {
          from_addr = NULL;
        }
      
      if (mu_rfc2822_in_reply_to (msg, &value) == 0)
        {
          mu_header_set_value (newhdr, MU_HEADER_IN_REPLY_TO, value, 1);
          free (value);
        }
      
      if (mu_rfc2822_references (msg, &value) == 0)
        {
          mu_header_set_value (newhdr, MU_HEADER_REFERENCES, value, 1);
          free (value);
        }
      
      mailer = mu_sieve_get_mailer (mach);
      if (mailer)
	{
	  rc = mu_mailer_send_message (mailer, newmsg, from_addr, to_addr);
	}
      else
	rc = MU_ERR_FAILURE;
    }
  mu_address_destroy (&to_addr);
  mu_address_destroy (&from_addr);
  mu_mime_destroy (&mime);
  return rc;
}
Beispiel #8
0
static void
vacation_subject (mu_sieve_machine_t mach, mu_list_t tags,
		  mu_message_t msg, mu_header_t newhdr)
{
  mu_sieve_value_t *arg;
  char *value;
  char *subject;
  int subject_allocated = 0;
  mu_header_t hdr;
  
  if (mu_sieve_tag_lookup (tags, "subject", &arg))
    subject =  arg->v.string;
  else if (mu_message_get_header (msg, &hdr) == 0
	   && mu_header_aget_value_unfold (hdr, MU_HEADER_SUBJECT,
					   &value) == 0)
    {
      char *p;
      
      int rc = mu_rfc2047_decode (MU_SIEVE_CHARSET, value, &p);

      subject_allocated = 1;
      if (rc)
	{
	  subject = value;
	  value = NULL;
	}
      else
	{
	  subject = p;
	}

      if (mu_sieve_tag_lookup (tags, "reply_regex", &arg))
	{
	  char *err = NULL;
	  
	  rc = mu_unre_set_regex (arg->v.string, 0, &err);
	  if (rc)
	    {
	      mu_sieve_error (mach,
			      _("%lu: cannot compile reply prefix regexp: %s: %s"),
			      (unsigned long) mu_sieve_get_message_num (mach),
			      mu_strerror (rc),
			      err ? err : "");
	    }
	}
	  
      if (mu_unre_subject (subject, NULL))
	re_subject (mach, tags, &subject);
      
      free (value);
    }
  else
    subject = "Re: Your mail";
    
  if (mu_rfc2047_encode (MU_SIEVE_CHARSET, "quoted-printable",
			 subject, &value))
    mu_header_set_value (newhdr, MU_HEADER_SUBJECT, subject, 0);
  else
    {
      mu_header_set_value (newhdr, MU_HEADER_SUBJECT, value, 0);
      free (value);
    }

  if (subject_allocated)
    free (subject);
}
Beispiel #9
0
/* Check and update the vacation database. Return 0 if the mail should
   be answered, 0 if it should not, and throw exception if an error
   occurs. */
static int
check_db (mu_sieve_machine_t mach, mu_list_t tags, char *from)
{
  mu_property_t prop;
  char *file;
  mu_sieve_value_t *arg;
  unsigned int days;
  int rc;
  mu_stream_t str;
  mu_locker_t locker;
  
  if (mu_sieve_tag_lookup (tags, "days", &arg))
    {
      days = arg->v.number;
      if (days > DAYS_MAX)
	days = DAYS_MAX;
    }
  else
    days = DAYS_DEFAULT;

  file = mu_tilde_expansion ("~/.vacation", MU_HIERARCHY_DELIMITER, NULL);
  if (!file)
    {
      mu_sieve_error (mach, _("%lu: cannot build db file name"),
		      (unsigned long) mu_sieve_get_message_num (mach));
      mu_sieve_abort (mach);
    }

  rc = mu_locker_create (&locker, file, 0);
  if (rc)
    {
      mu_sieve_error (mach, _("%lu: cannot lock %s: %s"),
		      (unsigned long) mu_sieve_get_message_num (mach),
		      file,
		      mu_strerror (rc));
      free (file);
      mu_sieve_abort (mach);
    }

  rc = mu_file_stream_create (&str, file, MU_STREAM_RDWR|MU_STREAM_CREAT);
  if (rc)
    {
      mu_sieve_error (mach, "%lu: mu_file_stream_create(%s): %s",
		      (unsigned long) mu_sieve_get_message_num (mach),
		      file,
		      mu_strerror (rc));
      mu_locker_destroy (&locker);
      free (file);
      mu_sieve_abort (mach);
    }
  
  free (file);

  rc = mu_property_create_init (&prop, mu_assoc_property_init, str);
  if (rc)
    {
      mu_sieve_error (mach, "%lu: mu_property_create_init: %s",
		      (unsigned long) mu_sieve_get_message_num (mach),
		      mu_strerror (rc));
      mu_locker_destroy (&locker);
      mu_sieve_abort (mach);
    }

  rc = mu_locker_lock (locker);
  if (rc)
    {
      mu_sieve_error (mach, "%lu: cannot lock vacation database: %s",
		      (unsigned long) mu_sieve_get_message_num (mach),
		      mu_strerror (rc));
      mu_property_destroy (&prop);
      mu_sieve_abort (mach);
    }

  rc = test_and_update_prop (prop, from, time (NULL), days, mach);
  mu_property_destroy (&prop);
  mu_locker_unlock (locker);
  mu_locker_destroy (&locker);
  if (rc == -1)
    mu_sieve_abort (mach);

  return rc;
}
Beispiel #10
0
/* Syntax: deleteheader [:index <fieldno: number> [:last]]
                        [COMPARATOR] [MATCH-TYPE]
                        <field-name: string>
                        [<value-patterns: string-list>]
 */
int
sieve_deleteheader (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags)
{
  mu_sieve_value_t *val;
  const char *field_name;
  const char *field_pattern;
  mu_message_t msg;
  mu_header_t hdr;
  int rc;
  mu_sieve_comparator_t comp;
  mu_iterator_t itr;
  unsigned long i, idx = 0;
  
  val = mu_sieve_value_get (args, 0);
  if (!val)
    {
      mu_sieve_error (mach, "%lu: %s",
		      (unsigned long) mu_sieve_get_message_num (mach),
		      _("cannot get field name"));
      mu_sieve_abort (mach);
    }
  field_name = val->v.string;

  val = mu_sieve_value_get (args, 1);
  if (!val)
    {
      field_pattern = NULL;
      mu_sieve_log_action (mach, "DELETEHEADER", "%s", field_name);
    }
  else
    {
      switch (val->type)
	{
	case SVT_STRING_LIST:
	  if (mu_list_get (val->v.list, 0, (void**)&field_pattern))
	    {
	      mu_sieve_error (mach, "%lu: %s",
			      (unsigned long) mu_sieve_get_message_num (mach),
			      _("cannot get list item"));
	      mu_sieve_abort (mach);
	    }
	  mu_sieve_log_action (mach, "DELETEHEADER", "%s: (regexp)",
			       field_name);
	  break;
	  
	case SVT_STRING:
	  field_pattern = val->v.string;
	  mu_sieve_log_action (mach, "DELETEHEADER", "%s: %s", field_name,
			       field_pattern);
	  break;

	default:
	  mu_sieve_error (mach, "%lu: %s: %d",
			  (unsigned long) mu_sieve_get_message_num (mach),
			  _("unexpected value type"), val->type);
	  mu_sieve_abort (mach);
	  
	}
    }
  
  if (mu_sieve_is_dry_run (mach))
    return 0;

  msg = mu_sieve_get_message (mach);
  rc = mu_message_get_header (msg, &hdr);
  if (rc)
    {
      mu_sieve_error (mach, "%lu: %s: %s",
		      (unsigned long) mu_sieve_get_message_num (mach),
		      _("cannot get message header"),
		      mu_strerror (rc));
      mu_sieve_abort (mach);
    }

  mu_header_get_iterator (hdr, &itr);
  if (mu_sieve_tag_lookup (tags, "last", NULL))
    {
      int backwards = 1;
      mu_iterator_ctl (itr, mu_itrctl_set_direction, &backwards);
    }
  comp = mu_sieve_get_comparator (mach, tags);

  if (mu_sieve_tag_lookup (tags, "index", &val))
    idx = val->v.number;
  
  for (i = 0, mu_iterator_first (itr); !mu_iterator_is_done (itr);
       mu_iterator_next (itr))
    {
      const char *fn, *fv;

      mu_iterator_current_kv (itr, (const void **)&fn, (void **)&fv);
      if (strcmp (field_name, fn))
	continue;
      if (idx && ++i < idx)
	continue;
	  
      if (field_pattern)
	{
	  if (comp (field_pattern, fv))
	    mu_iterator_ctl (itr, mu_itrctl_delete, NULL);
	}
      else
	mu_iterator_ctl (itr, mu_itrctl_delete, NULL);

      if (idx)
	break;
    }
  mu_iterator_destroy (&itr);
  return 0;
}