Maildrop
- Maildrop
- Versión
- Introducción
- Depurando
- maildroprc
- Órdenes
- cc expresion
- dotlock
- echo expresion
- exception
- exit
- flock expresion
- foreach
- if
- import variable
- include archivo
- logfile archivo
- log expresion
- to expresion
- while
- xfilter external_program
- ||
- &&
- Comparaciones numéricas
- Comparaciones alfanuméricas
- |
- &
- Operaciones numéricas
- Búsqueda de patrones contra un texto
- Búsqueda de patrones contra el mensaje
- !
- Escapando caracteres especiales
- Acceso a GDBM
- Extraer direcciones en formato RFC 2822
- Buscar una dirección
- Longitud de un texto
- Búsqueda con un archivo de patrones
- Extrayendo subcadenas
- Leyendo la fecha y la hora
- Convirtiendo a minúsculas
- Convirtiendo a mayúsculas
Versión
Estas notas referencian la versión 2.0.2-11 del paquete Debian (maildrop).
Introducción
Es un programa muy efectivo para despachar correo en carpetas, pero también bastante puñetero en cuanto a funcionamiento.
Lo primero que quiero registrar es que cuando funciona en modo de despacho directo (deliver mode) no funciona la opción de depuración (verbose level), porque es ignorada completamente. Como tampoco se queja de que la incluyas en la línea de llamada ó en alguno de los archivos de reglas de filtrado, no vas a enterarte de nada de lo ocurre a menos que recuerdes esta circunstancia.
El programa permite que exista un archivo global de reglas de filtrado situado
en /etc/maildroprc
y que lee antes que el de usuario en $HOME/.mailfilter
,
por lo que hay que ser cuidadoso con lo que allí guardas ya que lo usarán
todos los otros usuarios del sistema.
Depurando
Cuando es necesario depurar el funcionamiento de maildrop la mejor opción es
invocarlo desde el usuario final, con el que se han registrado los fallos
temporales, código 75 y nombre EX_TEMPFAIL
.
# su usuario
$ maildrop -V 9
En este ejemplo estoy cambiando al usuario en cuestión desde
root
debido a que tengo usuarios virtuales y no es fácil hacerlo desde otra cuenta con menos privilegios.
maildroprc
A continuación, y siguiendo el orden de la página de manual, extractos de su contenido.
Estructura léxica
- La mayor parte de los espacios en blanco se ignoran
- Los comentarios se marcan con el carácter sostenido
#
y alcanzan hasta el final de la línea. - maildrop lee el archivo de filtrado y lo valida antes de leer el mensaje
de correo. Si hay algún error sintáctico retorna un error temporal
EX_TEMPFAIL
. - El carácter de fin de línea es un token léxico, por lo que para
continuarla en otra es necesario añadir una barra atrás
\
al final de la misma.
Texto literal
- Para introducir un texto literal hay que entrecomillarlo, bien con comillas simples, bien con comillas dobles.
- Los literales consecutivos se concatenan automáticamente.
- Para escapar un carácter se precede con una barra atrás
\
.
Sustitución de variables
- Los nombres de variables deben comenzar por una letra en mayúsculas ó
minúsculas, ó un carácter subrayado
_
. - La sustitución de variables sólo se da dentro de textos literales con entrecomillado doble, no el simple.
Dentro de estos literales las variables a sustituir pueden nombrarse mediante el prefijo dólar
$
y, opcionalmente, encerrados entre llaves.MAILBOX="$HOME/Maildir" MAILBOX="${HOME}/Maildir"
Parámetros de llamada
- maildrop toma los restantes paŕametros que ha recibido en su llamada e
inicializa las variables
$1
,$2
, ... , que pueden utilizarse como cualquier otra variable.
Variables predefinidas
maildrop define automáticamente un juego de variables que nunca importa del entorno, y cuyos valores por defecto pueden ser definidos por el administrador.
Estas variables son:
- DEFAULT: El buzón predeterminado al que enviar el mensaje si el archivo de reglas de filtrado no define otro valor.
FROM:
El emisor del sobre del mensaje, es decir, la dirección desde la que se efectuó la conexión de correo. Puede estar vacío en caso de mensajes especiales como los rebotes, y su valor se toma de los siguientes lugares en este orden:- El parámetro
-f
de maildrop. - La línea
From
del mensaje (diferente del campoFrom:
). - El identificador de usuario que llama al programa.
- El parámetro
- HOME: Directorio raíz del usuario que ejecuta el programa.
- HOSTNAME:
Nombre de red de la máquina que ejecuta el programa (obtenida mediante
gethostname(3)
). - LOCKEXT:
Extensión que usan los archivos de bloqueo (dot-lock files):
.lock
. - LOCKREFRESH: Tiempo de refresco (en segundos) del bloqueo del buzón.
- LOCKSLEEP: Tiempo de espera (en segundos) para intentar bloquear un buzón de correo si ya existe un bloqueo posterior.
- LOCKTIMEOUT: Tiempo límite (en segundos también) para desbloquear un buzón por la fuerza. maildrop asume que pasado este tiempo no debe existir bloqueos sobre un buzón de correo.
- LOGNAME: Nombre del usuario receptor del mensaje.
- MAILDROPOLDREGEXP: Indicador que vuelve al antiguo motor de expresiones regulares si por alguna razón no se quiere utilizar PCRE, vigente desde la versión 2.0. Cuidado_, este sistema será abandonado en versiones futuras, y este parámetro sólo debería servir como herramienta de transición entre reglas de filtrado antiguas y nuevas.
- MAILFILTER:
Nombre del archivo de reglas de filtrado original recibidas por el
programa maildrop cuando ha sido llamado. Permite pues obtener el valor
del parámetro
-M
. - PATH: Ruta de ejecución de comandos. maildrop toma inicialmente el valor predeterminado en el sistema.
- SENDMAIL:
Agente de despacho de correo. Cuando maildrop recibe como buzón de correo
una dirección prefijada con un cierre de admiración
!
entiende que debe reenviar el mensaje, y para ello usa el valor de esta variable. - SHELL: Programa shell con el cual ejecutar cualquier programa externo.
- VERBOSE:
Nivel de mensajes de depuración cuyo valor inicial es cero (0). Puede
variar entre 0 y 9, siendo éste último el que más valor informativo
proporciona.
Aviso: para no confundir al programa de transporte de correo que llama
a maildrop este valor se ignora completamente en modo de despacho de
correo (
-d
). - UMASK:
Máscara de permisos de creación de archivos en base octal. El valor
predeterminado es `077', lo que hace que los buzones sólo puedan ser
leídos y modificados por el dueño.
Otros valores son:
007
: legible y modificable por el usuario y el grupo.037
: legible por el usuario y el grupo pero modificables sólo por el usuario. Es de señalar que esta máscara sólo se aplica a buzones nuevos; los que ya existen no se alteran.
Variables especiales en ejecución
Las siguientes variables se utilizan cuando maildrop está procesando las reglas de filtrado:
- EXITCODE:
Código de salida de maildrop que será cero (0) cuando haya despachado el
mensaje satisfactoriamente. En el caso de tener que usar un programa
externo ó una tubería (usando las órdenes
to
ócc
) esta variable toma el valor de salida de dicho recurso externo, y si éste no genera un código interpretable es necesario modificar la variable antes de efectuar el despacho. - KEYWORDS:
Se emplea únicamente cuando el mensaje va a para a un
maildir
(tengo pendiente ampliar el tema). - LINES: Número de líneas en el mensaje actual, que pueden ser una aproximación al número real.
- MAILDIRQUOTA: Tamaño máximo de cualquier buzón de correo donde el mensaje vaya a ser despachado.
- RETURNCODE:
Código de salida de un programa externo ejecutado mediante
xfilter
ó acentos graves (\\
). - SIZE: Tamaño en bytes del mensaje actual.
Texto no entrecomillado
- Si un texto literal sólo incluye letras, números ó alguno de estos
caracteres
_-.:/${}@
puede aparecer sin entrecomillado, aunque se recomienda que se entrecomille siempre. - La única excepción a lo anterior es si el texto ocupa más de una línea en el archivo, entonces debe entrecomillarse.
Programas externos
El texto que aparezca entre acentos graves (backticks) es interpretado como llamadas a programas mediante el programa
$SHELL
, y el resultado que produzca se puede recoger en una variable ó usarse en una expresión tras sufrir ciertas transformaciones:DIR=`ls`
Dichas transformaciones son:
- Los caracteres de fin de línea se reemplazan por espacios.
- Se eliminan los caracteres sueltos al principio y al final del texto.
Importante: el programa exterior recibe una copia del mensaje en su entrada estándar.
Patrones de búsqueda
/patron/:opciones
- Un patrón especifica el texto a buscar en un mensaje.
- Los patrones de búsqueda de maildrop son similares a los del programa
grep
con diferencias menores. - No pueden comenzar con un espacio en blanco porque sino la primera barra
sería considerada un operador de división numérica. En caso necesario
tendremos que usar la fórmula
/[ ].../
. - La síntaxis general de los patrones de búsqueda se describe en la página de manual
pcrepattern
con las siguientes excepciones:- No funcionan las búsquedas con UTF8.
- No hay soporte para opciones internas.
- Los patrones con nombre no están implementados, aunque sí lo están los patrones numerados.
Opciones de búsqueda
- Las opciones de búsqueda aparecen tras el patrón, separadas con dos puntos,
y pueden ser alguna ó todas las siguientes, sin importar el orden:
h
compara el patrón con el contenido de la cabecera del mensajeb
compara el patrón con el contenido del cuerpo del mensajeD
diferencia en las búsquedas entre mayúsculas y minúsculas; lo contrario es el funcionamiento predeterminado.
- Si no aparecen ninguna de las dos opciones
b
yh
la búsqueda se efectúa sólo sobre la cabecera del mensaje. - El patrón se aplica a cada línea individualmente, aunque en el caso de las cabeceras, si se encuentran campos multilíneas (terminadas con una barra atrás) se unen en una antes de aplicar el patrón.
Resultados de búsqueda
En el momento en que una búsqueda con patrón resulta verdadera el texto se
guarda en la variable MATCH
que puede utilizarse a renglón seguido.
El siguiente patrón
/^From:.*/
hace que la línea From: postmaster@localhost
sea almacenada en la variable
MATCH
, mientras que si usamos un patrón con subpatrones como en
/^From:\s+(.*)@(.*)/
obtendremos postmaster en la variable MATCH1
y localhost en la variable
MATCH2
, es decir, tantas variables MATCH
como subpatrones encuentre.
Nota: los subpatrones no son procesados por una instrucción
foreach
.
Expresiones
- Los resultados de las expresiones se almacenan alfanuméricamente, aunque la comparación sea numérica.
- Si es necesario se convierte de texto a número antes de realizar una operación matemática, y el resultado se almacena siempre en texto.
Órdenes
cc expresion
- Esta órden despacha una copia del mensaje según la expresión indicada y
continúa el filtro desde ese punto. La expresión es más delicada de lo que
parece, sus posibilidades están descritas en la orden
to
.
dotlock
dotlock archivo_de_bloqueo {
...
}
- Crea un bloqueo usando un archivo, en lugar de una llamada al sistema
flock()
. - maildrop crea si puede el archivo de bloqueo, ejecuta el bloque de código y lo borra cuando termina.
echo expresion
- Usa expresion como un texto y lo envía a la salida estándar. Útil para depuración.
exception
exception {
...
}
- Atrapa errores fatales encontrados durante la ejecución de código evitando que maildrop aborte la ejecución.
- Continúa con el filtro tras ejecutar el bloque.
exit
- Termina incondicionalmente la ejecución del programa, utilizando el valor de
$EXITCODE
como salida.
flock expresion
flock archivo_a_bloquear {
...
}
- Crea un bloqueo utilizando la llamada al sistema
flock()
.
foreach
foreach /pattern/:options
{
...
}
foreach (expression) =~ /pattern/:options
{
...
}
- Ejecuta un bloque de código por cada ocurrencia del patrón de búsqueda.
- En cada iteración la variable
MATCH
toma el valor de la cadena encontrada por el patrón.
if
if (expresion)
{
...
}
else
{
...
}
- Ejecución condicional de código según la expresión.
- La claúsula
else
es opcional. - Si la expresión toma el valor numerico cero (0) ó el valor textual vacío se considera un valor falso.
- La síntaxis de la claúsula if es muy estricta y pueden darse muchos
errores sintácticos. Es importante asegurarse de que la palabra reservada
if
y las llaves están en líneas separadas; más concretamente, los paréntesis y las llaves de cierre, y la palabra reservadaelse
deben aparecer al final de la línea, aunque se admiten comentarios. Eso sí, no admite líneas en blanco entre los elementos, ni aunque lleven sólo un comentario.
import variable
- Importa el contenido de la variable de entorno variable.
include archivo
- Lee el contenido de un archivo fuente de reglas y lo ejecuta inmediatamente.
- Cualquier error sintáctico en dicho archivo, dado que esto se hace en tiempo
de ejecución, provocará un fallo de maildrop con un código
EX_TEMPFAIL
. - Igualmente si el archivo no existe.
logfile archivo
- Indica a maildrop que use el archivo como destino donde registrar dónde han ido a parar los mensajes.
- Si el archivo existe se abre para añadir contenido.
log expresion
- Usa la expresion como texto para enviar al registro de actividades.
to expresion
- Despacha el mensaje al destino indicado en la expresión y puede tomar alguno
de estos valores:
- Un archivo de correo en formato
mailbox
en el caso de que apunte a un archivo. - Un buzón de correo en formato
maildir
en el caso de que apunte a un directorio. - Un programa externo mediante una tubería (y usando
$SHELL
) si comienza con una barra vertical (|
). - Una lista de direcciones, separadas por comas, si comienza con un
carácter cierre de admiración (
!
), a las que enviar el mensaje (usando$SENDMAIL
).
- Un archivo de correo en formato
- Termina inmediatamente después de despachar el mensaje.
- Antes de situar el correo en un archivo ó buzón se usará un sistema de
bloqueo para el mismo (bien
flock()
, biendot-lock
).
while
while (expresion)
{
...
}
- La expresión se evalúa contínuamente hasta que se obtiene un resultado falso.
- Pueden crearse bucles infinitos fácilmente (cuidado).
xfilter external_program
- Toma el mensaje activo y lo entuba hacía el programa externo indicado.
- La salida resultante de la llamada sustituye al mensaje activo.
- El programa externo debe terminar con un código de salida verdadero (0).
- maildrop terminará con un código de error temporal
EX_TEMPFAIL
en caso de no recibir un código de salida cero ó en caso de que el programa no lea su entrada estándar.
||
expresion1 || expresion2
- Operador lógico OR.
- Si expresion1 es verdadera se toma como resultado para toda la operación.
- Si expresion1 es falsa se toma como resultado la evaluación de expresion2.
&&
expresion1 && expresion2
- Si expresion1 es falsa se toma como resultado para toda la operación.
- Si expresion1 es verdadera se toma como resultado la evaluación de expresion2.
Comparaciones numéricas
- Existen los siguientes operadores:
<
menor que<=
menor ó igual que>
mayor que>=
mayor ó igual que==
igual que!=
distinto de
- Las comparaciones se efectúan previa conversión a valor en punto flotante de ambos operandos.
- El resultado es, sin embargo, el texto "1" si es verdadero y "0" si es falso.
Comparaciones alfanuméricas
- Existen los siguientes operadores:
lt
menor quele
menor ó igual quegt
mayor quege
mayor ó igual queeq
igual quene
distinto de
- Las comparaciones se efectúan tomando como textos los dos operandos y usando ordenación alfabética sin importar el contenido real.
- El resultado es el texto "1" si es verdadero y "0" si es falso.
|
expresion1 | expresion2
- Operación OR a nivel de bits.
- El resultado es una entero de 32 bits.
&
expresion1 & expresion2
- Operacion AND a nivel de bits.
- El resultado es una entero de 32 bits.
Operaciones numéricas
- Estos son los posibles operadores numéricos:
+
suma-
resta*
multiplicación/
división
- Igual que con las comparaciones numéricas, se trabaja con operandos convertidos a cifras en punto flotante.
Búsqueda de patrones contra un texto
Búsqueda de patrones contra el mensaje
!
! expresion
- Efectúa una negación lógica de la expresión dada.
- Existe una versión a nivel de bit con el operador
~
, que efectúa un complemento a nivel de bits con el valor numérico de la expresion.
Escapando caracteres especiales
escape(expresion)
- Toma una expresión y retorna su contenido escapando cada carácter especial que encuentre con un carácter barra atrás (
\
). - Los caracteres considerados especiales son: |!$()[]+*?.&;`'-~<>^{}"
Acceso a GDBM
- Existe un juego de funciones que permite acceder a bases de datos de tipo GDBM: gdbmopen, gdbmclose, gdbmfetch y gdbmstore.
- Esta capacidad puede ser anulada por el administrador.
Extraer direcciones en formato RFC 2822
ADDR=getaddr($expresion)
- La función
getaddr
extrae direcciones según la norma descrita en el RFC 2822 de la expresión pasada como parámetro. No es necesario eliminar los literales
To:
óCc:
de la expresión:ADDRLIST="" foreach /^(To|Cc): .*/ { foreach (getaddr $MATCH) =~ /.+/ { ADDRLIST="$ADDRLIST $MATCH" } }
Buscar una dirección
if (hasaddr(expresion))
{
...
}
- La expresión debe tomar la disposición
usuario@dominio
. - La función
hasaddr()
retornará 1 si la dirección se encuentra en alguno de estas cabeceras del mensaje:To:
,Cc:
,Resent-To:
óResent-Cc:
. - Las cabeceras sufren un preprocesado acorde al RFC822, tras el que son extraídas las direcciones de correo y descartados los comentarios y nombres.
- Con las direcciones obtenidas es con las que se compara la expresión, ignorando la diferenciación entre mayúsculas y minúsculas.
Longitud de un texto
if (length(texto) > 80)
{
...
}
- La función
length()
retorna el número de caracteres que ocupa un texto.
Búsqueda con un archivo de patrones
if (lookup(expresion, archivo, opciones))
{
...
}
- Expresión puede ser cualquier cosa que maildrop entienda como tal.
- Archivo es la ruta a uno que contiene una lista de patrones. Es relativa al directorio de trabajo de maildrop.
- El archivo de patrones puede contener líneas en blanco y comentarios (
#
) que no se tendrán en cuenta. - Los patrones aparecen uno por cada línea, de donde se eliminan los carácteres en blanco al principio de la misma, pero no los del final.
- El texto resultante se utiliza como un patrón de búsqueda contra el texto.
- En cuanto encuentra la primera concidencia la función retorna "1" y "0" en caso de agotar la lista de patrones.
- Las opciones son las que se utilizan en una búsqueda normal, aunque la única
reconocida por el momento es
D
.
El siguiente ejemplo comprueba si la dirección del encabezado del mensaje está en una lista negra y lo descarta.
if ( /^To:\s*(.*)/ && lookup( $MATCH1, "badto.dat" ))
{
exit
}
y el contenido del archivo puede ser algo como
friend@public
^[^@]*$
y que instruye al filtro a coincidir con la dirección friend@public
o con una dirección que no contenga una arroba @
.
Extrayendo subcadenas
foo = substr(expresion, posicion, longitud)
- La función
substr()
toma tantos caracteres como se indique enlongitud
a partir de la posición dada porposicion
.
Leyendo la fecha y la hora
- La función
time
retorna la fecha y hora actual, en número de segundos desde el 1 de Enero de 1970.
Convirtiendo a minúsculas
tolower( expresion )
- La función
tolower()
devuelve el texto con las letras mayúsculas convertidas a minúsculas.
Convirtiendo a mayúsculas
toupper( expresion )
- La función
toupper()
devuelve el texto con las letras minúsculas convertidas a mayúsculas.