fdm-1.7/compat/strlcat.c010064400017500001750000000033371112127572500154660ustar00nicholasnicholas/* $Id: strlcat.c,v 1.1 2006/11/19 17:00:39 nicm Exp $ */ /* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */ /* * Copyright (c) 1998 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include "fdm.h" /* * Appends src to string dst of size siz (unlike strncat, siz is the * full size of dst, not space left). At most siz-1 characters * will be copied. Always NUL terminates (unless siz <= strlen(dst)). * Returns strlen(src) + MIN(siz, strlen(initial dst)). * If retval >= siz, truncation occurred. */ size_t strlcat(char *dst, const char *src, size_t siz) { char *d = dst; const char *s = src; size_t n = siz; size_t dlen; /* Find the end of dst and adjust bytes left but don't go past end */ while (n-- != 0 && *d != '\0') d++; dlen = d - dst; n = siz - dlen; if (n == 0) return(dlen + strlen(s)); while (*s != '\0') { if (n != 1) { *d++ = *s; n--; } s++; } *d = '\0'; return(dlen + (s - src)); /* count does not include NUL */ } fdm-1.7/compat/queue.h010064400017500001750000000433011112127572500151360ustar00nicholasnicholas/* $Id: queue.h,v 1.2 2006/12/09 20:43:57 nicm Exp $ */ /* $OpenBSD: queue.h,v 1.31 2005/11/25 08:06:25 otto Exp $ */ /* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */ /* * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)queue.h 8.5 (Berkeley) 8/20/94 */ #ifndef _SYS_QUEUE_H_ #define _SYS_QUEUE_H_ /* * This file defines five types of data structures: singly-linked lists, * lists, simple queues, tail queues, and circular queues. * * * A singly-linked list is headed by a single forward pointer. The elements * are singly linked for minimum space and pointer manipulation overhead at * the expense of O(n) removal for arbitrary elements. New elements can be * added to the list after an existing element or at the head of the list. * Elements being removed from the head of the list should use the explicit * macro for this purpose for optimum efficiency. A singly-linked list may * only be traversed in the forward direction. Singly-linked lists are ideal * for applications with large datasets and few or no removals or for * implementing a LIFO queue. * * A list is headed by a single forward pointer (or an array of forward * pointers for a hash table header). The elements are doubly linked * so that an arbitrary element can be removed without a need to * traverse the list. New elements can be added to the list before * or after an existing element or at the head of the list. A list * may only be traversed in the forward direction. * * A simple queue is headed by a pair of pointers, one the head of the * list and the other to the tail of the list. The elements are singly * linked to save space, so elements can only be removed from the * head of the list. New elements can be added to the list before or after * an existing element, at the head of the list, or at the end of the * list. A simple queue may only be traversed in the forward direction. * * A tail queue is headed by a pair of pointers, one to the head of the * list and the other to the tail of the list. The elements are doubly * linked so that an arbitrary element can be removed without a need to * traverse the list. New elements can be added to the list before or * after an existing element, at the head of the list, or at the end of * the list. A tail queue may be traversed in either direction. * * A circle queue is headed by a pair of pointers, one to the head of the * list and the other to the tail of the list. The elements are doubly * linked so that an arbitrary element can be removed without a need to * traverse the list. New elements can be added to the list before or after * an existing element, at the head of the list, or at the end of the list. * A circle queue may be traversed in either direction, but has a more * complex end of list detection. * * For details on the use of these macros, see the queue(3) manual page. */ #ifdef QUEUE_MACRO_DEBUG #define _Q_INVALIDATE(a) (a) = ((void *)-1) #else #define _Q_INVALIDATE(a) #endif /* * Singly-linked List definitions. */ #define SLIST_HEAD(name, type) \ struct name { \ struct type *slh_first; /* first element */ \ } #define SLIST_HEAD_INITIALIZER(head) \ { NULL } #define SLIST_ENTRY(type) \ struct { \ struct type *sle_next; /* next element */ \ } /* * Singly-linked List access methods. */ #define SLIST_FIRST(head) ((head)->slh_first) #define SLIST_END(head) NULL #define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head)) #define SLIST_NEXT(elm, field) ((elm)->field.sle_next) #define SLIST_FOREACH(var, head, field) \ for((var) = SLIST_FIRST(head); \ (var) != SLIST_END(head); \ (var) = SLIST_NEXT(var, field)) #define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ for ((varp) = &SLIST_FIRST((head)); \ ((var) = *(varp)) != SLIST_END(head); \ (varp) = &SLIST_NEXT((var), field)) /* * Singly-linked List functions. */ #define SLIST_INIT(head) { \ SLIST_FIRST(head) = SLIST_END(head); \ } #define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ (elm)->field.sle_next = (slistelm)->field.sle_next; \ (slistelm)->field.sle_next = (elm); \ } while (0) #define SLIST_INSERT_HEAD(head, elm, field) do { \ (elm)->field.sle_next = (head)->slh_first; \ (head)->slh_first = (elm); \ } while (0) #define SLIST_REMOVE_NEXT(head, elm, field) do { \ (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \ } while (0) #define SLIST_REMOVE_HEAD(head, field) do { \ (head)->slh_first = (head)->slh_first->field.sle_next; \ } while (0) #define SLIST_REMOVE(head, elm, type, field) do { \ if ((head)->slh_first == (elm)) { \ SLIST_REMOVE_HEAD((head), field); \ } else { \ struct type *curelm = (head)->slh_first; \ \ while (curelm->field.sle_next != (elm)) \ curelm = curelm->field.sle_next; \ curelm->field.sle_next = \ curelm->field.sle_next->field.sle_next; \ _Q_INVALIDATE((elm)->field.sle_next); \ } \ } while (0) /* * List definitions. */ #define LIST_HEAD(name, type) \ struct name { \ struct type *lh_first; /* first element */ \ } #define LIST_HEAD_INITIALIZER(head) \ { NULL } #define LIST_ENTRY(type) \ struct { \ struct type *le_next; /* next element */ \ struct type **le_prev; /* address of previous next element */ \ } /* * List access methods */ #define LIST_FIRST(head) ((head)->lh_first) #define LIST_END(head) NULL #define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head)) #define LIST_NEXT(elm, field) ((elm)->field.le_next) #define LIST_FOREACH(var, head, field) \ for((var) = LIST_FIRST(head); \ (var)!= LIST_END(head); \ (var) = LIST_NEXT(var, field)) /* * List functions. */ #define LIST_INIT(head) do { \ LIST_FIRST(head) = LIST_END(head); \ } while (0) #define LIST_INSERT_AFTER(listelm, elm, field) do { \ if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ (listelm)->field.le_next->field.le_prev = \ &(elm)->field.le_next; \ (listelm)->field.le_next = (elm); \ (elm)->field.le_prev = &(listelm)->field.le_next; \ } while (0) #define LIST_INSERT_BEFORE(listelm, elm, field) do { \ (elm)->field.le_prev = (listelm)->field.le_prev; \ (elm)->field.le_next = (listelm); \ *(listelm)->field.le_prev = (elm); \ (listelm)->field.le_prev = &(elm)->field.le_next; \ } while (0) #define LIST_INSERT_HEAD(head, elm, field) do { \ if (((elm)->field.le_next = (head)->lh_first) != NULL) \ (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ (head)->lh_first = (elm); \ (elm)->field.le_prev = &(head)->lh_first; \ } while (0) #define LIST_REMOVE(elm, field) do { \ if ((elm)->field.le_next != NULL) \ (elm)->field.le_next->field.le_prev = \ (elm)->field.le_prev; \ *(elm)->field.le_prev = (elm)->field.le_next; \ _Q_INVALIDATE((elm)->field.le_prev); \ _Q_INVALIDATE((elm)->field.le_next); \ } while (0) #define LIST_REPLACE(elm, elm2, field) do { \ if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ (elm2)->field.le_next->field.le_prev = \ &(elm2)->field.le_next; \ (elm2)->field.le_prev = (elm)->field.le_prev; \ *(elm2)->field.le_prev = (elm2); \ _Q_INVALIDATE((elm)->field.le_prev); \ _Q_INVALIDATE((elm)->field.le_next); \ } while (0) /* * Simple queue definitions. */ #define SIMPLEQ_HEAD(name, type) \ struct name { \ struct type *sqh_first; /* first element */ \ struct type **sqh_last; /* addr of last next element */ \ } #define SIMPLEQ_HEAD_INITIALIZER(head) \ { NULL, &(head).sqh_first } #define SIMPLEQ_ENTRY(type) \ struct { \ struct type *sqe_next; /* next element */ \ } /* * Simple queue access methods. */ #define SIMPLEQ_FIRST(head) ((head)->sqh_first) #define SIMPLEQ_END(head) NULL #define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head)) #define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) #define SIMPLEQ_FOREACH(var, head, field) \ for((var) = SIMPLEQ_FIRST(head); \ (var) != SIMPLEQ_END(head); \ (var) = SIMPLEQ_NEXT(var, field)) /* * Simple queue functions. */ #define SIMPLEQ_INIT(head) do { \ (head)->sqh_first = NULL; \ (head)->sqh_last = &(head)->sqh_first; \ } while (0) #define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ (head)->sqh_last = &(elm)->field.sqe_next; \ (head)->sqh_first = (elm); \ } while (0) #define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ (elm)->field.sqe_next = NULL; \ *(head)->sqh_last = (elm); \ (head)->sqh_last = &(elm)->field.sqe_next; \ } while (0) #define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ (head)->sqh_last = &(elm)->field.sqe_next; \ (listelm)->field.sqe_next = (elm); \ } while (0) #define SIMPLEQ_REMOVE_HEAD(head, field) do { \ if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ (head)->sqh_last = &(head)->sqh_first; \ } while (0) /* * Tail queue definitions. */ #define TAILQ_HEAD(name, type) \ struct name { \ struct type *tqh_first; /* first element */ \ struct type **tqh_last; /* addr of last next element */ \ } #define TAILQ_HEAD_INITIALIZER(head) \ { NULL, &(head).tqh_first } #define TAILQ_ENTRY(type) \ struct { \ struct type *tqe_next; /* next element */ \ struct type **tqe_prev; /* address of previous next element */ \ } /* * tail queue access methods */ #define TAILQ_FIRST(head) ((head)->tqh_first) #define TAILQ_END(head) NULL #define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) #define TAILQ_LAST(head, headname) \ (*(((struct headname *)((head)->tqh_last))->tqh_last)) /* XXX */ #define TAILQ_PREV(elm, headname, field) \ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) #define TAILQ_EMPTY(head) \ (TAILQ_FIRST(head) == TAILQ_END(head)) #define TAILQ_FOREACH(var, head, field) \ for((var) = TAILQ_FIRST(head); \ (var) != TAILQ_END(head); \ (var) = TAILQ_NEXT(var, field)) #define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ for((var) = TAILQ_LAST(head, headname); \ (var) != TAILQ_END(head); \ (var) = TAILQ_PREV(var, headname, field)) /* * Tail queue functions. */ #define TAILQ_INIT(head) do { \ (head)->tqh_first = NULL; \ (head)->tqh_last = &(head)->tqh_first; \ } while (0) #define TAILQ_INSERT_HEAD(head, elm, field) do { \ if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ (head)->tqh_first->field.tqe_prev = \ &(elm)->field.tqe_next; \ else \ (head)->tqh_last = &(elm)->field.tqe_next; \ (head)->tqh_first = (elm); \ (elm)->field.tqe_prev = &(head)->tqh_first; \ } while (0) #define TAILQ_INSERT_TAIL(head, elm, field) do { \ (elm)->field.tqe_next = NULL; \ (elm)->field.tqe_prev = (head)->tqh_last; \ *(head)->tqh_last = (elm); \ (head)->tqh_last = &(elm)->field.tqe_next; \ } while (0) #define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ (elm)->field.tqe_next->field.tqe_prev = \ &(elm)->field.tqe_next; \ else \ (head)->tqh_last = &(elm)->field.tqe_next; \ (listelm)->field.tqe_next = (elm); \ (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ } while (0) #define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ (elm)->field.tqe_next = (listelm); \ *(listelm)->field.tqe_prev = (elm); \ (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ } while (0) #define TAILQ_REMOVE(head, elm, field) do { \ if (((elm)->field.tqe_next) != NULL) \ (elm)->field.tqe_next->field.tqe_prev = \ (elm)->field.tqe_prev; \ else \ (head)->tqh_last = (elm)->field.tqe_prev; \ *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ _Q_INVALIDATE((elm)->field.tqe_prev); \ _Q_INVALIDATE((elm)->field.tqe_next); \ } while (0) #define TAILQ_REPLACE(head, elm, elm2, field) do { \ if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \ (elm2)->field.tqe_next->field.tqe_prev = \ &(elm2)->field.tqe_next; \ else \ (head)->tqh_last = &(elm2)->field.tqe_next; \ (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ *(elm2)->field.tqe_prev = (elm2); \ _Q_INVALIDATE((elm)->field.tqe_prev); \ _Q_INVALIDATE((elm)->field.tqe_next); \ } while (0) /* * Circular queue definitions. */ #define CIRCLEQ_HEAD(name, type) \ struct name { \ struct type *cqh_first; /* first element */ \ struct type *cqh_last; /* last element */ \ } #define CIRCLEQ_HEAD_INITIALIZER(head) \ { CIRCLEQ_END(&head), CIRCLEQ_END(&head) } #define CIRCLEQ_ENTRY(type) \ struct { \ struct type *cqe_next; /* next element */ \ struct type *cqe_prev; /* previous element */ \ } /* * Circular queue access methods */ #define CIRCLEQ_FIRST(head) ((head)->cqh_first) #define CIRCLEQ_LAST(head) ((head)->cqh_last) #define CIRCLEQ_END(head) ((void *)(head)) #define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) #define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) #define CIRCLEQ_EMPTY(head) \ (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head)) #define CIRCLEQ_FOREACH(var, head, field) \ for((var) = CIRCLEQ_FIRST(head); \ (var) != CIRCLEQ_END(head); \ (var) = CIRCLEQ_NEXT(var, field)) #define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ for((var) = CIRCLEQ_LAST(head); \ (var) != CIRCLEQ_END(head); \ (var) = CIRCLEQ_PREV(var, field)) /* * Circular queue functions. */ #define CIRCLEQ_INIT(head) do { \ (head)->cqh_first = CIRCLEQ_END(head); \ (head)->cqh_last = CIRCLEQ_END(head); \ } while (0) #define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ (elm)->field.cqe_next = (listelm)->field.cqe_next; \ (elm)->field.cqe_prev = (listelm); \ if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \ (head)->cqh_last = (elm); \ else \ (listelm)->field.cqe_next->field.cqe_prev = (elm); \ (listelm)->field.cqe_next = (elm); \ } while (0) #define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ (elm)->field.cqe_next = (listelm); \ (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \ (head)->cqh_first = (elm); \ else \ (listelm)->field.cqe_prev->field.cqe_next = (elm); \ (listelm)->field.cqe_prev = (elm); \ } while (0) #define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ (elm)->field.cqe_next = (head)->cqh_first; \ (elm)->field.cqe_prev = CIRCLEQ_END(head); \ if ((head)->cqh_last == CIRCLEQ_END(head)) \ (head)->cqh_last = (elm); \ else \ (head)->cqh_first->field.cqe_prev = (elm); \ (head)->cqh_first = (elm); \ } while (0) #define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ (elm)->field.cqe_next = CIRCLEQ_END(head); \ (elm)->field.cqe_prev = (head)->cqh_last; \ if ((head)->cqh_first == CIRCLEQ_END(head)) \ (head)->cqh_first = (elm); \ else \ (head)->cqh_last->field.cqe_next = (elm); \ (head)->cqh_last = (elm); \ } while (0) #define CIRCLEQ_REMOVE(head, elm, field) do { \ if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \ (head)->cqh_last = (elm)->field.cqe_prev; \ else \ (elm)->field.cqe_next->field.cqe_prev = \ (elm)->field.cqe_prev; \ if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \ (head)->cqh_first = (elm)->field.cqe_next; \ else \ (elm)->field.cqe_prev->field.cqe_next = \ (elm)->field.cqe_next; \ _Q_INVALIDATE((elm)->field.cqe_prev); \ _Q_INVALIDATE((elm)->field.cqe_next); \ } while (0) #define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \ if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \ CIRCLEQ_END(head)) \ (head).cqh_last = (elm2); \ else \ (elm2)->field.cqe_next->field.cqe_prev = (elm2); \ if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \ CIRCLEQ_END(head)) \ (head).cqh_first = (elm2); \ else \ (elm2)->field.cqe_prev->field.cqe_next = (elm2); \ _Q_INVALIDATE((elm)->field.cqe_prev); \ _Q_INVALIDATE((elm)->field.cqe_next); \ } while (0) #endif /* !_SYS_QUEUE_H_ */ fdm-1.7/compat/strlcpy.c010064400017500001750000000031601112127572500155040ustar00nicholasnicholas/* $Id: strlcpy.c,v 1.1 2006/11/19 17:00:39 nicm Exp $ */ /* $OpenBSD: strlcpy.c,v 1.10 2005/08/08 08:05:37 espie Exp $ */ /* * Copyright (c) 1998 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include "fdm.h" /* * Copy src to string dst of size siz. At most siz-1 characters * will be copied. Always NUL terminates (unless siz == 0). * Returns strlen(src); if retval >= siz, truncation occurred. */ size_t strlcpy(char *dst, const char *src, size_t siz) { char *d = dst; const char *s = src; size_t n = siz; /* Copy as many bytes as will fit */ if (n != 0 && --n != 0) { do { if ((*d++ = *s++) == 0) break; } while (--n != 0); } /* Not enough room in dst, add NUL and traverse rest of src */ if (n == 0) { if (siz != 0) *d = '\0'; /* NUL-terminate dst */ while (*s++) ; } return(s - src - 1); /* count does not include NUL */ } fdm-1.7/compat/strtonum.c010064400017500001750000000034661112127572500157100ustar00nicholasnicholas/* $Id: strtonum.c,v 1.1 2006/11/19 17:00:39 nicm Exp $ */ /* $OpenBSD: strtonum.c,v 1.6 2004/08/03 19:38:01 millert Exp $ */ /* * Copyright (c) 2004 Ted Unangst and Todd Miller * All rights reserved. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include "fdm.h" #define INVALID 1 #define TOOSMALL 2 #define TOOLARGE 3 long long strtonum(const char *numstr, long long minval, long long maxval, const char **errstrp) { long long ll = 0; char *ep; int error = 0; struct errval { const char *errstr; int err; } ev[4] = { { NULL, 0 }, { "invalid", EINVAL }, { "too small", ERANGE }, { "too large", ERANGE }, }; ev[0].err = errno; errno = 0; if (minval > maxval) error = INVALID; else { ll = strtoll(numstr, &ep, 10); if (numstr == ep || *ep != '\0') error = INVALID; else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval) error = TOOSMALL; else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval) error = TOOLARGE; } if (errstrp != NULL) *errstrp = ev[error].errstr; errno = ev[error].err; if (error) ll = 0; return (ll); } fdm-1.7/compat/tree.h010064400017500001750000000542701112127572500147600ustar00nicholasnicholas/* $Id: tree.h,v 1.2 2007/07/16 23:43:17 nicm Exp $ */ /* $OpenBSD: tree.h,v 1.9 2004/11/24 18:10:42 tdeval Exp $ */ /* * Copyright 2002 Niels Provos * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _SYS_TREE_H_ #define _SYS_TREE_H_ /* * This file defines data structures for different types of trees: * splay trees and red-black trees. * * A splay tree is a self-organizing data structure. Every operation * on the tree causes a splay to happen. The splay moves the requested * node to the root of the tree and partly rebalances it. * * This has the benefit that request locality causes faster lookups as * the requested nodes move to the top of the tree. On the other hand, * every lookup causes memory writes. * * The Balance Theorem bounds the total access time for m operations * and n inserts on an initially empty tree as O((m + n)lg n). The * amortized cost for a sequence of m accesses to a splay tree is O(lg n); * * A red-black tree is a binary search tree with the node color as an * extra attribute. It fulfills a set of conditions: * - every search path from the root to a leaf consists of the * same number of black nodes, * - each red node (except for the root) has a black parent, * - each leaf node is black. * * Every operation on a red-black tree is bounded as O(lg n). * The maximum height of a red-black tree is 2lg (n+1). */ #define SPLAY_HEAD(name, type) \ struct name { \ struct type *sph_root; /* root of the tree */ \ } #define SPLAY_INITIALIZER(root) \ { NULL } #define SPLAY_INIT(root) do { \ (root)->sph_root = NULL; \ } while (0) #define SPLAY_ENTRY(type) \ struct { \ struct type *spe_left; /* left element */ \ struct type *spe_right; /* right element */ \ } #define SPLAY_LEFT(elm, field) (elm)->field.spe_left #define SPLAY_RIGHT(elm, field) (elm)->field.spe_right #define SPLAY_ROOT(head) (head)->sph_root #define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL) /* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */ #define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \ SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \ SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ (head)->sph_root = tmp; \ } while (0) #define SPLAY_ROTATE_LEFT(head, tmp, field) do { \ SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \ SPLAY_LEFT(tmp, field) = (head)->sph_root; \ (head)->sph_root = tmp; \ } while (0) #define SPLAY_LINKLEFT(head, tmp, field) do { \ SPLAY_LEFT(tmp, field) = (head)->sph_root; \ tmp = (head)->sph_root; \ (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ } while (0) #define SPLAY_LINKRIGHT(head, tmp, field) do { \ SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ tmp = (head)->sph_root; \ (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ } while (0) #define SPLAY_ASSEMBLE(head, node, left, right, field) do { \ SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \ SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\ SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \ SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \ } while (0) /* Generates prototypes and inline functions */ #define SPLAY_PROTOTYPE(name, type, field, cmp) \ void name##_SPLAY(struct name *, struct type *); \ void name##_SPLAY_MINMAX(struct name *, int); \ struct type *name##_SPLAY_INSERT(struct name *, struct type *); \ struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \ \ /* Finds the node with the same key as elm */ \ static __inline struct type * \ name##_SPLAY_FIND(struct name *head, struct type *elm) \ { \ if (SPLAY_EMPTY(head)) \ return(NULL); \ name##_SPLAY(head, elm); \ if ((cmp)(elm, (head)->sph_root) == 0) \ return (head->sph_root); \ return (NULL); \ } \ \ static __inline struct type * \ name##_SPLAY_NEXT(struct name *head, struct type *elm) \ { \ name##_SPLAY(head, elm); \ if (SPLAY_RIGHT(elm, field) != NULL) { \ elm = SPLAY_RIGHT(elm, field); \ while (SPLAY_LEFT(elm, field) != NULL) { \ elm = SPLAY_LEFT(elm, field); \ } \ } else \ elm = NULL; \ return (elm); \ } \ \ static __inline struct type * \ name##_SPLAY_MIN_MAX(struct name *head, int val) \ { \ name##_SPLAY_MINMAX(head, val); \ return (SPLAY_ROOT(head)); \ } /* Main splay operation. * Moves node close to the key of elm to top */ #define SPLAY_GENERATE(name, type, field, cmp) \ struct type * \ name##_SPLAY_INSERT(struct name *head, struct type *elm) \ { \ if (SPLAY_EMPTY(head)) { \ SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \ } else { \ int __comp; \ name##_SPLAY(head, elm); \ __comp = (cmp)(elm, (head)->sph_root); \ if(__comp < 0) { \ SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\ SPLAY_RIGHT(elm, field) = (head)->sph_root; \ SPLAY_LEFT((head)->sph_root, field) = NULL; \ } else if (__comp > 0) { \ SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\ SPLAY_LEFT(elm, field) = (head)->sph_root; \ SPLAY_RIGHT((head)->sph_root, field) = NULL; \ } else \ return ((head)->sph_root); \ } \ (head)->sph_root = (elm); \ return (NULL); \ } \ \ struct type * \ name##_SPLAY_REMOVE(struct name *head, struct type *elm) \ { \ struct type *__tmp; \ if (SPLAY_EMPTY(head)) \ return (NULL); \ name##_SPLAY(head, elm); \ if ((cmp)(elm, (head)->sph_root) == 0) { \ if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \ (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\ } else { \ __tmp = SPLAY_RIGHT((head)->sph_root, field); \ (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\ name##_SPLAY(head, elm); \ SPLAY_RIGHT((head)->sph_root, field) = __tmp; \ } \ return (elm); \ } \ return (NULL); \ } \ \ void \ name##_SPLAY(struct name *head, struct type *elm) \ { \ struct type __node, *__left, *__right, *__tmp; \ int __comp; \ \ SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ __left = __right = &__node; \ \ while ((__comp = (cmp)(elm, (head)->sph_root))) { \ if (__comp < 0) { \ __tmp = SPLAY_LEFT((head)->sph_root, field); \ if (__tmp == NULL) \ break; \ if ((cmp)(elm, __tmp) < 0){ \ SPLAY_ROTATE_RIGHT(head, __tmp, field); \ if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ break; \ } \ SPLAY_LINKLEFT(head, __right, field); \ } else if (__comp > 0) { \ __tmp = SPLAY_RIGHT((head)->sph_root, field); \ if (__tmp == NULL) \ break; \ if ((cmp)(elm, __tmp) > 0){ \ SPLAY_ROTATE_LEFT(head, __tmp, field); \ if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ break; \ } \ SPLAY_LINKRIGHT(head, __left, field); \ } \ } \ SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ } \ \ /* Splay with either the minimum or the maximum element \ * Used to find minimum or maximum element in tree. \ */ \ void name##_SPLAY_MINMAX(struct name *head, int __comp) \ { \ struct type __node, *__left, *__right, *__tmp; \ \ SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ __left = __right = &__node; \ \ while (1) { \ if (__comp < 0) { \ __tmp = SPLAY_LEFT((head)->sph_root, field); \ if (__tmp == NULL) \ break; \ if (__comp < 0){ \ SPLAY_ROTATE_RIGHT(head, __tmp, field); \ if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ break; \ } \ SPLAY_LINKLEFT(head, __right, field); \ } else if (__comp > 0) { \ __tmp = SPLAY_RIGHT((head)->sph_root, field); \ if (__tmp == NULL) \ break; \ if (__comp > 0) { \ SPLAY_ROTATE_LEFT(head, __tmp, field); \ if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ break; \ } \ SPLAY_LINKRIGHT(head, __left, field); \ } \ } \ SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ } #define SPLAY_NEGINF -1 #define SPLAY_INF 1 #define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y) #define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y) #define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y) #define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y) #define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \ : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF)) #define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \ : name##_SPLAY_MIN_MAX(x, SPLAY_INF)) #define SPLAY_FOREACH(x, name, head) \ for ((x) = SPLAY_MIN(name, head); \ (x) != NULL; \ (x) = SPLAY_NEXT(name, head, x)) /* Macros that define a red-black tree */ #define RB_HEAD(name, type) \ struct name { \ struct type *rbh_root; /* root of the tree */ \ } #define RB_INITIALIZER(root) \ { NULL } #define RB_INIT(root) do { \ (root)->rbh_root = NULL; \ } while (0) #define RB_BLACK 0 #define RB_RED 1 #define RB_ENTRY(type) \ struct { \ struct type *rbe_left; /* left element */ \ struct type *rbe_right; /* right element */ \ struct type *rbe_parent; /* parent element */ \ int rbe_color; /* node color */ \ } #define RB_LEFT(elm, field) (elm)->field.rbe_left #define RB_RIGHT(elm, field) (elm)->field.rbe_right #define RB_PARENT(elm, field) (elm)->field.rbe_parent #define RB_COLOR(elm, field) (elm)->field.rbe_color #define RB_ROOT(head) (head)->rbh_root #define RB_EMPTY(head) (RB_ROOT(head) == NULL) #define RB_SET(elm, parent, field) do { \ RB_PARENT(elm, field) = parent; \ RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \ RB_COLOR(elm, field) = RB_RED; \ } while (0) #define RB_SET_BLACKRED(black, red, field) do { \ RB_COLOR(black, field) = RB_BLACK; \ RB_COLOR(red, field) = RB_RED; \ } while (0) #ifndef RB_AUGMENT #define RB_AUGMENT(x) #endif #define RB_ROTATE_LEFT(head, elm, tmp, field) do { \ (tmp) = RB_RIGHT(elm, field); \ if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field))) { \ RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \ } \ RB_AUGMENT(elm); \ if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \ if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ else \ RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ } else \ (head)->rbh_root = (tmp); \ RB_LEFT(tmp, field) = (elm); \ RB_PARENT(elm, field) = (tmp); \ RB_AUGMENT(tmp); \ if ((RB_PARENT(tmp, field))) \ RB_AUGMENT(RB_PARENT(tmp, field)); \ } while (0) #define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \ (tmp) = RB_LEFT(elm, field); \ if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field))) { \ RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \ } \ RB_AUGMENT(elm); \ if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \ if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ else \ RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ } else \ (head)->rbh_root = (tmp); \ RB_RIGHT(tmp, field) = (elm); \ RB_PARENT(elm, field) = (tmp); \ RB_AUGMENT(tmp); \ if ((RB_PARENT(tmp, field))) \ RB_AUGMENT(RB_PARENT(tmp, field)); \ } while (0) /* Generates prototypes and inline functions */ #define RB_PROTOTYPE(name, type, field, cmp) \ void name##_RB_INSERT_COLOR(struct name *, struct type *); \ void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\ struct type *name##_RB_REMOVE(struct name *, struct type *); \ struct type *name##_RB_INSERT(struct name *, struct type *); \ struct type *name##_RB_FIND(struct name *, struct type *); \ struct type *name##_RB_NEXT(struct type *); \ struct type *name##_RB_MINMAX(struct name *, int); \ \ /* Main rb operation. * Moves node close to the key of elm to top */ #define RB_GENERATE(name, type, field, cmp) \ void \ name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ { \ struct type *parent, *gparent, *tmp; \ while ((parent = RB_PARENT(elm, field)) && \ RB_COLOR(parent, field) == RB_RED) { \ gparent = RB_PARENT(parent, field); \ if (parent == RB_LEFT(gparent, field)) { \ tmp = RB_RIGHT(gparent, field); \ if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ RB_COLOR(tmp, field) = RB_BLACK; \ RB_SET_BLACKRED(parent, gparent, field);\ elm = gparent; \ continue; \ } \ if (RB_RIGHT(parent, field) == elm) { \ RB_ROTATE_LEFT(head, parent, tmp, field);\ tmp = parent; \ parent = elm; \ elm = tmp; \ } \ RB_SET_BLACKRED(parent, gparent, field); \ RB_ROTATE_RIGHT(head, gparent, tmp, field); \ } else { \ tmp = RB_LEFT(gparent, field); \ if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ RB_COLOR(tmp, field) = RB_BLACK; \ RB_SET_BLACKRED(parent, gparent, field);\ elm = gparent; \ continue; \ } \ if (RB_LEFT(parent, field) == elm) { \ RB_ROTATE_RIGHT(head, parent, tmp, field);\ tmp = parent; \ parent = elm; \ elm = tmp; \ } \ RB_SET_BLACKRED(parent, gparent, field); \ RB_ROTATE_LEFT(head, gparent, tmp, field); \ } \ } \ RB_COLOR(head->rbh_root, field) = RB_BLACK; \ } \ \ void \ name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \ { \ struct type *tmp; \ while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \ elm != RB_ROOT(head)) { \ if (RB_LEFT(parent, field) == elm) { \ tmp = RB_RIGHT(parent, field); \ if (RB_COLOR(tmp, field) == RB_RED) { \ RB_SET_BLACKRED(tmp, parent, field); \ RB_ROTATE_LEFT(head, parent, tmp, field);\ tmp = RB_RIGHT(parent, field); \ } \ if ((RB_LEFT(tmp, field) == NULL || \ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ (RB_RIGHT(tmp, field) == NULL || \ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ RB_COLOR(tmp, field) = RB_RED; \ elm = parent; \ parent = RB_PARENT(elm, field); \ } else { \ if (RB_RIGHT(tmp, field) == NULL || \ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\ struct type *oleft; \ if ((oleft = RB_LEFT(tmp, field)))\ RB_COLOR(oleft, field) = RB_BLACK;\ RB_COLOR(tmp, field) = RB_RED; \ RB_ROTATE_RIGHT(head, tmp, oleft, field);\ tmp = RB_RIGHT(parent, field); \ } \ RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ RB_COLOR(parent, field) = RB_BLACK; \ if (RB_RIGHT(tmp, field)) \ RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\ RB_ROTATE_LEFT(head, parent, tmp, field);\ elm = RB_ROOT(head); \ break; \ } \ } else { \ tmp = RB_LEFT(parent, field); \ if (RB_COLOR(tmp, field) == RB_RED) { \ RB_SET_BLACKRED(tmp, parent, field); \ RB_ROTATE_RIGHT(head, parent, tmp, field);\ tmp = RB_LEFT(parent, field); \ } \ if ((RB_LEFT(tmp, field) == NULL || \ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ (RB_RIGHT(tmp, field) == NULL || \ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ RB_COLOR(tmp, field) = RB_RED; \ elm = parent; \ parent = RB_PARENT(elm, field); \ } else { \ if (RB_LEFT(tmp, field) == NULL || \ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\ struct type *oright; \ if ((oright = RB_RIGHT(tmp, field)))\ RB_COLOR(oright, field) = RB_BLACK;\ RB_COLOR(tmp, field) = RB_RED; \ RB_ROTATE_LEFT(head, tmp, oright, field);\ tmp = RB_LEFT(parent, field); \ } \ RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ RB_COLOR(parent, field) = RB_BLACK; \ if (RB_LEFT(tmp, field)) \ RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\ RB_ROTATE_RIGHT(head, parent, tmp, field);\ elm = RB_ROOT(head); \ break; \ } \ } \ } \ if (elm) \ RB_COLOR(elm, field) = RB_BLACK; \ } \ \ struct type * \ name##_RB_REMOVE(struct name *head, struct type *elm) \ { \ struct type *child, *parent, *old = elm; \ int color; \ if (RB_LEFT(elm, field) == NULL) \ child = RB_RIGHT(elm, field); \ else if (RB_RIGHT(elm, field) == NULL) \ child = RB_LEFT(elm, field); \ else { \ struct type *left; \ elm = RB_RIGHT(elm, field); \ while ((left = RB_LEFT(elm, field))) \ elm = left; \ child = RB_RIGHT(elm, field); \ parent = RB_PARENT(elm, field); \ color = RB_COLOR(elm, field); \ if (child) \ RB_PARENT(child, field) = parent; \ if (parent) { \ if (RB_LEFT(parent, field) == elm) \ RB_LEFT(parent, field) = child; \ else \ RB_RIGHT(parent, field) = child; \ RB_AUGMENT(parent); \ } else \ RB_ROOT(head) = child; \ if (RB_PARENT(elm, field) == old) \ parent = elm; \ (elm)->field = (old)->field; \ if (RB_PARENT(old, field)) { \ if (RB_LEFT(RB_PARENT(old, field), field) == old)\ RB_LEFT(RB_PARENT(old, field), field) = elm;\ else \ RB_RIGHT(RB_PARENT(old, field), field) = elm;\ RB_AUGMENT(RB_PARENT(old, field)); \ } else \ RB_ROOT(head) = elm; \ RB_PARENT(RB_LEFT(old, field), field) = elm; \ if (RB_RIGHT(old, field)) \ RB_PARENT(RB_RIGHT(old, field), field) = elm; \ if (parent) { \ left = parent; \ do { \ RB_AUGMENT(left); \ } while ((left = RB_PARENT(left, field))); \ } \ goto color; \ } \ parent = RB_PARENT(elm, field); \ color = RB_COLOR(elm, field); \ if (child) \ RB_PARENT(child, field) = parent; \ if (parent) { \ if (RB_LEFT(parent, field) == elm) \ RB_LEFT(parent, field) = child; \ else \ RB_RIGHT(parent, field) = child; \ RB_AUGMENT(parent); \ } else \ RB_ROOT(head) = child; \ color: \ if (color == RB_BLACK) \ name##_RB_REMOVE_COLOR(head, parent, child); \ return (old); \ } \ \ /* Inserts a node into the RB tree */ \ struct type * \ name##_RB_INSERT(struct name *head, struct type *elm) \ { \ struct type *tmp; \ struct type *parent = NULL; \ int comp = 0; \ tmp = RB_ROOT(head); \ while (tmp) { \ parent = tmp; \ comp = (cmp)(elm, parent); \ if (comp < 0) \ tmp = RB_LEFT(tmp, field); \ else if (comp > 0) \ tmp = RB_RIGHT(tmp, field); \ else \ return (tmp); \ } \ RB_SET(elm, parent, field); \ if (parent != NULL) { \ if (comp < 0) \ RB_LEFT(parent, field) = elm; \ else \ RB_RIGHT(parent, field) = elm; \ RB_AUGMENT(parent); \ } else \ RB_ROOT(head) = elm; \ name##_RB_INSERT_COLOR(head, elm); \ return (NULL); \ } \ \ /* Finds the node with the same key as elm */ \ struct type * \ name##_RB_FIND(struct name *head, struct type *elm) \ { \ struct type *tmp = RB_ROOT(head); \ int comp; \ while (tmp) { \ comp = cmp(elm, tmp); \ if (comp < 0) \ tmp = RB_LEFT(tmp, field); \ else if (comp > 0) \ tmp = RB_RIGHT(tmp, field); \ else \ return (tmp); \ } \ return (NULL); \ } \ \ struct type * \ name##_RB_NEXT(struct type *elm) \ { \ if (RB_RIGHT(elm, field)) { \ elm = RB_RIGHT(elm, field); \ while (RB_LEFT(elm, field)) \ elm = RB_LEFT(elm, field); \ } else { \ if (RB_PARENT(elm, field) && \ (elm == RB_LEFT(RB_PARENT(elm, field), field))) \ elm = RB_PARENT(elm, field); \ else { \ while (RB_PARENT(elm, field) && \ (elm == RB_RIGHT(RB_PARENT(elm, field), field)))\ elm = RB_PARENT(elm, field); \ elm = RB_PARENT(elm, field); \ } \ } \ return (elm); \ } \ \ struct type * \ name##_RB_MINMAX(struct name *head, int val) \ { \ struct type *tmp = RB_ROOT(head); \ struct type *parent = NULL; \ while (tmp) { \ parent = tmp; \ if (val < 0) \ tmp = RB_LEFT(tmp, field); \ else \ tmp = RB_RIGHT(tmp, field); \ } \ return (parent); \ } #define RB_NEGINF -1 #define RB_INF 1 #define RB_INSERT(name, x, y) name##_RB_INSERT(x, y) #define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) #define RB_FIND(name, x, y) name##_RB_FIND(x, y) #define RB_NEXT(name, x, y) name##_RB_NEXT(y) #define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) #define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF) #define RB_FOREACH(x, name, head) \ for ((x) = RB_MIN(name, head); \ (x) != NULL; \ (x) = name##_RB_NEXT(x)) #endif /* _SYS_TREE_H_ */ fdm-1.7/examples/f-terbeck.conf010064400017500001750000000451141112127571600167110ustar00nicholasnicholas### fdm configuration ### vim:ft=config ### ### All in one replacement for {get,fetch}mail and procmail. ### ### ### Frank Terbeck ### ### Last-Modified: Thu Mar 8 17:03:05 2007 ### ########################################################################### ### The following strings are replaced in pipe commands and ### maildir/mbox paths: ### %a: account name ### %h: user's home directory ### %n: user's uid ### %t: action name if performing action ### %u: name of user ### %H: current hour (00-23) ### %M: current minute (00-59) ### %S: current second (00-59) ### %d: current day of the month (00-31) ### %m: current month (01-12) ### %y: current year ### %W: current day of the week (0-6, Sunday is 0) ### %Y: current day of the year (000-365) ### %Q: current quarter (1-4) ########################################################################### ### Some macros used below. ### where I keep my mail $path = "%h/Mail" ### where I keep my config files $cfgdir = "%h/etc/fdm" ### location of killfile $killfile = "%h/etc/mailnews/killfile" ### spam filter commands $com_spam_filter = "spamprobe receive" $com_train_good = "spamprobe good" $com_train_spam = "spamprobe spam" ### some filters use these unix commands: $com_sed = "sed" $com_awk = "awk" $com_perl = "perl" ### spam header expressions $header_spam = "X-SpamProbe" $filtered_spam = "SPAM" $filtered_good = "GOOD" $filter_trained = " TRAINED" ### if do_catchall is "yes", all incoming mail will be saved ### to ${catchall_mbox}; useful for testing (so nothing gets lost). $do_catchall = "nope" $catchall_mbox = "%h/catchall.mbox" ### this is used by my archive action. ### Mails older than this (in days) are moved to the archive. %max_age = 30 ### zblog $com_zblog = "%h/bin/zblog" ### print from headers (Sender, From, From:, Reply-To:) ### used for killfiling. $com_pfh = "${com_awk} '/^(From|From:|Reply-To:|Sender)/{sub(/[^ \\t]*[ \\t]*/,\"\",$0);print};/^\$/{exit 0}'" ### list of headers I don't want. $ill_headers = "(" $ill_headers = "${ill_headers}X-Qmail-Scanner.*|X-SA-Exim.*|X-CR-.*|" $ill_headers = "${ill_headers}X-MIME-.*|X-Authentication-.*|" $ill_headers = "${ill_headers}X-Mailman-.*|X-Spam-.*|X-MimeOLE|" $ill_headers = "${ill_headers}X-Msmail-.*|X-Priority|X-MS-.*|" $ill_headers = "${ill_headers}Thread-Topic|Thread-Index|" $ill_headers = "${ill_headers}X-OriginalArrivalTime|" $ill_headers = "${ill_headers}X-Face|DKIM-Signature|" $ill_headers = "${ill_headers}X-IronPort-.*|DomainKey-Signature|" $ill_headers = "${ill_headers}X-Rc-.*" $ill_headers = "${ill_headers})" ### perl script that filters out unwanted headers $com_filter_headers = "${com_perl} -e '\$k=\$e=0;while(<>){if(\$e||m/^$/){\$e=1;print;next;}" $com_filter_headers = "${com_filter_headers}if(m/^[ \\t]+/&&\$k){next;}if(m/^${ill_headers}:/i)" $com_filter_headers = "${com_filter_headers}{\$k=1;next;}if(\$k){\$k=0;}print;}'" ########################################################################### ### This is used to set the maximum size of a mail. Mails larger than ### this limit are dropped and, if applicable, not deleted from the ### server. set maximum-size 128M ### If this option is specified, fdm(1) attempts to delete messages ### which exceed maximum-size, and continue.If it is not specified, ### oversize messages are a fatal error and cause fdm(1) to abort. #set delete-oversized ### If this option is specified, fdm(1) does not attempt to create a ### lock file and allows multiple instances to run simultaneously. #set allow-multiple ### This sets an alternative lock file. The default is ~/.fdm.lock ### for non-root users and /var/db/fdm.lock for root. set lock-file "${cfgdir}/fdm.lock" ### This specifies the locks to be used for mbox locking. Possible ### types are fcntl, flock, and dotlock. The flock and fcntl types ### are mutually exclusive. The default is flock. #set lock-types flock ### This sets the default user to change to before delivering mail, ### if fdmis running as root and no alternative user is specified as ### part of the action or rule. #set default-user "hawk" ### This specifies the domains to be used when looking for users with ### the from-headers keyword. The default is the computer's hostname. #set domain "bewatermyfriend.org" ### This allows the headers to be examined when looking for users to ### be set. The default is to look only at the "From" and "Cc" ### headers. The headers are case-insensitive. #set header ### This instructs fdm to proxy all connections through url. HTTP ### and SOCKS5 proxies are supported at present (URLs of the form ### http://host[:port] or socks://[user:pass@]host[:port]). ### No authentication is supported for HTTP. #set proxy ### This option controls what fdm does with mail that reaches the ### end of the ruleset (mail that matches no rules or matches only ### rules with the continue keyword). drop will cause such mail to ### be discarded, and keep will attempt to leave the mail on the ### server. The default is to keep the mail and log a warning that ### it reached the end of the ruleset. set unmatched-mail keep ### This option makes fdm attempt to purge deleted mail from the ### server (if supported) after count mails have been retrieved. set purge-after none ### If set, fdm will not insert a 'Received' header into each mail. #set no-received ### This specifies the umask(2) to use when creating files. 'user' ### means to use the umask set when fdm is started, or umask may be ### specified as a three-digit octal number. set file-umask 077 ### This option allows the default group ownership of files and ### directories created by fdm(1) to be specified. 'group' may be a ### group name string or a numeric gid. 'user' does nothing. set file-group user ### This controls the maximum time to wait for a server to send data ### before closing a connection. The default is 900 seconds. set timeout 900 ########################################################################### ### include account information from seperate file. ### it contains lines that look like this: ### account "name" server pop3 "pop3.serv.tld" user "uname" pass "pwd" include "${cfgdir}/accounts.conf" ########################################################################### ### simple actions action "drop" drop action "keep" keep ### zblog action "zblog" pipe "${com_zblog} email" action "zcomm" pipe "${com_zblog} commentmode" ### killfiling action "killfile" maildir "${path}/Trash" ### a mailbox to rule them all action "catchall" mbox "${catchall_mbox}" ### spam actions action "spam" maildir "${path}/Spam" action "train-spam" pipe "${com_train_spam}" action "train-good" pipe "${com_train_good}" action "sp-add-header" add-header "${header_spam}" "%[command1]" action "sp-remove-header" remove-header "${header_spam}" action "sp-add-trained-good" add-header "${header_spam}" "${filtered_good}${filter_trained}" action "sp-add-trained-spam" add-header "${header_spam}" "${filtered_spam}${filter_trained}" ### action for adding Lines: headers ### Current CVS versions can do this themselves. action "add-lines-header" add-header "Lines" "%[body_lines]" ### action to remove unneeded headers action "remove-ill-headers" rewrite "${com_filter_headers}" ### mark as read in maildirs. this requires /bin/sh to be somewhat POSIXly ### correct. ash, ksh, bash etc. will do; older bourne shells (like /bin/sh ### on OpenSolaris) will not. You'll need to use {base,dir}name with these. action "maildir-mark-as-read" exec "mf=\"%[mail_file]\" ; mv \"\${mf}\" \"\${mf%%/*}\"/../cur/\"\${mf##*/}:2,S\"" ### archiving action action "archive" mbox "${path}/archive/%[maildir]-%yq%Q" compress ### handle mailinglists ### path actions #{{{ action "inbox" maildir "${path}/Inbox" action "debian-announce" maildir "${path}/debian-announce" action "debian-boot" maildir "${path}/debian-boot" action "debian-curiosa" maildir "${path}/debian-curiosa" action "debian-devel" maildir "${path}/debian-devel" action "debian-devel-announce" maildir "${path}/debian-devel-announce" action "debian-mentors" maildir "${path}/debian-mentors" action "debian-news-german" maildir "${path}/debian-news-german" action "debian-outbox" maildir "${path}/debian-outbox" action "debian-policy" maildir "${path}/debian-policy" action "debian-project" maildir "${path}/debian-project" action "debian-pts" maildir "${path}/debian-pts" action "debian-publicity" maildir "${path}/debian-publicity" action "debian-release" maildir "${path}/debian-release" action "debian-security" maildir "${path}/debian-security" action "debian-vote" maildir "${path}/debian-vote" action "debian-women" maildir "${path}/debian-women" action "openbsd-announce" maildir "${path}/openbsd-announce" action "openbsd-ipv6" maildir "${path}/openbsd-ipv6" action "openbsd-misc" maildir "${path}/openbsd-misc" action "openbsd-ports" maildir "${path}/openbsd-ports" action "openbsd-ports-bugs" maildir "${path}/openbsd-ports-bugs" action "openbsd-ports-security" maildir "${path}/openbsd-ports-security" action "openbsd-security-announce" maildir "${path}/openbsd-security-announce" action "openbsd-tech" maildir "${path}/openbsd-tech" action "openbsd-www" maildir "${path}/openbsd-www" action "openbsd-x11" maildir "${path}/openbsd-x11" action "mutt-dev" maildir "${path}/mutt-dev" action "mutt-users" maildir "${path}/mutt-users" action "fvwm" maildir "${path}/fvwm" action "fvwm-workers" maildir "${path}/fvwm-workers" action "grml" maildir "${path}/grml" action "grml-devel" maildir "${path}/grml-devel" action "zsh-users" maildir "${path}/zsh-users" action "zsh-workers" maildir "${path}/zsh-workers" action "cmus-devel" maildir "${path}/cmus-devel" action "leafnode" maildir "${path}/leafnode" action "remind-fans" maildir "${path}/remind-fans" action "screen-users" maildir "${path}/screen-users" action "slrn-users" maildir "${path}/slrn-users" action "tuhs" maildir "${path}/tuhs" action "vim-users" maildir "${path}/vim-users" action "linux-kernel" maildir "${path}/linux-kernel" action "kernelnewbies" maildir "${path}/linux-kernel-newbies" action "linux-elitists" maildir "${path}/linux-elitists" action "bugtraq" maildir "${path}/bugtraq" action "full-disclosure" maildir "${path}/full-disclosure" action "pen-test" maildir "${path}/pen-test" action "schopppe" maildir "${path}/schopppe" #}}} ### rewrite actions (some mailinglist add tags to their subjects...) ### '1,/^$/...' only rewrites lines in the mail _headers_. #{{{ action "strip-full-disclosure" rewrite "${com_sed} '1,/^$/s/^\\(Subject:.*\\)\\[Full-disclosure\\] /\\1/'" action "strip-remind-fans" rewrite "${com_sed} '1,/^$/s/^\\(Subject:.*\\)\\[Remind-Fans\\] /\\1/'" action "strip-fvwm" rewrite "${com_sed} '1,/^$/s/^\\(Subject:\\) FVWM:/\\1/'" action "strip-grml" rewrite "${com_sed} '1,/^$/s/^\\(Subject:.*\\)\\[Grml\\] /\\1/'" action "strip-leafnode" rewrite "${com_sed} '1,/^$/s/^\\(Subject:.*\\)\\[leafnode-list\\] /\\1/'" action "strip-linux-elitists" rewrite "${com_sed} '1,/^$/s/^\\(Subject:.*\\)\\[linux-elitists\\] /\\1/'" action "strip-tuhs" rewrite "${com_sed} '1,/^$/s/^\\(Subject:.*\\)\\[TUHS\\] /\\1/'" #}}} ########################################################################### ### accounts for spam-training ### -asp-train-spam ### trains the message from stdin as spam; ### moves the mail to the appropriate folder ### -asp-train-good ### trains the message from stdin as ham; ### continues with normal rules to sort the message ### to the folder it belongs to. account "sp-train-spam" disabled stdin account "sp-train-good" disabled stdin ### sometimes you want to test new things by providing mails on stdin account "stdin" disabled stdin ########################################################################### ### Automatic archiving. ### This is a nice idea, I shamelessly stole from NicM's config. ### Mail is kept in Maildirs for 30 days. After that it is ### automatically moved to compressed mboxes, which in turn ### may by periodically removed (by cron for examples, or ### by hand). This (again) uses an account that is disabled, ### so it can be explicitly called by '-aarchive'. account "archive" disabled maildirs { #{{{ "${path}/Inbox" "${path}/bugtraq" "${path}/cmus-devel" "${path}/debian-*" "${path}/full-disclosure" "${path}/fvwm*" "${path}/grml*" "${path}/leafnode" "${path}/linux-*" "${path}/mutt-*" "${path}/openbsd-*" "${path}/pen-test" "${path}/remind-fans" "${path}/schopppe" "${path}/screen-users" "${path}/slrn-users" "${path}/tuhs" "${path}/vim-users" "${path}/zsh-*" #}}} } match account "archive" and age > %{max_age} days action "archive" match account "archive" action "keep" ########################################################################### ### handle mail ### do catchall as early as possible. match string "${do_catchall}" to "^yes$" action "catchall" continue ########## zblog messages ########## ### mails to blog -at- bewatermyfriend -dot- org are meant for zblog. match account "blog" action "zblog" match account "comments" action "zcomm" ########## killfiling ########## ### killfiling on From, From:, Reply-To: and Sender headers ### If your killfile is rather large, this will slow down fdm ### considerably. So do this only on people that really disturb you. match pipe "${com_pfh} | grep -Eqif ${killfile}" returns ( 0, ) actions { "killfile" "maildir-mark-as-read" } ########## spam handling ########## ### force message from stdin to spamfolder and train it as spam match account "sp-train-spam" { match all action "train-spam" continue match "^${header_spam}" in headers action "sp-remove-header" continue match all action "sp-add-trained-spam" continue match all action "spam" } ### train message from stdin as ham match account "sp-train-good" action "train-good" continue match account "sp-train-good" and "^${header_spam}" in headers action "sp-remove-header" continue match account "sp-train-good" action "sp-add-trained-good" continue ### scan for spam match not "^${header_spam}" in headers { match pipe "${com_spam_filter}" returns ( , "(.*)" ) { match "^${header_spam}" in headers action "sp-remove-header" continue match all action "sp-add-header" continue } } ### move messages marked as spam to spamfolder match "^${header_spam}:[ \t]*${filtered_spam}" in headers action "spam" ########## modifying headers ########## ### add Lines: header if it is missing. match not "^Lines:" in headers action "add-lines-header" continue ### remove headers I don't care about match "^${ill_headers}:" in headers action "remove-ill-headers" continue ########## sorting ########## ### debian- mailinglists and pts match "^List-Id:[ \t]*>${base}/ignore" action "dead" } $is_dead = "echo '%1'|grep -Fqif ${base}/ignore" # ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------ # Archive mail to mailboxes. # ------------------------------------------------------------------------------ account "archive" disabled maildirs { "${path}/blug" "${path}/linux-rdma" "${path}/linux-rt-users" "${path}/openbsd-{misc,ports,www,bugs,source-changes,ports-changes}" "${path}/openssh-unix-dev" "${path}/rss" } #action "archive" mbox "${path}/%[maildir]-archives/%[maildir]-%yq%Q" compress action "archive" drop match account "archive" { # Archive mail with invalid dates or older than 30 days. match age invalid or age > 30 days action "archive" # Don't let any other mail get to the normal rules. match all action keep } # ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------ # RSS. # ------------------------------------------------------------------------------ match account "rss" { $crap = "football|sport|prince harry|horse|jockey|royal family|" + "britney spears|cricket|tennis|snooker|motorsport|rugby|" + "princess diana|heather mills|paul mccartney|jamie oliver|" + "music award|candle-lit|in memory|concert|celtic|the queen|" + "richard and judy|madeleine mccann|motoring costs|john crace|" + "richard branson|commonwealth games|olympic games|jill dando|" + "vigil|day of mourning|war dead|amy winehouse|prince charles|" + "remembrance day" match "(${crap})" action drop # Never worth reading... match "^From:.*overheard in new york" in headers { match "^Subject:.*Wednesday.*" in headers action drop match "^Subject:.*One-Liner.*" in headers action drop } match "From:.*techdirt" in headers { match "Subject:.*DailyDirt:.*" in headers action drop match "Subject:.*Of The Week.*" in headers action drop } match "^From:.*tom's hardware" in headers { match "^Subject:.*Presented By:$" in headers action drop } match "^From:.*wired" in headers { match "^Subject:.*Google-a-Day Puzzle.*" in headers action drop } match all action maildir "${path}/rss" } # ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------ # Newsgroups. These are disabled so I can run them using a "fdm -anews f" from # a seperate cronjob less often than normal mail accounts. # ------------------------------------------------------------------------------ account "news" disabled nntp server "infosun2.rus.uni-stuttgart.de" groups { "comp.unix.bsd.openbsd.misc" # "comp.unix.programmer" } cache "${base}/news" match account "news" { match "\\" in body action "junk" # comp.unix.programmer pointless argument usual suspects. match "^From:.*rweikusat@mssgmbh.com" in headers action drop match "^From:.*davids@webmaster.com" in headers action drop # Idiots. match "^From:.*MI5-?Victim@mi5.gov.uk" in headers action drop match "^Organization:.*www.altopia.com" in headers action drop match "^From:.*robin_carey5@yahoo.co.uk" in headers action drop # Spammers. match "^From:.*jak@isp2dial.com" in headers action drop match "^From:.*doctor@doctor.nl2k.ab.ca" in headers action drop # Match based on the group name. match all action maildir "${path}/news-%[group]" } # ------------------------------------------------------------------------------ # Catch local mail early. match account "stdin" action "inbox" # Catch duplicate messages using a message-id cache. $db = "${base}/duplicates" $key = "%[message_id]" cache $db expire 1 week match not string $key to "" { # Filter messages already in the cache. match in-cache $db key $key { # Stupid Google Groups sends me everything twice. match "List-Id:.*belfastlinux.googlegroups.com" in headers action drop match all action maildir "${path}/_duplicates" } # Add message-ids to the cache. match all action to-cache $db key $key continue } # Junk (eejits). match ".*YAHOO.*BOOTER.*" in body action drop # Junk (spam). match "^From:.*ezine@recruitni.com" in headers action drop match "^From:.*@*.chase.com" in headers action drop match "^From:.*@*.chaseonline.com" in headers action drop match "^From:.*@citi-bank.com" in headers action drop match "^From:.*@emaillabs.com" in headers action drop match "^From:.*baypos@gmail.com" in headers action drop match "^From:.*E-Greeting" in headers action drop match "^From:.*@postcard.org" in headers action drop match "^From:.*@mail.itp.net" in headers action drop match "^From:.*@faith-h.net" in headers action drop match "^From:.*reponse@altech-france.fr" in headers action drop match "^From:.*ecards@americangreetings.com" in headers action drop # Junk (ISP/website garbage). match "^From:.*@newsletter.ntlworld.com" in headers action drop match "^From:.*@newsletter.virginmedia.com" in headers action drop match "^From:.*mailings@(gmxnet.de|gmx.net|gmx-gmbh.de)" in headers action drop match "^From:.*@friendsreunited.co.uk" in headers action drop match "^From:.*offers@dabs.com" in headers action drop # AWAD uninteresting crap. match "^Subject:[ \t]*AWADmail Issue [0-9]+" in headers action drop # Copy invalid dates to a special action so I can inspect them. match age invalid action maildir "${path}/_invalid" continue # Copy HTML mail to special action to test attachment parsing. #match attachment any-type "*/html" action maildir "${path}/_html" continue # Test rewriting through cat. #match all action rewrite "cat" continue # Test mbox delivery. #match size > 1K and size < 4K action mbox "${path}/_mbox" compress continue # Add line count header. match all action add-header "Lines" value "%[lines]" continue # Add rule number header. #match all action add-header "Rule" value "%[rule]" continue # BLUG mailing list. match "^X-Apparently-To:.*belfastlinux@googlegroups.com" in headers or "List-ID:.*belfastlinux.googlegroups.com" in headers action maildir "${path}/blug" # ------------------------------------------------------------------------------ # OpenBSD. # ------------------------------------------------------------------------------ match "^Sender:.*owner-([a-z-]*)@openbsd.org" in headers { # Tag the mail. match all action tag "list" value "%1" continue # Drop any mail which is replying to a message-id on the ignore list. match "^References:[ \t]*(.*)" in headers and exec ${is_dead} returns (0, ) action "dead" match "^In-Reply-To:[ \t]*([^()]*)" in headers and exec ${is_dead} returns (0, ) action "dead" # Drop a selection of eejits/trolls/time wasters/whiners/pompous # twits/uninteresting persons and add to ignore list. match "^From:.*john@johntate.org" in headers action "diediedie" match "^From:.*billitch@gmail.com" in headers action "diediedie" match "^From:.*rms@1407.org" in headers action "diediedie" match "^From:.*clock@twibright.com" in headers action "diediedie" match "^From:.*dfeustel@mindspring.com" in headers action "diediedie" match "^From:.*peter_philipp@freenet.de" in headers action "diediedie" match "^From:.*philipp.peter@freenet.de" in headers action "diediedie" match "^From:.*suck@my-balls.com" in headers action "diediedie" match "^From:.*chefren@pi.net" in headers action "diediedie" match "^From:.*demuel@thephinix.org" in headers action "diediedie" match "^From:.*lvl@omnitec.net" in headers action "diediedie" match "^From:.*timo.schoeler@riscworks.net" in headers action "diediedie" match "^From:.*ropers@gmail.com" in headers action "diediedie" match "^From:.*leonleon77@gmail.com" in headers action "diediedie" match "^From:.*af.gourmet@videotron.ca" in headers action "diediedie" match "^From:.*nicedaemon@googlemail.com" in headers action "diediedie" match "^From:.*vim.unix@googlemail.com" in headers action "diediedie" match "^From:.*emaillistemail@gmail.com" in headers action "diediedie" match "^From:.*4625khz@gmail.com" in headers action "diediedie" match "^From:.*Rhubbell@iHubbell.com" in headers action "diediedie" match "^From:.*donaldcallen@gmail.com" in headers action "diediedie" match "^From:.*nealhogan@gmail.com" in headers action "diediedie" match "^From:.*glisten@witworx.com" in headers action "diediedie" match "^From:.*ma1l1ists@yahoo.co.uk" in headers action "diediedie" match "^From:.*yclwebmaster@gmail.com" in headers action "diediedie" match "^From:.*fritz@.*.rodent.frell.theremailer.net" in headers action "diediedie" # Special-case announce. match string "%[list]" to "announce" action "inbox" # Special-case gnats. match string "%[list]" to "gnats" action "${path}/openbsd-bugs" # Deliver to openbsd-%1. match all action maildir "${path}/openbsd-%[list]" } # ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------ # NetBSD. # ------------------------------------------------------------------------------ #match "^List-Id: ([a-z-]*).NetBSD.org" in headers # action maildir "${path}/netbsd-%1" # ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------ # FreeBSD. # ------------------------------------------------------------------------------ #match "^Sender:.*owner-([a-z-]*)@freebsd.org" in headers # action maildir "${path}/freebsd-%1" # ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------ # GNU Screen. # ------------------------------------------------------------------------------ match "^X-BeenThere:.*screen-users@gnu.org" in headers action maildir "${path}/screen-users" match "^X-BeenThere:.*screen-devel@gnu.org" in headers action maildir "${path}/screen-devel" # ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------ # GNU ncurses. # ------------------------------------------------------------------------------ match "^X-BeenThere:.*bug-ncurses@gnu.org" in headers action maildir "${path}/bug-ncurses" # ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------ # libevent # ------------------------------------------------------------------------------ match "^Sender: owner-libevent-users@freehaven.net" in headers action maildir "${path}/libevent-users" # ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------ # btpd # ------------------------------------------------------------------------------ match "^Sender: btpd-users@googlegroups.com" in headers action maildir "${path}/btpd-users" # ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------ # Linux # ------------------------------------------------------------------------------ match "^X-Mailing-List:.*linux-rdma@vger.kernel.org" in headers action maildir "${path}/linux-rdma" match "^X-Mailing-List:.*linux-rt-users@vger.kernel.org" in headers action maildir "${path}/linux-rt-users" # ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------ # OpenSSH. # ------------------------------------------------------------------------------ match "^X-BeenThere:.*openssh-unix-dev@mindrot.org" in headers action maildir "${path}/openssh-unix-dev" # ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------ # OSS Security. # ------------------------------------------------------------------------------ match "^List-Post:.*oss-security@lists.openwall.com" in headers action maildir "${path}/oss-security" # ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------ # OSS Security. # ------------------------------------------------------------------------------ match "^X-Mailing-List:.*austin-group-l" in headers action maildir "${path}/austin-group-l" # ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------ # Poem-A-Day # ------------------------------------------------------------------------------ match "^To:.*poetnews@poets.org" in headers action maildir "${path}/poems" # ------------------------------------------------------------------------------ # OpenMAMA # ------------------------------------------------------------------------------ match "^List-Id:.*openmama-dev.lists.openmama.org" in headers action maildir "${path}/openmama-dev" match "^List-Id:.*openmama-users.lists.openmama.org" in headers action maildir "${path}/openmama-users" # Default action. match all action "inbox" fdm-1.7/examples/t-ulmer.conf010064400017500001750000000143051112127571600164320ustar00nicholasnicholasaccount "tmux" imaps server "host" user "tobiasu" pass "password" account "spam-box" maildir "%h/mail/.spam.train" # Actions action "inbox" maildir "%h/mail" action "friends" maildir "%h/mail/.friends" action "tendra-dev" maildir "%h/mail/.tendra-dev" action "edri" maildir "%h/mail/.edri" action "fitug" maildir "%h/mail/.fitug" action "nanog" maildir "%h/mail/.nanog" action "cryptogram" maildir "%h/mail/.cryptogram" action "bibliothek" maildir "%h/mail/.bibliothek" action "arcor" maildir "%h/mail/.arcor" action "obsd-advocacy" maildir "%h/mail/.openbsd.advocacy" action "obsd-alpha" maildir "%h/mail/.openbsd.alpha" action "obsd-arm" maildir "%h/mail/.openbsd.arm" action "obsd-bugs" maildir "%h/mail/.openbsd.bugs" action "obsd-hppa" maildir "%h/mail/.openbsd.hppa" action "obsd-ipv6" maildir "%h/mail/.openbsd.ipv6" action "obsd-mac68k" maildir "%h/mail/.openbsd.mac68k" action "obsd-misc" maildir "%h/mail/.openbsd.misc" action "obsd-ports" maildir "%h/mail/.openbsd.ports" action "obsd-ports-changes" maildir "%h/mail/.openbsd.ports-changes" action "obsd-ppc" maildir "%h/mail/.openbsd.ppc" action "obsd-source-changes" maildir "%h/mail/.openbsd.source-changes" action "obsd-sparc" maildir "%h/mail/.openbsd.sparc" action "obsd-tech" maildir "%h/mail/.openbsd.tech" action "obsd-vax" maildir "%h/mail/.openbsd.vax" action "obsd-www" maildir "%h/mail/.openbsd.www" action "obsd-x11" maildir "%h/mail/.openbsd.x11" action "sec-bugtraq" maildir "%h/mail/.security.bugtraq" action "sec-fd" maildir "%h/mail/.security.full-disclosure" action "sec-secunia" maildir "%h/mail/.security.secunia" action "suck-wmii" maildir "%h/mail/.suckless.wmii" action "suck-dwm" maildir "%h/mail/.suckless.dwm" action "spam-new" maildir "%h/mail/.spam.new" action "spam-train" maildir "%h/mail/.spam.train" action "spam-archive" mbox "%h/mail/archive/trained-spam" action "drop" drop action "bf-unreg-nospam" rewrite "bogofilter -e -p -N" action "bf-reg-spam" rewrite "bogofilter -e -p -s" action "bf-update" rewrite "bogofilter -e -p -u" action "strip-bullshit" rewrite "reformail -IX-HE-Virus-Scanned: -IX-HE-Spam-Level: -IX-HE-Spam-Score: -IX-HE-Spam-Report: -IX-Antivirus-Scanner: -IX-AntiAbuse: -IX-Spam: -IX-SPAM-FLAG: -IX-Virus-Scanned: -IX-ELNK-Trace: -IX-Converted-To-Plain-Text: -IX-Priority: -IX-Greylist: -IX-OriginalArrivalTime: -IX-Sun-Charset: -IX-MSMail-Priority: -IImportance: -IX-MimeOLE: -IPriority:" action "strip-fd" rewrite "sed 's/^\\(Subject:.*\\)\\[Full-disclosure\\] /\\1/'" # spam-box rules match account "spam-box" { match "^X-MySecretSpamHeader: Yes" in headers action "spam-archive" match "^X-MySecretSpamHeader: No" in headers action "bf-unreg-nospam" continue match all action "bf-reg-spam" continue match "^X-MySecretSpamHeader: Yes" in headers action "spam-archive" match all action "bf-reg-spam" continue match "^X-MySecretSpamHeader: Yes" in headers action "spam-archive" match all action "bf-reg-spam" continue match "^X-MySecretSpamHeader: Yes" in headers action "spam-archive" match all action "bf-reg-spam" continue match "^X-MySecretSpamHeader: Yes" in headers action "spam-archive" match all action "bf-reg-spam" continue match "^X-MySecretSpamHeader: Yes" in headers action "spam-archive" match all action "bf-reg-spam" continue # ok, we've tried 5 times, just put the thing into the spam archive match all action "spam-archive" } # tmux rules match all action "strip-bullshit" continue match all action "bf-update" continue match "^X-MySecretSpamHeader: Yes" in headers action "spam-new" match "^sender: owner.*@openbsd\\.org" in headers { match "^sender:.*advocacy" in headers action "obsd-advocacy" match "^sender:.*alpha" in headers action "obsd-alpha" match "^sender:.*arm" in headers action "obsd-arm" match "^sender:.*bugs" in headers action "obsd-bugs" match "^sender:.*hppa" in headers action "obsd-hppa" match "^sender:.*ipv6" in headers action "obsd-ipv6" match "^sender:.*mac68k" in headers action "obsd-mac68k" match "^sender:.*misc" in headers action "obsd-misc" match "^sender:.*ports-changes" in headers action "obsd-ports-changes" # first! match "^sender:.*ports" in headers action "obsd-ports" match "^sender:.*ppc" in headers action "obsd-ppc" match "^sender:.*source-changes" in headers action "obsd-source-changes" match "^sender:.*sparc" in headers action "obsd-sparc" match "^sender:.*tech" in headers action "obsd-tech" match "^sender:.*vax" in headers action "obsd-vax" match "^sender:.*www" in headers action "obsd-www" match "^sender:.*x11" in headers action "obsd-x11" } match "^from: secunia security advisories " in headers or "^list-id: " in headers { match "^subject:.*\\[full-disclosure\\]" in headers action "strip-fd" continue match "^subject: \\[ glsa" in headers action "drop" match "^subject: \\[usn-" in headers action "drop" match "^subject: \\[ mdksa" in headers action "drop" match "^subject: \\[security\\] \\[dsa" in headers action "drop" match "^from:.*announce-noreply@rpath\\.com" in headers action "drop" match "^list-post: " in headers action "sec-fd" match "^list-id: " in headers action "sec-bugtraq" } match "^list-id: wmii community " in headers action "fitug" match "^list-id: edri-news\\.mailman\\.edri\\.org" in headers action "edri" match "^To: CRYPTO-GRAM-LIST@LISTSERV\\.MODWEST\\.COM" in headers action "cryptogram" match "^From: L-Service@bsz-bw\\.de" in headers action "bibliothek" match "^from:.*rechnung\\.arcor\\.de" in headers action "arcor" match "^from:.*friend1@googlemail\\.com" in headers or "^from:.*friend2@yahoo\\.de" in headers # ... action "friends" match "^sender: tendra-dev-bounces@lists\\.tendra\\.org" in headers action "tendra-dev" match all action "inbox" fdm-1.7/examples/w-maier.conf010064400017500001750000000160101112127571600164010ustar00nicholasnicholas# vim: set nospell: # Settings. set lock-types flock set maximum-size 10M # Macros. $path = "%h/.maildir" $hep = "${path}/HEP" $lug = "${path}/LUG" $foss = "${path}/FOSS" $obsd = "${path}/OBSD" $bsd = "${path}/BSD" $linux = "${path}/Linux" $ubuntu = "${path}/Ubuntu" $sec = "${path}/SEC" # Actions. action "drop" drop # General. action "inbox" maildir "${path}/Inbox" action "junk" maildir "${path}/Junk" action "sent" maildir "${path}/Sent" action "spam" maildir "${path}/Spam" # LUGs. action "madlug" maildir "${lug}/Madlug" action "mkelug" maildir "${lug}/Mkelug" # UW TP. action "tp" maildir "${path}/TP" # Security. action "bugtraq" maildir "${sec}/BugTraq" action "dailydave" maildir "${sec}/DailyDave" action "secunia" maildir "${sec}/Secunia" # Debian. action "deb-ann" maildir "${linux}/Debian/Announce" action "deb-news" maildir "${linux}/Debian/News" action "deb-sec" maildir "${linux}/Debian/Security" # FreeBSD. action "fbsd" maildir "${bsd}/Free/Announce" action "fbsd-sec" maildir "${bsd}/Free/Security" # OpenBSD. action "obsd" maildir "${obsd}/General" action "obsd-bugs" maildir "${obsd}/Bugs" action "obsd-cvs" maildir "${obsd}/CVS" action "obsd-misc" maildir "${obsd}/Misc" action "obsd-ports" maildir "${obsd}/Ports" action "obsd-tech" maildir "${obsd}/Tech" # NetBSD. action "netbsd-sec" maildir "${bsd}/Net/Security" # Ubuntu. action "ubuntu-sec" maildir "${ubuntu}/Security" action "ubuntu" maildir "${ubuntu}/News" # FOSS. action "afs" maildir "${foss}/OpenAFS" action "elinks" maildir "${foss}/Elinks" action "hg" maildir "${foss}/Hg" action "ion" maildir "${foss}/Ion" action "ipython" maildir "${foss}/IPython" action "maildrop" maildir "${foss}/Maildrop" action "mutt" maildir "${foss}/Mutt" action "postfix" maildir "${foss}/Postfix" action "roundup" maildir "${foss}/Roundup" action "screen" maildir "${foss}/Screen" action "vim" maildir "${foss}/Vim" action "zsh" maildir "${foss}/Zsh" # Personal. action "family" maildir "${path}/Family" action "friend" maildir "${path}/Friend" # Work. action "absent" maildir "${hep}/Absent" action "cms" maildir "${hep}/CMS" action "dept" maildir "${hep}/Department" action "hep" maildir "${hep}/Inbox" action "root" maildir "${hep}/Root" action "glow" maildir "${hep}/GLOW" action "glow-absent" maildir "${hep}/Absent" action "nagios" maildir "${hep}/Nagios" action "req" maildir "${hep}/RQ" # SPAM. action "bmf" rewrite "bmf -p" # The stdin account is disabled: it will be ignored unless # explicitly requested using the -a switch on the command line. account "stdin" disabled stdin # Accounts. account "fm" pop3s server "mail.messagingengine.com" port 995 user "" pass "" account "hep" imaps server "hep.wisc.edu" port 993 user "" pass "" account "uw" pop3s server "wiscmail.wisc.edu" port 995 user "" pass "" account "gmail" pop3s server "pop.googlemail.com" port 995 user "" pass "" # Filter rules. # SPAM trap. # STUB: add relaydb based on bmf(1) at some point. match all action "bmf" continue match "^X-Spam-Status: Yes" in headers action "spam" # LUGs. match "^List-Id:.*madlug\\.madisonlinux\\.org" in headers action "madlug" match "^List-Id:.*mlug-list\\.mail\\.milwaukeelug\\.org" in headers action "mkelug" # FOSS. match "^List-Id:.*openafs-info\\.openafs\\.org" in headers action "afs" match "^List-Id:.*elinks-users\\.linuxfromscratch\\.org" in headers action "elinks" match "^List-Id:.*mercurial\\.selenic\\.com" in headers action "hg" match "^List-Id:.*ion-general\\.lists\\.berlios\\.de" in headers action "ion" match "^List-Id:.*ipython-user\\.scipy\\.org" in headers action "ipython" match "^List-Id:.*courier-maildrop\\.lists\\.sourceforge\\.net" in headers action "maildrop" match "^Sender:.*owner-mutt-users@mutt\\.org" in headers action "mutt" match "^List-Post:.*postfix-users@postfix\\.org" in headers action "postfix" match "^List-Id:.*roundup-users\\.lists\\.sourceforge\\.net" in headers action "roundup" match "^Mailing-List:.*vim-help@vim\\.org" in headers action "vim" match "^Mailing-List:.*zsh.*@sunsite\\.dk" in headers action "zsh" # Debian. match "^List-Id:.*lists\\.debian\\.org" in headers { match "^List-Id:.*announce" in headers action "deb-ann" match "^List-Id:.*news" in headers action "deb-news" match "^List-Id:.*security" in headers action "deb-sec" } # FreeBSD. match "^List-Id:.*freebsd-.*\\.freebsd\\.org" in headers { match "^List-Id:.*security-notifications" in headers action "fbsd-sec" match "^List-Id:.*announce" in headers { # I already get security announcements... match "^Subject.*FreeBSD Security Advisory FreeBSD-SA-" action "drop" match all action "fbsd" } } # OpenBSD. match "^Sender:[ \t]*owner-([a-z-]*)@openbsd\\.org" in headers { match string "%1" to "gnats" action "obsd-bugs" match string "%1" to "ports-changes" action "obsd-cvs" match string "%1" to "source-changes" action "obsd-cvs" match all action "obsd-%1" } # Ubuntu. match "^List-Id:.*ubuntu-.*\\.lists\\.ubuntu\\.com" in headers { match "^List-Id:.*security" in headers action "ubuntu-sec" match all action "ubuntu" } # NetBSD. match "^Sender:.*@netbsd\\.org" in headers { match "^Sender:.*tech-security" in headers action "netbsd-sec" } # Techpartners. match "^(To|Cc):.*techpartners@lists\\.wisc\\.edu" in headers action "tp" # DailyDave. match "^List-Id:.*dailydave\\.lists\\.immunitysec\\.com" in headers action "dailydave" # BugTraq. match "^List-Id:.*bugtraq\\.list-id\\.securityfocus\\.com" in headers action "bugtraq" # Secunia advisories. match "^From:.*sec-adv@secunia\\.com" in headers action "secunia" # Family. match "^From:.*mom@mom\\.net" or "^From:.*dad@(dad|father)\\.com" or "^From:.*sister@yahoo\\.com" in headers action "family" # Friends. match "^From:.*tom@hotmail\\.com" or "^From:.*dick@yahoo\\.com" or "^From:.*harry\\.cameron@gmail\\.com" in headers action "friend" # GLOW. match "^List-Id:.*glow-tech\\.cs\\.wisc\\.edu" in headers { match "^Subject: \\[glow-tech\\] GLOW Absent Report$" in headers action "glow-absent" match all action "glow" } # CMS. match "^List-Owner:.*CMS.*@LISTSERV\\.FNAL\\.GOV" in headers action "cms" # Physics. match "^(To|Cc):.*@physics\\.wisc\\.edu" in headers { match "^(To|Cc):.*(root|operator|cron)@" in headers action "root" match all action "dept" } # HEP. match "^(From|To):.*(hep|cs)\\.wisc\\.edu" in headers { match "^Subject: (UW-HEP)? (Condor|dCache|CFengine) Absent Report" in headers action "absent" match "(From|To|Cc):.*(help|req)@(nod|ginseng)\.hep\.wisc\.edu" in headers action "req" # HEP root mail. match "^(To|Cc):.*(root|operator|cron)@" in headers action "root" match "^Subject: (UP|DOWN|RECOVERY|PROBLEM):" in headers action "nagios" match all action "hep" } # Default filter. match all action "inbox" fdm-1.7/regress/test-imap/imap-close-1.test010064400017500001750000000004721112127570300210210ustar00nicholasnicholas>* OK <1 CAPABILITY >* CAPABILITY IMAP4rev1 >1 OK <2 LOGIN {4} >+ + 2 OK <3 SELECT {5} >+ * 1 EXISTS >3 OK <4 UID SEARCH ALL >* SEARCH 1 >4 OK <5 UID FETCH 1 BODY[] >* 1 FETCH (BODY[] {5} >Test.) >5 OK <6 UID STORE 1 +FLAGS.SILENT (\Deleted) >6 OK <7 CLOSE >7 NO -- unexpected data: 7 NO fdm-1.7/regress/test-imap/Makefile010064400017500001750000000005701112227734700173770ustar00nicholasnicholas# $Id: Makefile,v 1.2 2008/12/17 22:36:23 nicm Exp $ CLEANFILES= *~ *.fifo.{in,out} *.log *.conf TESTFILES!= echo imap-*.test TARGETS= .for n in ${TESTFILES} TARGETS+= ${n} ${n}: @HOME=. FDM="../../fdm -h" sh test-imap.sh ${n} .endfor .MAIN: all .PHONY: regress clean ${TARGETS} .PRECIOUS: ${TARGETS} all: regress regress: ${TARGETS} clean: rm -f ${CLEANFILES} fdm-1.7/regress/test-imap/imap-capability-1.test010064400017500001750000000000631112127570300220310ustar00nicholasnicholas>* OK <1 CAPABILITY >1 OK -- unexpected data: 1 OK fdm-1.7/regress/test-imap/imap-capability-2.test010064400017500001750000000001131112127570200220250ustar00nicholasnicholas>* OK <1 CAPABILITY >* CAPABILITY IMAP4rev1 >2 OK -- unexpected data: 2 OK fdm-1.7/regress/test-imap/imap-capability-3.test010064400017500001750000000001141112127570300220300ustar00nicholasnicholas>* OK <1 CAPABILITY >* CAPABILITY -- no IMAP4rev1 capability: \* CAPABILITY fdm-1.7/regress/test-imap/imap-capability-4.test010064400017500001750000000000631112127570400220350ustar00nicholasnicholas>* OK <1 CAPABILITY >1 NO -- unexpected data: 1 NO fdm-1.7/regress/test-imap/imap-close-2.test010064400017500001750000000004761112127570400210270ustar00nicholasnicholas>* OK <1 CAPABILITY >* CAPABILITY IMAP4rev1 >1 OK <2 LOGIN {4} >+ + 2 OK <3 SELECT {5} >+ * 1 EXISTS >3 OK <4 UID SEARCH ALL >* SEARCH 1 >4 OK <5 UID FETCH 1 BODY[] >* 1 UID FETCH (BODY[] {5} >Test.) >5 OK <6 UID STORE 1 +FLAGS.SILENT (\Deleted) >6 OK <7 CLOSE >8 OK -- unexpected data: 8 OK fdm-1.7/regress/test-imap/imap-cram-md5-1.test010064400017500001750000000001701112127570300213140ustar00nicholasnicholas>* OK <1 CAPABILITY >* CAPABILITY IMAP4rev1 AUTH=CRAM-MD5 >1 OK <2 AUTHENTICATE CRAM-MD5 >2 OK -- unexpected data: 2 OK fdm-1.7/regress/test-imap/imap-cram-md5-2.test010064400017500001750000000002001112127570200213060ustar00nicholasnicholas>* OK <1 CAPABILITY >* CAPABILITY IMAP4rev1 AUTH=CRAM-MD5 >1 OK <2 AUTHENTICATE CRAM-MD5 # No spaces. >+ -- invalid response: + fdm-1.7/regress/test-imap/imap-cram-md5-3.test010064400017500001750000000002021112127570300213120ustar00nicholasnicholas>* OK <1 CAPABILITY >* CAPABILITY IMAP4rev1 AUTH=CRAM-MD5 >1 OK <2 AUTHENTICATE CRAM-MD5 # One space. >+ -- invalid response: + fdm-1.7/regress/test-imap/imap-cram-md5-4.test010064400017500001750000000002661112127570200213240ustar00nicholasnicholas>* OK <1 CAPABILITY >* CAPABILITY IMAP4rev1 AUTH=CRAM-MD5 >1 OK <2 AUTHENTICATE CRAM-MD5 >+ test 3 OK -- unexpected data: 3 OK fdm-1.7/regress/test-imap/imap-cram-md5-5.test010064400017500001750000000003461112127570200213240ustar00nicholasnicholas>* OK <1 CAPABILITY >* CAPABILITY IMAP4rev1 AUTH=CRAM-MD5 >1 OK <2 AUTHENTICATE CRAM-MD5 >+ test 2 OK <3 SELECT {5} >+ * 0 EXISTS >3 OK <4 CLOSE >4 OK <5 LOGOUT >5 OK fdm-1.7/regress/test-imap/imap-cram-md5-6.test010064400017500001750000000003601112127570200213210ustar00nicholasnicholas>* OK <1 CAPABILITY >* CAPABILITY IMAP4rev1 AUTH=CRAM-MD5 >1 OK <2 AUTHENTICATE CRAM-MD5 >+ test 2 OK test test <3 SELECT {5} >+ * 0 EXISTS >3 OK <4 CLOSE >4 OK <5 LOGOUT >5 OK fdm-1.7/regress/test-imap/imap-fetch-body-1.test010064400017500001750000000004001112127570300217270ustar00nicholasnicholas>* OK <1 CAPABILITY >* CAPABILITY IMAP4rev1 >1 OK <2 LOGIN {4} >+ + 2 OK <3 SELECT {5} >+ * 1 EXISTS >3 OK <4 UID SEARCH ALL >* SEARCH 1 >4 OK <5 UID FETCH 1 BODY[] >* 1 UID FETCH (BODY[] {5} >Test.X) -- invalid response: Test.X) fdm-1.7/regress/test-imap/imap-fetch-body-2.test010064400017500001750000000004001112127570200217270ustar00nicholasnicholas>* OK <1 CAPABILITY >* CAPABILITY IMAP4rev1 >1 OK <2 LOGIN {4} >+ + 2 OK <3 SELECT {5} >+ * 1 EXISTS >3 OK <4 UID SEARCH ALL >* SEARCH 1 >4 OK <5 UID FETCH 1 BODY[] >* 1 UID FETCH (BODY[] {5} >Test.)) -- invalid response: Test.)) fdm-1.7/regress/test-imap/imap-fetch-body-3.test010064400017500001750000000004121112127570300217340ustar00nicholasnicholas>* OK <1 CAPABILITY >* CAPABILITY IMAP4rev1 >1 OK <2 LOGIN {4} >+ + 2 OK <3 SELECT {5} >+ * 1 EXISTS >3 OK <4 UID SEARCH ALL >* SEARCH 1 >4 OK <5 UID FETCH 1 BODY[] >* 1 UID FETCH (BODY[] {} -- invalid response: \* 1 UID FETCH (BODY\[\] {} fdm-1.7/regress/test-imap/imap-fetch-body-4.test010064400017500001750000000003361112127570300217420ustar00nicholasnicholas>* OK <1 CAPABILITY >* CAPABILITY IMAP4rev1 >1 OK <2 LOGIN {4} >+ + 2 OK <3 SELECT {5} >+ * 1 EXISTS >3 OK <4 UID SEARCH ALL >* SEARCH 1 >4 OK <5 UID FETCH 1 BODY[] >5 NO -- unexpected data: 5 NO fdm-1.7/regress/test-imap/imap-fetch-body-5.test010064400017500001750000000004011112127570300217340ustar00nicholasnicholas>* OK <1 CAPABILITY >* CAPABILITY IMAP4rev1 >1 OK <2 LOGIN {4} >+ + 2 OK <3 SELECT {5} >+ * 1 EXISTS >3 OK <4 UID SEARCH ALL >* SEARCH 1 >4 OK <5 UID FETCH 1 BODY[] >* 1 UID FETCH (BODY[] {5} >Test.) >5 NO -- unexpected data: 5 NO fdm-1.7/regress/test-imap/imap-fetch-body-6.test010064400017500001750000000003771112127570300217510ustar00nicholasnicholas>* OK <1 CAPABILITY >* CAPABILITY IMAP4rev1 >1 OK <2 LOGIN {4} >+ + 2 OK <3 SELECT {5} >+ * 1 EXISTS >3 OK <4 UID SEARCH ALL >* SEARCH 1 >4 OK <5 UID FETCH 1 BODY[] >* 1 UID FETCH (BODY[] {5} >Test. >) -- invalid response: Test. fdm-1.7/regress/test-imap/imap-fetch-body-7.test010064400017500001750000000003641112127570300217460ustar00nicholasnicholas>* OK <1 CAPABILITY >* CAPABILITY IMAP4rev1 >1 OK <2 LOGIN {4} >+ + 2 OK <3 SELECT {5} >+ * 1 EXISTS >3 OK <4 UID SEARCH ALL >* SEARCH 1 >4 OK <5 UID FETCH 1 BODY[] >* 1 UID FETCH (BODY[] {0} >) >5 OK -- empty message fdm-1.7/regress/test-imap/imap-fetch-body-8.test010064400017500001750000000004761112127570300217530ustar00nicholasnicholas>* OK <1 CAPABILITY >* CAPABILITY IMAP4rev1 >1 OK <2 LOGIN {4} >+ + 2 OK <3 SELECT {5} >+ * 1 EXISTS >3 OK <4 UID SEARCH ALL >* SEARCH 1 >4 OK <5 UID FETCH 1 BODY[] >* 1 UID FETCH (BODY[] {5} >Test. FLAGS ()) >5 OK <6 UID STORE 1 +FLAGS.SILENT (\Deleted) >6 OK <7 CLOSE >7 OK <8 LOGOUT >8 OK fdm-1.7/regress/test-imap/imap-fetch-body-9.test010064400017500001750000000003751112127570200217510ustar00nicholasnicholas>* OK <1 CAPABILITY >* CAPABILITY IMAP4rev1 >1 OK <2 LOGIN {4} >+ + 2 OK <3 SELECT {5} >+ * 1 EXISTS >3 OK <4 UID SEARCH ALL >* SEARCH 1 >4 OK <5 UID FETCH 1 BODY[] >* 1 UID FETCH (BODY[] {0} >FLAGS ()) >5 OK -- empty message fdm-1.7/regress/test-imap/imap-fetch-body-A.test010064400017500001750000000004241112127570300217550ustar00nicholasnicholas>* OK <1 CAPABILITY >* CAPABILITY IMAP4rev1 >1 OK <2 LOGIN {4} >+ + 2 OK <3 SELECT {5} >+ * 1 EXISTS >3 OK <4 UID SEARCH ALL >* SEARCH 1 >4 OK <5 UID FETCH 1 BODY[] >* 1 UID FETCH (BODY[] {5} >Test. FLAGS () >5 OK -- invalid response: Test. FLAGS () fdm-1.7/regress/test-imap/imap-fetch-body-B.test010064400017500001750000000004261112127570200217570ustar00nicholasnicholas>* OK <1 CAPABILITY >* CAPABILITY IMAP4rev1 >1 OK <2 LOGIN {4} >+ + 2 OK <3 SELECT {5} >+ * 1 EXISTS >3 OK <4 UID SEARCH ALL >* SEARCH 1 >4 OK <5 UID FETCH 1 BODY[] >* 1 UID FETCH (BODY[] {6} >Test. FLAGS ()) >5 OK -- invalid response: Test. FLAGS ()) fdm-1.7/regress/test-imap/imap-fetch-uid-1.test010064400017500001750000000002661112127570200215640ustar00nicholasnicholas>* OK <1 CAPABILITY >* CAPABILITY IMAP4rev1 >1 OK <2 LOGIN {4} >+ + 2 OK <3 SELECT {5} >+ * 1 EXISTS >3 OK <4 UID SEARCH ALL >5 OK -- unexpected data: 5 OK fdm-1.7/regress/test-imap/imap-fetch-uid-2.test010064400017500001750000000002661112127570400215670ustar00nicholasnicholas>* OK <1 CAPABILITY >* CAPABILITY IMAP4rev1 >1 OK <2 LOGIN {4} >+ + 2 OK <3 SELECT {5} >+ * 1 EXISTS >3 OK <4 UID SEARCH ALL >4 OK -- unexpected data: 4 OK fdm-1.7/regress/test-imap/imap-login-1.test010064400017500001750000000001361112127570400210220ustar00nicholasnicholas>* OK <1 CAPABILITY >* CAPABILITY IMAP4rev1 >1 OK <2 LOGIN {4} >2 OK -- unexpected data: 2 OK fdm-1.7/regress/test-imap/imap-login-2.test010064400017500001750000000001531112127570300210210ustar00nicholasnicholas>* OK <1 CAPABILITY >* CAPABILITY IMAP4rev1 >1 OK <2 LOGIN {4} >+ 2 OK -- unexpected data: 2 OK fdm-1.7/regress/test-imap/imap-login-3.test010064400017500001750000000001531112127570200210210ustar00nicholasnicholas>* OK <1 CAPABILITY >* CAPABILITY IMAP4rev1 >1 OK <2 LOGIN {4} >+ 2 NO -- unexpected data: 2 NO fdm-1.7/regress/test-imap/imap-logout-1.test010064400017500001750000000005161112127570300212240ustar00nicholasnicholas>* OK <1 CAPABILITY >* CAPABILITY IMAP4rev1 >1 OK <2 LOGIN {4} >+ + 2 OK <3 SELECT {5} >+ * 1 EXISTS >3 OK <4 UID SEARCH ALL >* SEARCH 1 >4 OK <5 UID FETCH 1 BODY[] >* 1 UID FETCH (BODY[] {5} >Test.) >5 OK <6 UID STORE 1 +FLAGS.SILENT (\Deleted) >6 OK <7 CLOSE >7 OK <8 LOGOUT >8 NO -- unexpected data: 8 NO fdm-1.7/regress/test-imap/imap-logout-2.test010064400017500001750000000005161112127570300212250ustar00nicholasnicholas>* OK <1 CAPABILITY >* CAPABILITY IMAP4rev1 >1 OK <2 LOGIN {4} >+ + 2 OK <3 SELECT {5} >+ * 1 EXISTS >3 OK <4 UID SEARCH ALL >* SEARCH 1 >4 OK <5 UID FETCH 1 BODY[] >* 1 UID FETCH (BODY[] {5} >Test.) >5 OK <6 UID STORE 1 +FLAGS.SILENT (\Deleted) >6 OK <7 CLOSE >7 OK <8 LOGOUT >9 OK -- unexpected data: 9 OK fdm-1.7/regress/test-imap/imap-one-1.test010064400017500001750000000004651112127570200204760ustar00nicholasnicholas>* OK <1 CAPABILITY >* CAPABILITY IMAP4rev1 >1 OK <2 LOGIN {4} >+ + 2 OK <3 SELECT {5} >+ * 1 EXISTS >3 OK <4 UID SEARCH ALL >* SEARCH 1 >4 OK <5 UID FETCH 1 BODY[] >* 1 UID FETCH (BODY[] {5} >Test.) >5 OK <6 UID STORE 1 +FLAGS.SILENT (\Deleted) >6 OK <7 CLOSE >7 OK <8 LOGOUT >8 OK fdm-1.7/regress/test-imap/imap-one-2.test010064400017500001750000000006551112127570300205010ustar00nicholasnicholas>* OK test test <1 CAPABILITY >* CAPABILITY IMAP4rev1 >1 OK test test <2 LOGIN {4} >+ test test + test test 2 OK test test <3 SELECT {5} >+ test test * 1 EXISTS >3 OK test test <4 UID SEARCH ALL >* SEARCH 1 >4 OK test test <5 UID FETCH 1 BODY[] >* 1 UID FETCH (BODY[] {5} >Test.) >5 OK test test <6 UID STORE 1 +FLAGS.SILENT (\Deleted) >6 OK test test <7 CLOSE >7 OK test test <8 LOGOUT >8 OK test test fdm-1.7/regress/test-imap/imap-select-1.test010064400017500001750000000002101112127570200211600ustar00nicholasnicholas>* OK <1 CAPABILITY >* CAPABILITY IMAP4rev1 >1 OK <2 LOGIN {4} >+ + 2 OK <3 SELECT {5} >3 OK -- unexpected data: 3 OK fdm-1.7/regress/test-imap/imap-select-2.test010064400017500001750000000002101112127570200211610ustar00nicholasnicholas>* OK <1 CAPABILITY >* CAPABILITY IMAP4rev1 >1 OK <2 LOGIN {4} >+ + 2 OK <3 SELECT {5} >3 NO -- unexpected data: 3 NO fdm-1.7/regress/test-imap/imap-select-3.test010064400017500001750000000002221112127570300211660ustar00nicholasnicholas>* OK <1 CAPABILITY >* CAPABILITY IMAP4rev1 >1 OK <2 LOGIN {4} >+ + 2 OK <3 SELECT {5} >+ 3 NO -- unexpected data: 3 NO fdm-1.7/regress/test-imap/imap-select-4.test010064400017500001750000000002221112127570300211670ustar00nicholasnicholas>* OK <1 CAPABILITY >* CAPABILITY IMAP4rev1 >1 OK <2 LOGIN {4} >+ + 2 OK <3 SELECT {5} >+ 3 OK -- unexpected data: 3 OK fdm-1.7/regress/test-imap/imap-select-5.test010064400017500001750000000002601112127570200211710ustar00nicholasnicholas>* OK <1 CAPABILITY >* CAPABILITY IMAP4rev1 >1 OK <2 LOGIN {4} >+ + 2 OK <3 SELECT {5} >+ * 0 EXISTS >* 1 EXISTS >3 OK <4 CLOSE >4 OK <5 LOGOUT >5 OK fdm-1.7/regress/test-imap/imap-store-flags-1.test010064400017500001750000000004571112127570300221450ustar00nicholasnicholas>* OK <1 CAPABILITY >* CAPABILITY IMAP4rev1 >1 OK <2 LOGIN {4} >+ + 2 OK <3 SELECT {5} >+ * 1 EXISTS >3 OK <4 UID SEARCH ALL >* SEARCH 1 >4 OK <5 UID FETCH 1 BODY[] >* 1 UID FETCH (BODY[] {5} >Test.) >5 OK <6 UID STORE 1 +FLAGS.SILENT (\Deleted) >6 NO -- unexpected data: 6 NO fdm-1.7/regress/test-imap/imap-store-flags-2.test010064400017500001750000000004571112127570300221460ustar00nicholasnicholas>* OK <1 CAPABILITY >* CAPABILITY IMAP4rev1 >1 OK <2 LOGIN {4} >+ + 2 OK <3 SELECT {5} >+ * 1 EXISTS >3 OK <4 UID SEARCH ALL >* SEARCH 1 >4 OK <5 UID FETCH 1 BODY[] >* 1 UID FETCH (BODY[] {5} >Test.) >5 OK <6 UID STORE 1 +FLAGS.SILENT (\Deleted) >7 OK -- unexpected data: 7 OK fdm-1.7/regress/test-imap/imap-zero-1.test010064400017500001750000000002441112127570300206700ustar00nicholasnicholas>* OK <1 CAPABILITY >* CAPABILITY IMAP4rev1 >1 OK <2 LOGIN {4} >+ + 2 OK <3 SELECT {5} >+ * 0 EXISTS >3 OK <4 CLOSE >4 OK <5 LOGOUT >5 OK fdm-1.7/regress/test-imap/imap-zero-2.test010064400017500001750000000003761112127570200206760ustar00nicholasnicholas>* OK test test <1 CAPABILITY >* CAPABILITY IMAP4rev1 >1 OK test test <2 LOGIN {4} >+ test test + test test 2 OK test test <3 SELECT {5} >+ test test * 0 EXISTS >3 OK test test <4 CLOSE >4 OK test test <5 LOGOUT >5 OK test test fdm-1.7/regress/test-imap/test-imap.sh010064400017500001750000000024651112127570200201730ustar00nicholasnicholas#!/bin/sh # $Id: test-imap.sh,v 1.1 2007/10/11 09:14:10 nicm Exp $ [ -z "$FDM" ] && exit 1 TEST=$1 FIFO=$TEST.fifo TYPE=imap cat <$TEST.conf set lock-file "$TEST.lock" account 'account' $TYPE pipe "cat $FIFO.in & cat >$FIFO.out" user "test" pass "test" match all action drop EOF rm -f $FIFO.in $FIFO.out mkfifo $FIFO.in $FIFO.out || exit 1 $FDM -mvvvv -f $TEST.conf f >$TEST.log 2>&1 & PID=$! cat $FIFO.out |& hold() { while kill -0 $! 2>/dev/null; do perl -e 'select(undef,undef,undef,0.01)' done } quit() { rm -f $FIFO.in $FIFO.out $TEST.conf [ "$DEBUG" = "" ] && rm -f $TEST.log if [ $1 -ne 1 ]; then echo "$TEST: PASSED" else echo "$TEST: FAILED" fi exit $1 } awk '/^\>/ { print substr($0, 2) }' $TEST >$FIFO.in || exit 1 awk '/^\/dev/null || quit 1 grep "^account: fetching error. aborted" $TEST.log >/dev/null || quit 1 quit 2 done if [ $? -eq 0 ]; then hold grep "^account: [0-9]* messages processed" $TEST.log >/dev/null || quit 1 quit 0 fi fdm-1.7/regress/test-pop3/pop3-apop-1.test010064400017500001750000000001341112127570500205360ustar00nicholasnicholas>+OK POP3 +OK +OK 0 0 +OK fdm-1.7/regress/test-pop3/Makefile010064400017500001750000000005701112227734700173320ustar00nicholasnicholas# $Id: Makefile,v 1.2 2008/12/17 22:36:23 nicm Exp $ CLEANFILES= *~ *.fifo.{in,out} *.log *.conf TESTFILES!= echo pop3-*.test TARGETS= .for n in ${TESTFILES} TARGETS+= ${n} ${n}: @HOME=. FDM="../../fdm -h" sh test-pop3.sh ${n} .endfor .MAIN: all .PHONY: regress clean ${TARGETS} .PRECIOUS: ${TARGETS} all: regress regress: ${TARGETS} clean: rm -f ${CLEANFILES} fdm-1.7/regress/test-pop3/pop3-apop-2.test010064400017500001750000000001121112127570500205330ustar00nicholasnicholas>+OK POP3 +OK +OK +OK 0 0 +OK fdm-1.7/regress/test-pop3/pop3-apop-3.test010064400017500001750000000001121112127570500205340ustar00nicholasnicholas>+OK POP3 test> +OK +OK +OK 0 0 +OK fdm-1.7/regress/test-pop3/pop3-apop-4.test010064400017500001750000000001401112127570500205360ustar00nicholasnicholas>+OK POP3 test +OK +OK 0 0 +OK fdm-1.7/regress/test-pop3/pop3-apop-5.test010064400017500001750000000001721112127570500205440ustar00nicholasnicholas>+OK POP3 -ERR test test test -- unexpected data: -ERR test test test fdm-1.7/regress/test-pop3/pop3-dele-1.test010064400017500001750000000002751112127570500205160ustar00nicholasnicholas>+OK POP3 +OK +OK +OK 1 0 +OK >1 uidl1 >. +OK 1 5 +OK >Test. >. -ERR test test test -- unexpected data: -ERR test test test fdm-1.7/regress/test-pop3/pop3-list-1.test010064400017500001750000000002251112127570400205520ustar00nicholasnicholas>+OK POP3 +OK +OK +OK 1 0 +OK >1 uidl1 >. -ERR test test test -- unexpected data: -ERR test test test fdm-1.7/regress/test-pop3/pop3-list-2.test010064400017500001750000000001751112127570500205600ustar00nicholasnicholas>+OK POP3 +OK +OK +OK 1 0 +OK >1 uidl1 >. +OK 2 0 -- unexpected data: +OK 2 0 fdm-1.7/regress/test-pop3/pop3-one.test010064400017500001750000000002201112127570500202160ustar00nicholasnicholas>+OK POP3 +OK +OK +OK 1 0 +OK >1 uidl1 >. +OK 1 5 +OK >Test. >. +OK +OK fdm-1.7/regress/test-pop3/pop3-pass-1.test010064400017500001750000000001421112127570400205430ustar00nicholasnicholas>+OK POP3 +OK -ERR test test test -- unexpected data: -ERR test test test fdm-1.7/regress/test-pop3/pop3-pass-2.test010064400017500001750000000001231112127570400205430ustar00nicholasnicholas>+OK POP3 +OK +OK test test test +OK 0 0 +OK fdm-1.7/regress/test-pop3/pop3-retr-1.test010064400017500001750000000002461112127570500205570ustar00nicholasnicholas>+OK POP3 +OK +OK +OK 1 0 +OK >1 uidl1 >. +OK 1 5 -ERR test test test -- unexpected data: -ERR test test test fdm-1.7/regress/test-pop3/pop3-retr-2.test010064400017500001750000000002211112127570500205510ustar00nicholasnicholas>+OK POP3 +OK +OK +OK 1 0 +OK >1 uidl1 >. +OK 1 10 +OK >Test. >. +OK +OK fdm-1.7/regress/test-pop3/pop3-retr-3.test010064400017500001750000000002211112127570400205510ustar00nicholasnicholas>+OK POP3 +OK +OK +OK 1 0 +OK >1 uidl1 >. +OK 1 1 +OK >Test. >. +OK +O K fdm-1.7/regress/test-pop3/pop3-retr-4.test010064400017500001750000000002021112127570500205520ustar00nicholasnicholas>+OK POP3 +OK +OK +OK 1 0 +OK >1 uidl1 >. +OK 1 0 +OK >. -- empty message fdm-1.7/regress/test-pop3/pop3-stat-1.test010064400017500001750000000001161112127570500205520ustar00nicholasnicholas>+OK POP3 +OK +OK +OK -- invalid response: +OK fdm-1.7/regress/test-pop3/pop3-stat-2.test010064400017500001750000000001221112127570500205500ustar00nicholasnicholas>+OK POP3 +OK +OK +OK 0 -- invalid response: +OK 0 fdm-1.7/regress/test-pop3/pop3-stat-3.test010064400017500001750000000001231112127570400205510ustar00nicholasnicholas>+OK POP3 +OK +OK +OK 0 0 test test test +OK fdm-1.7/regress/test-pop3/pop3-stat-4.test010064400017500001750000000001551112127570400205570ustar00nicholasnicholas>+OK POP3 +OK +OK -ERR test test test -- unexpected data: -ERR test test test fdm-1.7/regress/test-pop3/pop3-uidl-1.test010064400017500001750000000001741112127570400205370ustar00nicholasnicholas>+OK POP3 +OK +OK +OK 1 0 -ERR test test test -- unexpected data: -ERR test test test fdm-1.7/regress/test-pop3/pop3-uidl-2.test010064400017500001750000000001621112127570500205360ustar00nicholasnicholas>+OK POP3 +OK +OK +OK 1 0 +OK >1 uidl1 >2 uidl2 -- unexpected data: 2 uidl2 fdm-1.7/regress/test-pop3/pop3-uidl-3.test010064400017500001750000000001361112127570400205370ustar00nicholasnicholas>+OK POP3 +OK +OK +OK 1 0 +OK >. -- invalid response: . fdm-1.7/regress/test-pop3/pop3-uidl-4.test010064400017500001750000000001621112127570500205400ustar00nicholasnicholas>+OK POP3 +OK +OK +OK 2 0 +OK >1 uidl1 >3 uidl3 -- unexpected data: 3 uidl3 fdm-1.7/regress/test-pop3/pop3-uidl-5.test010064400017500001750000000001301112127570400205330ustar00nicholasnicholas>+OK POP3 +OK +OK +OK 1 0 +OK >1 >. -- empty UID fdm-1.7/regress/test-pop3/pop3-uidl-6.test010064400017500001750000000001631112127570500205430ustar00nicholasnicholas>+OK POP3 +OK +OK +OK 1 0 +OK # Note two spaces here. >1 >. -- bad UID: fdm-1.7/regress/test-pop3/pop3-uidl-7.test010064400017500001750000000001561112127570500205460ustar00nicholasnicholas>+OK POP3 +OK +OK +OK 2 0 +OK >1 uidl1 >2 uidl1 -- UID collision: uidl1 fdm-1.7/regress/test-pop3/pop3-uidl-8.test010064400017500001750000000003411112127570500205430ustar00nicholasnicholas>+OK POP3 +OK +OK +OK 1 0 +OK # 70 characters. >1 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx >. +OK 1 5 +OK >Test. >. +OK +OK fdm-1.7/regress/test-pop3/pop3-uidl-9.test010064400017500001750000000003701112127570500205460ustar00nicholasnicholas>+OK POP3 +OK +OK +OK 1 0 +OK # 71 characters. >1 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -- UID too big: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx fdm-1.7/regress/test-pop3/pop3-user-1.test010064400017500001750000000001221112127570400205510ustar00nicholasnicholas>+OK POP3 -ERR test test test -- unexpected data: -ERR test test test fdm-1.7/regress/test-pop3/pop3-user-2.test010064400017500001750000000001231112127570500205540ustar00nicholasnicholas>+OK POP3 +OK test test test +OK +OK 0 0 +OK fdm-1.7/regress/test-pop3/pop3-zero.test010064400017500001750000000001041112127570500204150ustar00nicholasnicholas>+OK POP3 +OK +OK +OK 0 0 +OK fdm-1.7/regress/test-pop3/test-pop3.sh010064400017500001750000000024651112127570400200630ustar00nicholasnicholas#!/bin/sh # $Id: test-pop3.sh,v 1.3 2007/10/10 22:31:24 nicm Exp $ [ -z "$FDM" ] && exit 1 TEST=$1 FIFO=$TEST.fifo TYPE=pop3 cat <$TEST.conf set lock-file "$TEST.lock" account 'account' $TYPE pipe "cat $FIFO.in & cat >$FIFO.out" user "test" pass "test" match all action drop EOF rm -f $FIFO.in $FIFO.out mkfifo $FIFO.in $FIFO.out || exit 1 $FDM -mvvvv -f $TEST.conf f >$TEST.log 2>&1 & PID=$! cat $FIFO.out |& hold() { while kill -0 $! 2>/dev/null; do perl -e 'select(undef,undef,undef,0.01)' done } quit() { rm -f $FIFO.in $FIFO.out $TEST.conf [ "$DEBUG" = "" ] && rm -f $TEST.log if [ $1 -ne 1 ]; then echo "$TEST: PASSED" else echo "$TEST: FAILED" fi exit $1 } awk '/^\>/ { print substr($0, 2) }' $TEST >$FIFO.in || exit 1 awk '/^\/dev/null || quit 1 grep "^account: fetching error. aborted" $TEST.log >/dev/null || quit 1 quit 2 done if [ $? -eq 0 ]; then hold grep "^account: [0-9]* messages processed" $TEST.log >/dev/null || quit 1 quit 0 fi fdm-1.7/regress/tests/test-add-header1.sh010064400017500001750000000003671112127570700205470ustar00nicholasnicholas#!/bin/sh # $Id: test-add-header1.sh,v 1.1 2007/08/30 21:46:33 nicm Exp $ . ./test.subr && test_init cat <$TEST.in } test_out() { cat >$TEST.out } test_run() { ( echo "set lock-file \"$TEST.lock\"" echo "account \"test\" stdin" cat echo "match all action write \"$TEST.data\"" ) >$TEST.conf chmod 600 $TEST.conf FLAGS=-q if [ "$DEBUG" != "" ]; then FLAGS=-vvv fi cat $TEST.in|$FDM $FLAGS -f $TEST.conf f || exit 1 diff -u $TEST.out $TEST.data RESULT=$? if [ $RESULT -eq 0 ]; then echo "$0: PASSED" else echo "$0: FAILED" fi if [ "$DEBUG" == "" ]; then rm -f $TEST.in $TEST.out $TEST.conf $TEST.data fi exit $RESULT } fdm-1.7/regress/account.test010064400017500001750000000210771112127570500163710ustar00nicholasnicholas# $Id: account.test,v 1.8 2008/04/01 21:02:23 nicm Exp $ account "" @1 ^/dev/stdin: syntax error at line .$ # ---------------------------------------------------------------------------- # STDIN account "" stdin @1 ^/dev/stdin: invalid account name at line .$ account "name" stdin @0 ^added account "name": fetch=stdin$ # ---------------------------------------------------------------------------- # POP3 account "name" pop3 @1 ^/dev/stdin: syntax error at line .$ account "name" pop3 server @1 ^/dev/stdin: syntax error at line .$ account "name" pop3 server "server" @1 ^/dev/stdin: ./.netrc: No such file or directory at line .$ account "name" pop3 server "server" user "user" @1 ^/dev/stdin: ./.netrc: No such file or directory at line .$ account pop3 server "server" user "user" pass "pass" @1 ^/dev/stdin: syntax error at line .$ account "name" pop3 "server" user "user" pass "pass" @1 ^/dev/stdin: syntax error at line .$ account "name" pop3 server user "user" pass "pass" @1 ^/dev/stdin: syntax error at line .$ account "name" pop3 server "server" "user" pass "pass" @1 ^/dev/stdin: syntax error at line .$ account "name" pop3 server "server" user pass "pass" @1 ^/dev/stdin: syntax error at line .$ account "name" pop3 server "server" user "user" "pass" @1 ^/dev/stdin: syntax error at line .$ account "name" pop3 server "server" user "user" pass @1 ^/dev/stdin: syntax error at line .$ account "name" pop3 server "server" user "user" pass "pass" @0 ^added account "name": fetch=pop3 server "server" port pop3 user "user"$ account "name" pop3s server "server" user "user" pass "pass" @0 ^added account "name": fetch=pop3s server "server" port pop3s user "user"$ account "name" pop3 server "server" port 123 user "user" pass "pass" @0 ^added account "name": fetch=pop3 server "server" port 123 user "user"$ account "name" pop3 server "server" port "port" user "user" pass "pass" @0 ^added account "name": fetch=pop3 server "server" port port user "user"$ account "name" pop3 server "server" port 0 user "user" pass "pass" @1 ^/dev/stdin: invalid port at line .$ account "name" pop3 server "server" port 65536 user "user" pass "pass" @1 ^/dev/stdin: invalid port at line .$ account "name" pop3 server "server" port "" user "user" pass "pass" @1 ^/dev/stdin: invalid port at line .$ account "" pop3 server "server" user "user" pass "pass" @1 ^/dev/stdin: invalid account name at line .$ account "name" pop3 server "" user "user" pass "pass" @1 ^/dev/stdin: invalid host at line .$ account "name" pop3 server "server" user "" pass "pass" @1 ^/dev/stdin: invalid user at line .$ account "name" pop3 server "server" user "user" pass "" @1 ^/dev/stdin: invalid pass at line .$ # ---------------------------------------------------------------------------- # IMAP account "name" imap @1 ^/dev/stdin: syntax error at line .$ account "name" imap server @1 ^/dev/stdin: syntax error at line .$ account "name" imap server "server" @1 ^/dev/stdin: ./.netrc: No such file or directory at line .$ account "name" imap server "server" user "user" @1 ^/dev/stdin: ./.netrc: No such file or directory at line .$ account imap server "server" user "user" pass "pass" @1 ^/dev/stdin: syntax error at line .$ account "name" imap "server" user "user" pass "pass" @1 ^/dev/stdin: syntax error at line .$ account "name" imap server user "user" pass "pass" @1 ^/dev/stdin: syntax error at line .$ account "name" imap server "server" "user" pass "pass" @1 ^/dev/stdin: syntax error at line .$ account "name" imap server "server" user pass "pass" @1 ^/dev/stdin: syntax error at line .$ account "name" imap server "server" user "user" "pass" @1 ^/dev/stdin: syntax error at line .$ account "name" imap server "server" user "user" pass @1 ^/dev/stdin: syntax error at line .$ account "name" imap server "server" user "user" pass "pass" "folder" @1 ^/dev/stdin: syntax error at line .$ account "name" imap server "server" user "user" pass "pass" folder @1 ^/dev/stdin: syntax error at line .$ account "name" imap server "server" user "user" pass "pass" @0 ^added account "name": fetch=imap server "server" port imap user "user" folders "INBOX"$ account "name" imaps server "server" user "user" pass "pass" @0 ^added account "name": fetch=imaps server "server" port imaps user "user" folders "INBOX"$ account "name" imap server "server" user "user" pass "pass" folder "folder" @0 ^added account "name": fetch=imap server "server" port imap user "user" folders "folder"$ account "name" imaps server "server" user "user" pass "pass" folder "folder" @0 ^added account "name": fetch=imaps server "server" port imaps user "user" folders "folder"$ account "name" imap server "server" user "user" pass "pass" folders { "folder1" "folder2" } @0 ^added account "name": fetch=imap server "server" port imap user "user" folders "folder1" "folder2"$ account "name" imaps server "server" user "user" pass "pass" folders { "folder1" "folder2" } @0 ^added account "name": fetch=imaps server "server" port imaps user "user" folders "folder1" "folder2"$ account "name" imap server "server" port 123 user "user" pass "pass" @0 ^added account "name": fetch=imap server "server" port 123 user "user" folders "INBOX"$ account "name" imap server "server" port "port" user "user" pass "pass" @0 ^added account "name": fetch=imap server "server" port port user "user" folders "INBOX"$ account "name" imap server "server" port 0 user "user" pass "pass" @1 ^/dev/stdin: invalid port at line .$ account "name" imap server "server" port 65536 user "user" pass "pass" @1 ^/dev/stdin: invalid port at line .$ account "name" imap server "server" port "" user "user" pass "pass" @1 ^/dev/stdin: invalid port at line .$ account "" imap server "server" user "user" pass "pass" @1 ^/dev/stdin: invalid account name at line .$ account "name" imap server "" user "user" pass "pass" @1 ^/dev/stdin: invalid host at line .$ account "name" imap server "server" user "" pass "pass" @1 ^/dev/stdin: invalid user at line .$ account "name" imap server "server" user "user" pass "" @1 ^/dev/stdin: invalid pass at line .$ # ---------------------------------------------------------------------------- # NNTP account "name" nntp @1 ^/dev/stdin: syntax error at line .$ account "name" nntp server @1 ^/dev/stdin: syntax error at line .$ account "name" nntp server "server" @1 ^/dev/stdin: syntax error at line .$ account "name" nntp server "server" group @1 ^/dev/stdin: syntax error at line .$ account "name" nntp server "server" group { } @1 ^/dev/stdin: syntax error at line .$ account "name" nntp server "server" groups @1 ^/dev/stdin: syntax error at line .$ account "name" nntp server "server" groups "group" @1 ^/dev/stdin: syntax error at line .$ account "name" nntp server "server" groups { } @1 ^/dev/stdin: syntax error at line .$ account "name" nntp server "server" group "group" "cache" @1 ^/dev/stdin: syntax error at line .$ account "name" nntp server "server" groups { "group" } cache @1 ^/dev/stdin: syntax error at line .$ account "name" nntp server "server" port 123 group "group" cache "cache" @0 ^added account "name": fetch=nntp server "server" port 123 groups "group" cache "cache"$ account "name" nntp server "server" port "port" group "group" cache "cache" @0 ^added account "name": fetch=nntp server "server" port port groups "group" cache "cache"$ account "name" nntp server "server" port 0 group "group" cache "cache" @1 ^/dev/stdin: invalid port at line .$ account "name" nntp server "server" port 65536 group "group" cache "cache" @1 ^/dev/stdin: invalid port at line .$ account "name" nntp server "server" port "" group "group" cache "cache" @1 ^/dev/stdin: invalid port at line .$ account "name" nntp server "server" port 123 groups { "group" } cache "cache" @0 ^added account "name": fetch=nntp server "server" port 123 groups "group" cache "cache"$ account "name" nntp server "server" port "port" groups { "group" } cache "cache" @0 ^added account "name": fetch=nntp server "server" port port groups "group" cache "cache"$ account "name" nntp server "server" port 0 groups { "group" } cache "cache" @1 ^/dev/stdin: invalid port at line .$ account "name" nntp server "server" port 65536 groups { "group" } cache "cache" @1 ^/dev/stdin: invalid port at line .$ account "name" nntp server "server" port "" groups { "group" } cache "cache" @1 ^/dev/stdin: invalid port at line .$ account "" nntp server "server" group "group" cache "cache" @1 ^/dev/stdin: invalid account name at line .$ account "name" nntp server "" group "group" cache "cache" @1 ^/dev/stdin: invalid host at line .$ account "name" nntp server "server" group "" cache "cache" @1 ^/dev/stdin: invalid group at line .$ account "name" nntp server "server" group "group" cache "" @1 ^/dev/stdin: invalid cache at line .$ fdm-1.7/regress/Makefile010064400017500001750000000007261112227734700154770ustar00nicholasnicholas# $Id: Makefile,v 1.18 2008/12/17 22:36:23 nicm Exp $ CLEANFILES= *~ TESTFILES!= echo *.test TARGETS= .for n in ${TESTFILES} TARGETS+= ${n} ${n}: @echo ${n}: @HOME=. awk -v CMD="../fdm -hvvvnf /dev/stdin" \ -v DEBUG=${DEBUG} -f test.awk ${n} .endfor .MAIN: all .PHONY: regress clean ${TARGETS} .PRECIOUS: ${TARGETS} all: regress regress: ${TARGETS} cd tests && ${MAKE} cd test-pop3 && ${MAKE} cd test-imap && ${MAKE} clean: rm -f ${CLEANFILES} fdm-1.7/regress/attachment.test010064400017500001750000000026331112127571000170560ustar00nicholasnicholas# $Id: attachment.test,v 1.5 2007/04/06 13:29:33 nicm Exp $ !account "account" stdin !action "action" drop match attachment count < 0 action "action" @0 ^added rule 0: matches=attachment count < 0 actions="action"$ match attachment count > 0 action "action" @0 ^added rule 0: matches=attachment count > 0 actions="action"$ match attachment count == 0 action "action" @0 ^added rule 0: matches=attachment count == 0 actions="action"$ match attachment count != 0 action "action" @0 ^added rule 0: matches=attachment count != 0 actions="action"$ match attachment total-size < 0 action "action" @0 ^added rule 0: matches=attachment total-size < 0 actions="action"$ match attachment total-size > 0 action "action" @0 ^added rule 0: matches=attachment total-size > 0 actions="action"$ match attachment any-size < 0 action "action" @0 ^added rule 0: matches=attachment any-size < 0 actions="action"$ match attachment any-size > 0 action "action" @0 ^added rule 0: matches=attachment any-size > 0 actions="action"$ match attachment any-name "string" action "action" @0 ^added rule 0: matches=attachment any-name "string" actions="action"$ match attachment any-name "" action "action" @1 ^/dev/stdin: invalid string at line .$ match attachment any-type "string" action "action" @0 ^added rule 0: matches=attachment any-type "string" actions="action"$ match attachment any-type "" action "action" @1 ^/dev/stdin: invalid string at line .$ fdm-1.7/regress/macros.test010064400017500001750000000041751112127570600162220ustar00nicholasnicholas# $Id: macros.test,v 1.8 2007/07/30 09:05:19 nicm Exp $ %macro = 0 @0 ^added macro "%macro": 0$ %macro = 9223372036854775808 @1 ^/dev/stdin: number is too large at line .$ %macro = 9223372036854775807 @0 ^added macro "%macro": 9223372036854775807$ $macro = "" @0 ^added macro "\$macro": ""$ $macro = "string" @0 ^added macro "\$macro": "string"$ $macro = "one" $macro = "two" @- ^added macro "\$macro": "one"$ @- ^added macro "\$macro": "two"$ @0 %macro = 1000 %macro = 2000 @- ^added macro "%macro": 1000$ @- ^added macro "%macro": 2000$ @0 # ---------------------------------------------------------------------------- # UNDEFINED account $macro stdin @1 ^/dev/stdin: undefined macro: \$macro at line .$ account %macro stdin @1 ^/dev/stdin: syntax error at line .$ set maximum-size %macro @1 ^/dev/stdin: undefined macro: %macro at line .$ account "${macro}" stdin @1 ^/dev/stdin: invalid account name at line .$ account "a${macro}" stdin @0 ^added account "a": fetch=stdin$ account "${macro}b" stdin @0 ^added account "b": fetch=stdin$ account "a${macro}b" stdin @0 ^added account "ab": fetch=stdin$ account "%{macro}" stdin @1 ^/dev/stdin: invalid account name at line .$ account "a%{macro}" stdin @0 ^added account "a": fetch=stdin$ account "%{macro}b" stdin @0 ^added account "b": fetch=stdin$ account "a%{macro}b" stdin @0 ^added account "ab": fetch=stdin$ # ---------------------------------------------------------------------------- # DEFINED !%macro = 1000 !$macro = "one" account $macro stdin @0 ^added account "one": fetch=stdin$ account %macro stdin @1 ^/dev/stdin: syntax error at line .$ set maximum-size %macro @0 account "${macro}" stdin @0 ^added account "one": fetch=stdin$ account "a${macro}" stdin @0 ^added account "aone": fetch=stdin$ account "${macro}b" stdin @0 ^added account "oneb": fetch=stdin$ account "a${macro}b" stdin @0 ^added account "aoneb": fetch=stdin$ account "%{macro}" stdin @0 ^added account "1000": fetch=stdin$ account "a%{macro}" stdin @0 ^added account "a1000": fetch=stdin$ account "%{macro}b" stdin @0 ^added account "1000b": fetch=stdin$ account "a%{macro}b" stdin @0 ^added account "a1000b": fetch=stdin$ fdm-1.7/regress/nested.test010064400017500001750000000024011112127570600162060ustar00nicholasnicholas# $Id: nested.test,v 1.4 2007/08/30 10:45:06 nicm Exp $ !account "account" stdin !action "action" drop match "abc" { match "def" action "action" } @- ^added rule 0: matches=regexp "abc" in any nested$ @- ^added rule 1: matches=regexp "def" in any actions="action"$ @0 match "abc" accounts { } { match "def" action "action" } @1 ^/dev/stdin: syntax error at line .$ match "abc" and accounts { "account" } { match "def" action "action" } @- ^added rule 0: matches=regexp "abc" in any and account "account" nested$ @- ^added rule 1: matches=regexp "def" in any actions="action"$ @0 match "abc" and account "account" { match "def" action "action" } @- ^added rule 0: matches=regexp "abc" in any and account "account" nested$ @- ^added rule 1: matches=regexp "def" in any actions="action"$ @0 match "abc" { } @0 ^added rule 0: matches=regexp "abc" in any nested$ match "abc" and accounts { } { } @1 ^/dev/stdin: syntax error at line .$ match "abc" and account "account" { } @0 ^added rule 0: matches=regexp "abc" in any and account "account" nested$ match "abc" and accounts { "account" } { } @0 ^added rule 0: matches=regexp "abc" in any and account "account" nested$ match "abc" and account "account" { } @0 ^added rule 0: matches=regexp "abc" in any and account "account" nested$ fdm-1.7/regress/options.test010064400017500001750000000071471112127570600164330ustar00nicholasnicholas# $Id: options.test,v 1.10 2008/10/28 07:01:39 nicm Exp $ set lock-types test @1 ^/dev/stdin: unknown token: test at line .$ set lock-types flock @0 ^locking using: flock $ set lock-types fcntl @0 ^locking using: fcntl $ set lock-types dotlock @0 ^locking using: dotlock $ set lock-types flock fcntl @1 ^/dev/stdin: fcntl and flock locking cannot be used together at line .$ set lock-types dotlock fcntl @0 ^locking using: fcntl dotlock $ set lock-types dotlock flock @0 ^locking using: flock dotlock $ set lock-file "" @0 set lock-file "/tmp/file" @0 set delete-oversized @0 ^options are:.*delete-oversized set allow-multiple @0 ^options are:.*allow-multiple set default-user "0" @0 ^options are:.*default-user="0" set default-user "root" @0 ^options are:.*default-user="root" set command-user "0" @0 ^options are:.*command-user="0" set command-user "root" @0 ^options are:.*command-user="root" set unmatched-mail drop @0 ^options are:.*unmatched-mail=drop set unmatched-mail keep @0 ^options are:.*unmatched-mail=keep set unmatched-mail test @1 ^/dev/stdin: unknown token: test at line .$ set file-umask 777 @0 ^options are:.*file-umask=777 set file-umask 0 @0 ^options are:.*file-umask=000 set file-umask 7777 @1 ^/dev/stdin: invalid umask: 7777 at line .$ set file-umask test @1 ^/dev/stdin: unknown token: test at line .$ set file-group 0 @0 ^options are:.*file-group=0 set file-group "wheel" @0 ^options are:.*file-group=0 set queue-high 0 @1 ^/dev/stdin: zero queue-high at line .$ set queue-high 1 @0 ^options are:.*queue-high=1, queue-low=0 set queue-high 25 @0 ^options are:.*queue-high=25, queue-low=18 set queue-high 49 @0 ^options are:.*queue-high=49, queue-low=36 set queue-high 50 @0 ^options are:.*queue-high=50, queue-low=37 set queue-high 51 @1 ^/dev/stdin: queue-high too big: 51 at line .$ set queue-low 0 @1 ^/dev/stdin: queue-high not specified at line .$ set queue-low 1 @1 ^/dev/stdin: queue-high not specified at line .$ set queue-low 25 @1 ^/dev/stdin: queue-high not specified at line .$ set queue-low 49 @1 ^/dev/stdin: queue-high not specified at line .$ set queue-low 50 @1 ^/dev/stdin: queue-high not specified at line .$ set queue-low 51 @1 ^/dev/stdin: queue-low too big: 51 at line .$ set queue-high 25 set queue-low 0 @0 ^options are:.*queue-high=25, queue-low=0 set queue-high 25 set queue-low 1 @0 ^options are:.*queue-high=25, queue-low=1 set queue-high 25 set queue-low 24 @0 ^options are:.*queue-high=25, queue-low=24 set queue-high 25 set queue-low 25 @1 ^/dev/stdin: queue-low must be smaller than queue-high at line .$ set queue-high 25 set queue-low 26 @1 ^/dev/stdin: queue-low must be smaller than queue-high at line .$ set queue-high 25 set queue-low 49 @1 ^/dev/stdin: queue-low must be smaller than queue-high at line .$ set queue-high 25 set queue-low 50 @1 ^/dev/stdin: queue-low must be smaller than queue-high at line .$ set queue-high 25 set queue-low 51 @1 ^/dev/stdin: queue-low too big: 51 at line .$ set queue-high 0 set queue-low 25 @1 ^/dev/stdin: zero queue-high at line .$ set queue-high 1 set queue-low 25 @1 ^/dev/stdin: queue-low must be smaller than queue-high at line .$ set queue-high 24 set queue-low 25 @1 ^/dev/stdin: queue-low must be smaller than queue-high at line .$ set queue-high 25 set queue-low 25 @1 ^/dev/stdin: queue-low must be smaller than queue-high at line .$ set queue-high 26 set queue-low 25 @0 ^options are:.*queue-high=26, queue-low=25 set queue-high 49 set queue-low 25 @0 ^options are:.*queue-high=49, queue-low=25 set queue-high 50 set queue-low 25 @0 ^options are:.*queue-high=50, queue-low=25 set queue-high 51 set queue-low 25 @1 ^/dev/stdin: queue-high too big: 51 at line .$ fdm-1.7/regress/proxy.test010064400017500001750000001016461112127570400161160ustar00nicholasnicholas# $Id: proxy.test,v 1.2 2007/04/06 13:29:33 nicm Exp $ set proxy "" @1 ^/dev/stdin: invalid proxy at line .$ # ---------------------------------------------------------------------------- set proxy "http" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://my.host/" @0 ^using proxy: HTTP on my.host:http$ set proxy "http://my.host" @0 ^using proxy: HTTP on my.host:http$ set proxy "http://my.host:80/" @0 ^using proxy: HTTP on my.host:80$ set proxy "http://my.host:80" @0 ^using proxy: HTTP on my.host:80$ set proxy "http://my.host:http/" @0 ^using proxy: HTTP on my.host:http$ set proxy "http://my.host:http" @0 ^using proxy: HTTP on my.host:http$ set proxy "http://my.host:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://my.host:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http:///" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://:http/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://:http" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://user@my.host/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://user@my.host" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://user@my.host:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://user@my.host:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://user@my.host:http/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://user@my.host:http" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://user@my.host:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://user@my.host:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://user@/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://user@" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://user@:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://user@:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://user@:http/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://user@:http" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://user@:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://user@:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://@my.host/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://@my.host" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://@my.host:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://@my.host:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://@my.host:http/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://@my.host:http" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://@my.host:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://@my.host:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://@/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://@" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://@:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://@:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://@:http/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://@:http" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://@:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://@:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://user:pass@my.host/" @0 ^using proxy: HTTP on my.host:http$ set proxy "http://user:pass@my.host" @0 ^using proxy: HTTP on my.host:http$ set proxy "http://user:pass@my.host:80/" @0 ^using proxy: HTTP on my.host:80$ set proxy "http://user:pass@my.host:80" @0 ^using proxy: HTTP on my.host:80$ set proxy "http://user:pass@my.host:http/" @0 ^using proxy: HTTP on my.host:http$ set proxy "http://user:pass@my.host:http" @0 ^using proxy: HTTP on my.host:http$ set proxy "http://user:pass@my.host:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://user:pass@my.host:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://user:pass@/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://user:pass@" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://user:pass@:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://user:pass@:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://user:pass@:http/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://user:pass@:http" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://user:pass@:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://user:pass@:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://:pass@my.host/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://:pass@my.host" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://:pass@my.host:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://:pass@my.host:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://:pass@my.host:http/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://:pass@my.host:http" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://:pass@my.host:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://:pass@my.host:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://:pass@/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://:pass@" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://:pass@:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://:pass@:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://:pass@:http/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://:pass@:http" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://:pass@:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://:pass@:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://user:@my.host/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://user:@my.host" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://user:@my.host:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://user:@my.host:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://user:@my.host:http/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://user:@my.host:http" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://user:@my.host:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://user:@my.host:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://user:@/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://user:@" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://user:@:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://user:@:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://user:@:http/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://user:@:http" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://user:@:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://user:@:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://:@my.host/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://:@my.host" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://:@my.host:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://:@my.host:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://:@my.host:http/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://:@my.host:http" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://:@my.host:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://:@my.host:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://:@/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://:@" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://:@:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://:@:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://:@:http/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://:@:http" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://:@:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "http://:@:" @1 ^/dev/stdin: invalid proxy at line .$ # ---------------------------------------------------------------------------- set proxy "https" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://my.host/" @0 ^using proxy: HTTPS on my.host:https$ set proxy "https://my.host" @0 ^using proxy: HTTPS on my.host:https$ set proxy "https://my.host:80/" @0 ^using proxy: HTTPS on my.host:80$ set proxy "https://my.host:80" @0 ^using proxy: HTTPS on my.host:80$ set proxy "https://my.host:https/" @0 ^using proxy: HTTPS on my.host:https$ set proxy "https://my.host:https" @0 ^using proxy: HTTPS on my.host:https$ set proxy "https://my.host:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://my.host:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https:///" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://:https/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://:https" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://user@my.host/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://user@my.host" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://user@my.host:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://user@my.host:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://user@my.host:https/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://user@my.host:https" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://user@my.host:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://user@my.host:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://user@/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://user@" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://user@:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://user@:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://user@:https/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://user@:https" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://user@:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://user@:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://@my.host/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://@my.host" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://@my.host:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://@my.host:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://@my.host:https/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://@my.host:https" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://@my.host:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://@my.host:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://@/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://@" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://@:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://@:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://@:https/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://@:https" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://@:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://@:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://user:pass@my.host/" @0 ^using proxy: HTTPS on my.host:https$ set proxy "https://user:pass@my.host" @0 ^using proxy: HTTPS on my.host:https$ set proxy "https://user:pass@my.host:80/" @0 ^using proxy: HTTPS on my.host:80$ set proxy "https://user:pass@my.host:80" @0 ^using proxy: HTTPS on my.host:80$ set proxy "https://user:pass@my.host:https/" @0 ^using proxy: HTTPS on my.host:https$ set proxy "https://user:pass@my.host:https" @0 ^using proxy: HTTPS on my.host:https$ set proxy "https://user:pass@my.host:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://user:pass@my.host:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://user:pass@/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://user:pass@" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://user:pass@:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://user:pass@:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://user:pass@:https/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://user:pass@:https" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://user:pass@:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://user:pass@:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://:pass@my.host/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://:pass@my.host" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://:pass@my.host:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://:pass@my.host:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://:pass@my.host:https/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://:pass@my.host:https" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://:pass@my.host:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://:pass@my.host:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://:pass@/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://:pass@" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://:pass@:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://:pass@:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://:pass@:https/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://:pass@:https" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://:pass@:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://:pass@:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://user:@my.host/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://user:@my.host" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://user:@my.host:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://user:@my.host:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://user:@my.host:https/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://user:@my.host:https" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://user:@my.host:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://user:@my.host:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://user:@/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://user:@" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://user:@:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://user:@:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://user:@:https/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://user:@:https" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://user:@:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://user:@:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://:@my.host/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://:@my.host" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://:@my.host:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://:@my.host:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://:@my.host:https/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://:@my.host:https" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://:@my.host:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://:@my.host:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://:@/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://:@" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://:@:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://:@:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://:@:https/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://:@:https" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://:@:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "https://:@:" @1 ^/dev/stdin: invalid proxy at line .$ # ---------------------------------------------------------------------------- set proxy "socks" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://my.host/" @0 ^using proxy: SOCKS5 on my.host:socks$ set proxy "socks://my.host" @0 ^using proxy: SOCKS5 on my.host:socks$ set proxy "socks://my.host:80/" @0 ^using proxy: SOCKS5 on my.host:80$ set proxy "socks://my.host:80" @0 ^using proxy: SOCKS5 on my.host:80$ set proxy "socks://my.host:socks/" @0 ^using proxy: SOCKS5 on my.host:socks$ set proxy "socks://my.host:socks" @0 ^using proxy: SOCKS5 on my.host:socks$ set proxy "socks://my.host:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://my.host:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks:///" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://:socks/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://:socks" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://user@my.host/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://user@my.host" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://user@my.host:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://user@my.host:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://user@my.host:socks/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://user@my.host:socks" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://user@my.host:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://user@my.host:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://user@/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://user@" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://user@:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://user@:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://user@:socks/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://user@:socks" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://user@:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://user@:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://@my.host/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://@my.host" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://@my.host:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://@my.host:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://@my.host:socks/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://@my.host:socks" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://@my.host:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://@my.host:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://@/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://@" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://@:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://@:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://@:socks/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://@:socks" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://@:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://@:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://user:pass@my.host/" @0 ^using proxy: SOCKS5 on my.host:socks$ set proxy "socks://user:pass@my.host" @0 ^using proxy: SOCKS5 on my.host:socks$ set proxy "socks://user:pass@my.host:80/" @0 ^using proxy: SOCKS5 on my.host:80$ set proxy "socks://user:pass@my.host:80" @0 ^using proxy: SOCKS5 on my.host:80$ set proxy "socks://user:pass@my.host:socks/" @0 ^using proxy: SOCKS5 on my.host:socks$ set proxy "socks://user:pass@my.host:socks" @0 ^using proxy: SOCKS5 on my.host:socks$ set proxy "socks://user:pass@my.host:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://user:pass@my.host:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://user:pass@/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://user:pass@" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://user:pass@:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://user:pass@:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://user:pass@:socks/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://user:pass@:socks" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://user:pass@:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://user:pass@:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://:pass@my.host/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://:pass@my.host" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://:pass@my.host:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://:pass@my.host:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://:pass@my.host:socks/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://:pass@my.host:socks" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://:pass@my.host:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://:pass@my.host:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://:pass@/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://:pass@" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://:pass@:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://:pass@:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://:pass@:socks/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://:pass@:socks" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://:pass@:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://:pass@:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://user:@my.host/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://user:@my.host" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://user:@my.host:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://user:@my.host:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://user:@my.host:socks/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://user:@my.host:socks" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://user:@my.host:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://user:@my.host:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://user:@/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://user:@" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://user:@:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://user:@:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://user:@:socks/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://user:@:socks" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://user:@:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://user:@:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://:@my.host/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://:@my.host" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://:@my.host:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://:@my.host:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://:@my.host:socks/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://:@my.host:socks" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://:@my.host:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://:@my.host:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://:@/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://:@" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://:@:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://:@:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://:@:socks/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://:@:socks" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://:@:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks://:@:" @1 ^/dev/stdin: invalid proxy at line .$ # ---------------------------------------------------------------------------- set proxy "socks5" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://my.host/" @0 ^using proxy: SOCKS5 on my.host:socks$ set proxy "socks5://my.host" @0 ^using proxy: SOCKS5 on my.host:socks$ set proxy "socks5://my.host:80/" @0 ^using proxy: SOCKS5 on my.host:80$ set proxy "socks5://my.host:80" @0 ^using proxy: SOCKS5 on my.host:80$ set proxy "socks5://my.host:socks/" @0 ^using proxy: SOCKS5 on my.host:socks$ set proxy "socks5://my.host:socks" @0 ^using proxy: SOCKS5 on my.host:socks$ set proxy "socks5://my.host:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://my.host:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5:///" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://:socks/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://:socks" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://user@my.host/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://user@my.host" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://user@my.host:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://user@my.host:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://user@my.host:socks/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://user@my.host:socks" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://user@my.host:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://user@my.host:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://user@/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://user@" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://user@:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://user@:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://user@:socks/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://user@:socks" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://user@:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://user@:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://@my.host/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://@my.host" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://@my.host:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://@my.host:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://@my.host:socks/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://@my.host:socks" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://@my.host:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://@my.host:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://@/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://@" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://@:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://@:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://@:socks/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://@:socks" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://@:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://@:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://user:pass@my.host/" @0 ^using proxy: SOCKS5 on my.host:socks$ set proxy "socks5://user:pass@my.host" @0 ^using proxy: SOCKS5 on my.host:socks$ set proxy "socks5://user:pass@my.host:80/" @0 ^using proxy: SOCKS5 on my.host:80$ set proxy "socks5://user:pass@my.host:80" @0 ^using proxy: SOCKS5 on my.host:80$ set proxy "socks5://user:pass@my.host:socks/" @0 ^using proxy: SOCKS5 on my.host:socks$ set proxy "socks5://user:pass@my.host:socks" @0 ^using proxy: SOCKS5 on my.host:socks$ set proxy "socks5://user:pass@my.host:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://user:pass@my.host:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://user:pass@/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://user:pass@" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://user:pass@:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://user:pass@:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://user:pass@:socks/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://user:pass@:socks" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://user:pass@:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://user:pass@:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://:pass@my.host/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://:pass@my.host" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://:pass@my.host:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://:pass@my.host:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://:pass@my.host:socks/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://:pass@my.host:socks" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://:pass@my.host:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://:pass@my.host:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://:pass@/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://:pass@" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://:pass@:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://:pass@:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://:pass@:socks/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://:pass@:socks" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://:pass@:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://:pass@:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://user:@my.host/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://user:@my.host" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://user:@my.host:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://user:@my.host:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://user:@my.host:socks/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://user:@my.host:socks" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://user:@my.host:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://user:@my.host:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://user:@/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://user:@" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://user:@:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://user:@:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://user:@:socks/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://user:@:socks" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://user:@:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://user:@:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://:@my.host/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://:@my.host" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://:@my.host:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://:@my.host:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://:@my.host:socks/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://:@my.host:socks" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://:@my.host:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://:@my.host:" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://:@/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://:@" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://:@:80/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://:@:80" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://:@:socks/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://:@:socks" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://:@:/" @1 ^/dev/stdin: invalid proxy at line .$ set proxy "socks5://:@:" @1 ^/dev/stdin: invalid proxy at line .$ fdm-1.7/regress/size.test010064400017500001750000000120051112127570400156750ustar00nicholasnicholas# $Id: size.test,v 1.4 2007/06/29 21:28:43 nicm Exp $ set maximum-size 0 @1 ^/dev/stdin: zero maximum size at line .$ set maximum-size 1 @0 ^options are: .*maximum-size=1, set maximum-size 2147483648 @1 ^/dev/stdin: maximum size too large: 2147483648 at line .$ set maximum-size 0b @1 ^/dev/stdin: zero maximum size at line .$ set maximum-size 1b @0 ^options are: .*maximum-size=1, set maximum-size 2147483648b @1 ^/dev/stdin: maximum size too large: 2147483648 at line .$ set maximum-size 0B @1 ^/dev/stdin: zero maximum size at line .$ set maximum-size 1B @0 ^options are: .*maximum-size=1, set maximum-size 2147483648B @1 ^/dev/stdin: maximum size too large: 2147483648 at line .$ set maximum-size 0 bytes @1 ^/dev/stdin: zero maximum size at line .$ set maximum-size 1 bytes @0 ^options are: .*maximum-size=1, set maximum-size 2147483648 bytes @1 ^/dev/stdin: maximum size too large: 2147483648 at line .$ set maximum-size 0 byte @1 ^/dev/stdin: zero maximum size at line .$ set maximum-size 1 byte @0 ^options are: .*maximum-size=1, set maximum-size 2147483648 byte @1 ^/dev/stdin: maximum size too large: 2147483648 at line .$ set maximum-size 0K @1 ^/dev/stdin: zero maximum size at line .$ set maximum-size 1K @0 ^options are: .*maximum-size=1024, set maximum-size 2097152K @1 ^/dev/stdin: maximum size too large: 2147483648 at line .$ set maximum-size 0k @1 ^/dev/stdin: zero maximum size at line .$ set maximum-size 1k @0 ^options are: .*maximum-size=1024, set maximum-size 2097152k @1 ^/dev/stdin: maximum size too large: 2147483648 at line .$ set maximum-size 0 kb @1 ^/dev/stdin: zero maximum size at line .$ set maximum-size 1 kb @0 ^options are: .*maximum-size=1024, set maximum-size 2097152 kb @1 ^/dev/stdin: maximum size too large: 2147483648 at line .$ set maximum-size 0 KB @1 ^/dev/stdin: zero maximum size at line .$ set maximum-size 1 KB @0 ^options are: .*maximum-size=1024, set maximum-size 2097152 KB @1 ^/dev/stdin: maximum size too large: 2147483648 at line .$ set maximum-size 0 kilobytes @1 ^/dev/stdin: zero maximum size at line .$ set maximum-size 1 kilobytes @0 ^options are: .*maximum-size=1024, set maximum-size 2097152 kilobytes @1 ^/dev/stdin: maximum size too large: 2147483648 at line .$ set maximum-size 0 kilobyte @1 ^/dev/stdin: zero maximum size at line .$ set maximum-size 1 kilobyte @0 ^options are: .*maximum-size=1024, set maximum-size 2097152 kilobyte @1 ^/dev/stdin: maximum size too large: 2147483648 at line .$ set maximum-size 0M @1 ^/dev/stdin: zero maximum size at line .$ set maximum-size 1M @0 ^options are: .*maximum-size=1048576, set maximum-size 2048M @1 ^/dev/stdin: maximum size too large: 2147483648 at line .$ set maximum-size 0m @1 ^/dev/stdin: zero maximum size at line .$ set maximum-size 1m @0 ^options are: .*maximum-size=1048576, set maximum-size 2048M @1 ^/dev/stdin: maximum size too large: 2147483648 at line .$ set maximum-size 0 mb @1 ^/dev/stdin: zero maximum size at line .$ set maximum-size 1 mb @0 ^options are: .*maximum-size=1048576, set maximum-size 2048 mb @1 ^/dev/stdin: maximum size too large: 2147483648 at line .$ set maximum-size 0 MB @1 ^/dev/stdin: zero maximum size at line .$ set maximum-size 1 MB @0 ^options are: .*maximum-size=1048576, set maximum-size 2048 MB @1 ^/dev/stdin: maximum size too large: 2147483648 at line .$ set maximum-size 0 megabytes @1 ^/dev/stdin: zero maximum size at line .$ set maximum-size 1 megabytes @0 ^options are: .*maximum-size=1048576, set maximum-size 2048 megabytes @1 ^/dev/stdin: maximum size too large: 2147483648 at line .$ set maximum-size 0 megabyte @1 ^/dev/stdin: zero maximum size at line .$ set maximum-size 1 megabyte @0 ^options are: .*maximum-size=1048576, set maximum-size 2048 megabyte @1 ^/dev/stdin: maximum size too large: 2147483648 at line .$ set maximum-size 0G @1 ^/dev/stdin: zero maximum size at line .$ set maximum-size 1G @0 ^options are: .*maximum-size=1073741824, set maximum-size 2G @1 ^/dev/stdin: maximum size too large: 2147483648 at line .$ set maximum-size 0g @1 ^/dev/stdin: zero maximum size at line .$ set maximum-size 1g @0 ^options are: .*maximum-size=1073741824, set maximum-size 2g @1 ^/dev/stdin: maximum size too large: 2147483648 at line .$ set maximum-size 0 gb @1 ^/dev/stdin: zero maximum size at line .$ set maximum-size 1 gb @0 ^options are: .*maximum-size=1073741824, set maximum-size 2 gb @1 ^/dev/stdin: maximum size too large: 2147483648 at line .$ set maximum-size 0 GB @1 ^/dev/stdin: zero maximum size at line .$ set maximum-size 1 GB @0 ^options are: .*maximum-size=1073741824, set maximum-size 2 GB @1 ^/dev/stdin: maximum size too large: 2147483648 at line .$ set maximum-size 0 gigabytes @1 ^/dev/stdin: zero maximum size at line .$ set maximum-size 1 gigabytes @0 ^options are: .*maximum-size=1073741824, set maximum-size 2 gigabytes @1 ^/dev/stdin: maximum size too large: 2147483648 at line .$ set maximum-size 0 gigabyte @1 ^/dev/stdin: zero maximum size at line .$ set maximum-size 1 gigabyte @0 ^options are: .*maximum-size=1073741824, set maximum-size 2 gigabyte @1 ^/dev/stdin: maximum size too large: 2147483648 at line .$ fdm-1.7/regress/test.awk010064400017500001750000000044531112127570700155200ustar00nicholasnicholas# $Id: test.awk,v 1.8 2006/12/21 10:38:19 nicm Exp $ # # Copyright (c) 2006 Nicholas Marriott # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER # IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING # OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # function failed(cmd) { failures++; print (FILENAME ":" line ": FAILED: " cmd); } function passed(cmd) { print (FILENAME ":" line ": PASSED: " cmd); } BEGIN { failures = 0; line = 0; nlines = 0; nheaders = 0; nmatches = 0; } /.*/ { line++; } /^!.+/ { headers[nheaders] = substr($0, 2); nheaders++; next; } /^[^@!\#].+/ { lines[nlines] = $0; nlines++; next; } /^@- .+/ { matches[nmatches] = substr($0, 4); nmatches++; next; } /^@[0-9]( .*)?/ { rc = int(substr($0, 2, 1)); matches[nmatches] = substr($0, 4); if (matches[nmatches] != 0 && matches[nmatches] != "") { nmatches++; } cmd = "(echo '" for (i = 0; i < nheaders; i++) { cmd = cmd headers[i] "';echo '"; } for (i = 0; i < nlines; i++) { if (i != nlines - 1) { cmd = cmd lines[i] "';echo '"; } else { cmd = cmd lines[i]; } } cmd = cmd "')|" CMD " 2>&1"; for (i = 0; i < nmatches; i++) { found[i] = 0; } do { error = cmd | getline; if (error == -1) { break; } if (DEBUG != "") { print ("\t" $0); } for (i = 0; i < nmatches; i++) { if ($0 ~ matches[i]) { found[i] = 1; } } } while (error == 1); close(cmd); if (error == -1) { failed(cmd); next; } nlines = 0; nfound = 0; for (i = 0; i < nmatches; i++) { if (found[i] == 1) { nfound++; } } if (nfound != nmatches) { nmatches = 0; failed(cmd); next; } nmatches = 0; if (system(cmd " 2>/dev/null") != rc) { failed(cmd); next; } passed(cmd); } END { exit (failures); } fdm-1.7/regress/time.test010064400017500001750000000057341112127570200156720ustar00nicholasnicholas# $Id: time.test,v 1.1 2007/06/29 21:28:43 nicm Exp $ set timeout 0 @1 ^/dev/stdin: zero timeout at line .$ set timeout 1 @0 ^options are: .*timeout=1, set timeout 2147483648 @1 ^/dev/stdin: timeout too long: 2147483648 at line .$ set timeout 0 second @1 ^/dev/stdin: zero timeout at line .$ set timeout 1 second @0 ^options are: .*timeout=1, set timeout 2147483648 second @1 ^/dev/stdin: timeout too long: 2147483648 at line .$ set timeout 0 seconds @1 ^/dev/stdin: zero timeout at line .$ set timeout 1 seconds @0 ^options are: .*timeout=1, set timeout 2147483648 seconds @1 ^/dev/stdin: timeout too long: 2147483648 at line .$ set timeout 0 minute @1 ^/dev/stdin: zero timeout at line .$ set timeout 1 minute @0 ^options are: .*timeout=60, set timeout 357913945 minute @1 ^/dev/stdin: timeout too long: 21474836700 at line .$ set timeout 0 minutes @1 ^/dev/stdin: zero timeout at line .$ set timeout 1 minutes @0 ^options are: .*timeout=60, set timeout 357913945 minutes @1 ^/dev/stdin: timeout too long: 21474836700 at line .$ set timeout 0 hour @1 ^/dev/stdin: zero timeout at line .$ set timeout 1 hour @0 ^options are: .*timeout=3600, set timeout 5965234 hour @1 ^/dev/stdin: timeout too long: 21474842400 at line .$ set timeout 0 hours @1 ^/dev/stdin: zero timeout at line .$ set timeout 1 hours @0 ^options are: .*timeout=3600, set timeout 5965234 hours @1 ^/dev/stdin: timeout too long: 21474842400 at line .$ set timeout 0 day @1 ^/dev/stdin: zero timeout at line .$ set timeout 1 day @0 ^options are: .*timeout=86400, set timeout 24856 day @1 ^/dev/stdin: timeout too long: 2147558400 at line .$ set timeout 0 days @1 ^/dev/stdin: zero timeout at line .$ set timeout 1 days @0 ^options are: .*timeout=86400, set timeout 24856 days @1 ^/dev/stdin: timeout too long: 2147558400 at line .$ set timeout 0 week @1 ^/dev/stdin: zero timeout at line .$ set timeout 1 week @0 ^options are: .*timeout=604800, set timeout 3551 week @1 ^/dev/stdin: timeout too long: 2147644800 at line .$ set timeout 0 weeks @1 ^/dev/stdin: zero timeout at line .$ set timeout 1 weeks @0 ^options are: .*timeout=604800, set timeout 3551 weeks @1 ^/dev/stdin: timeout too long: 2147644800 at line .$ set timeout 0 month @1 ^/dev/stdin: zero timeout at line .$ set timeout 1 month @1 ^/dev/stdin: timeout too long: 2419200 at line .$ set timeout 888 month @1 ^/dev/stdin: timeout too long: 2148249600 at line .$ set timeout 0 months @1 ^/dev/stdin: zero timeout at line .$ set timeout 1 months @1 ^/dev/stdin: timeout too long: 2419200 at line .$ set timeout 888 months @1 ^/dev/stdin: timeout too long: 2148249600 at line .$ set timeout 0 year @1 ^/dev/stdin: zero timeout at line .$ set timeout 1 year @1 ^/dev/stdin: timeout too long: 29030400 at line .$ set timeout 74 year @1 ^/dev/stdin: timeout too long: 2148249600 at line .$ set timeout 0 years @1 ^/dev/stdin: zero timeout at line .$ set timeout 1 years @1 ^/dev/stdin: timeout too long: 29030400 at line .$ set timeout 74 years @1 ^/dev/stdin: timeout too long: 2148249600 at line .$ fdm-1.7/tools/makeindex.awk010064400017500001750000000027431120405306100161610ustar00nicholasnicholas# $Id: makeindex.awk,v 1.1 2009/05/17 18:23:45 nicm Exp $ # # Copyright (c) 2006 Nicholas Marriott # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER # IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING # OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # /%%VERSION%%/ { gsub(/%%VERSION%%/, V); print ($0); next; } /^.*$/ { if ($0 ~ /^%%/) { name = substr($0, 3); while ((getline < name) == 1) { print ($0); } close(name); } else if ($0 ~ /^&&/) { name = substr($0, 3); while ((getline < name) == 1) { gsub("\<", "\\<", $0); gsub("\>", "\\>", $0); if ($0 ~ /^[0-9A-Za-z].+ ==+/) { gsub("==+$", "", $0); print ("

" $0 "

"); getline < name; continue; } if ($0 ~ /^[0-9A-Za-z].+ --+/) { gsub("--+$", "", $0); print ("

" $0 "

"); getline < name; continue; } print ($0); } close(name); } else { print ($0); } } fdm-1.7/tools/dist.mk010064400017500001750000000020651120550250600150050ustar00nicholasnicholas# $Id: dist.mk,v 1.2 2009/05/22 10:58:14 nicm Exp $ VERSION= 1.6 DISTDIR= fdm-${VERSION} DISTFILES= *.[chl] Makefile GNUmakefile configure *.[1-9] fdm-sanitize \ README MANUAL TODO CHANGES \ `find examples compat regress -type f -and ! -path '*CVS*'` dist: manual (./configure && make clean-all) grep '^#FDEBUG=' Makefile grep '^#FDEBUG=' GNUmakefile [ "`(grep '^VERSION' Makefile; grep '^VERSION' GNUmakefile)| \ uniq -u`" = "" ] chmod +x configure tar -zc \ -s '/.*/${DISTDIR}\/\0/' \ -f ${DISTDIR}.tar.gz ${DISTFILES} manual: awk -f tools/makemanual.awk MANUAL.in > MANUAL yannotate: awk -f tools/yannotate.awk parse.y > parse.y.new mv parse.y.new parse.y trim parse.y upload-index.html: update-index.html scp index.html nicm,fdm@web.sf.net:/home/groups/f/fd/fdm/htdoc update-index.html: manual nroff -mdoc fdm.conf.5|m2h -u > fdm.conf.5.html nroff -mdoc fdm.1|m2h -u > fdm.1.html awk -v V=${VERSION} -f tools/makeindex.awk \ index.html.in > index.html rm -f fdm.conf.5.html fdm.1.html fdm-1.7/tools/makemanual.awk010064400017500001750000000025551120405306100163300ustar00nicholasnicholas# $Id: makemanual.awk,v 1.1 2009/05/17 18:23:45 nicm Exp $ # # Copyright (c) 2007 Nicholas Marriott # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER # IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING # OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # BEGIN { c1 = 0; c2 = 0; h1 = 0; h2 = 0; } /^##[^#]/ { c1++; c2 = 0; print (c1 substr($0, 3)); next; } /^%%[^%]/ { c2++; print (c1 "." c2 substr($0, 3)); next; } /^\*\*\*/ { s = substr($0, 5) " "; while (length(s) < 80) { s = s "="; } print (s); next; } /^###/ { h1++; h2 = 0; s = h1 substr($0, 4) " "; while (length(s) < 80) { s = s "="; } print (s); next; } /^%%%/ { h2++; s = h1 "." h2 substr($0, 4) " "; while (length(s) < 80) { s = s "-"; } print (s); next; } /^.*$/ { print ($0); } fdm-1.7/tools/yannotate.awk010064400017500001750000000063641120405306100162210ustar00nicholasnicholas# $Id: yannotate.awk,v 1.1 2009/05/17 18:23:45 nicm Exp $ # # Copyright (c) 2006 Nicholas Marriott # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER # IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING # OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # # This whole file is pretty crappy and fragile, but it does the job. function convert() { n = 0; delete list; arg = 0; for (i = 2; i <= NF; i++) { arg++; type = rules[$i]; if (type != 0 && types[type] != 0) { list[n] = "[$" arg ": " $i " (" types[type] ")]"; n++; } } return (n); } function pretty(prefix, suffix, n) { s = prefix; column = length(s); for (i = 0; i < n; i++) { if (column + length(list[i]) + length(suffix) + 1 > 79) { column = 0; s = substr(s, 1, length(s) - 1) suffix "\n" prefix; } s = s list[i] " "; column += length(list[i]); } return (substr(s, 1, length(s) - 1) suffix); } function wspace(s, o) { gsub("\t", " ", s); n = match(s, "[^ ]"); n -= o; if (n < 0) n = 0; t = ""; for (i = 0; i < n; i++) { t = t " "; } return (t); } BEGIN { union = 0; name = ""; } /^[ \t]*\/\*\*/ { next; } /^%union/ { print ($0); union = 1; next; } /^%type .+/ { print ($0); if (NF < 3) next; for (i = 3; i <= NF; i++) { rules[$i] = $2; } next; } /^[a-z0-9]+: / { type = rules[substr($1, 1, length($1) - 1)]; if (type != 0) { print ("/** " toupper($1) " " type " (" types[type] ") */"); } else { print ("/** " toupper(substr($1, 1, length($1) - 1)) " */"); } print ($0); elements = convert(); if (elements > 0) { s = "" for (i = 0; i < length($1) - 4; i++) { s = " " s; } print (pretty("/**" s " ", " */", elements)); } next; } /^[ \t]*\| / { print ($0); elements = convert(); if (elements > 0) { s = wspace($0, 4); print (pretty("/**" s " ", " */" s, elements)); } next; } /.*/ { print ($0); if (union == 2) { if (NF == 2 && $1 == "}") { union = 1; name = $NF; if (substr(name, 1, 1) == "*") { type = type " *"; name = substr(name, 2); } name = substr(name, 1, length(name) - 1); types["<" name ">"] = type "... } " name; next; } # Include struct members. #for (i = 1; i <= NF; i++) { # type = type $i " "; #} next; } if (union == 1) { if ($1 == "}") { union = 0; next; } if (NF == 2 && $NF == "{") { type = $(NF - 1) " { "; union = 2; next; } type = "" for (i = 1; i < NF; i++) { type = type $i " "; } type = substr(type, 1, length(type) - 1); name = $NF; if (substr(name, 1, 1) == "*") { type = type " *"; name = substr(name, 2); } name = "<" substr(name, 1, length(name) - 1) ">"; types[name] = type; next; } } fdm-1.7/.cvsignore010064400017500001750000000000711112127572500143530ustar00nicholasnicholasfdm y.tab.c y.tab.h test.conf stress saved rfcs releases fdm-1.7/CHANGES010064400017500001750000000752701210615434400133600ustar00nicholasnicholas07 May 2011 * Add mbox tags for messages fetched from a mbox 01 September 2010 * Detect GMail's XYZZY capability for IMAP and use it to try and workaround some of their broken behaviour (incorrectly reported message sizes). 31 May 2009 * Print a warning on missing maildirs when fetching from them rather than crashing or giving an error. Reported by Frank Terbeck. 17 May 2009 * Introduce a configure script and tidy up build infrastructure. 02 May 2009 * GMail IMAP doesn't correctly set the \Seen flag after UID FETCH BODY[], so explicitly set it with STORE when mail is kept. Reported by Patrice Clement. 30 April 2009 * Properly count mails when polling multiple folders on a single IMAP server, reported by Claudio M. Alessi. 24 March 2009 * Support user and pass on NNTP, requested by Michael Hamann. 08 March 2009 * Escape . properly when delivering to SMTP. 27 December 2008 * Don't be as strict about format at the end of messages when using IMAP - accept additional information as well as FLAGS. Reported by rivo nurges. 22 December 2008 * fdm 1.6 released. 17 December 2008 * Only look at HOME environment variable if -h flag is passed. 28 October 2008 * Alter IMAP fetching code to build a UID list of mails to fetch and then fetch them, rather than iterating through all the mails regardless. 07 September 2008 * Process all privsep messages in parent rather than just the first. Fixes timeouts reported by Frank Terbeck. 08 August 2008 * Sort fetch list for POP3 to preserve server mailbox order, requested by Jeremy C Reed. * Fix bug where current user could overwrite default-user/command-user from configuration file. 26 June 2008 * Lookup using courier-authlib. Build with make -DLOOKUP_COURIER and use "set lookup-order courier passwd". * Framework for changing user lookup method. At the moment only normal Unix passwd (getpwnam(3)) is supported. This means only string usernames are supported - to enter a numeric Unix UID, enclose it in quotes. * Get rid of from-headers which was ugly and unreliable. 30 May 2008 * Make NNTP fetching save the cache file after each mail since some NNTP servers (such as my ISP's) are horrendously unreliable. * Handle 423/430 response from ARTICLE command in NNTP correctly. 26 May 2008 * New option: parallel-accounts. Sets number of accounts to fetch in parallel. 22 May 2008 * deliver-imap fetch method; suggested by Jason Dixon a while ago. 03 April 2008 * Support an extra space on the optional FLAGS response when fetching a mail, fixes problems with CommuniGate Pro, thanks to Anthony Wood. * New flags, no-cram-md5 and no-login, on IMAP accounts to force fdm not to use cram-md5 or login authentication even if the server supports it. From Anthony Wood. 01 April 2008 * Support SIGUSR1 as an alias for SIGINFO, for platforms without SIGINFO. 06 March 2008 * Support multiple folders (folders { "a" "b" }) on IMAP fetching. Requested by Claudio Alessi. 05 March 2008 * Print current progress on SIGINFO. Be careful with this, it is possible there are places where an unhandled EINTR would cause fdm to die. 04 March 2008 * fdm 1.5 released. 10 February 2008 * Consistently use geteuid(). * Correct mail_month/mail_dayofyear tags. 10 January 2008 * Added "from" to smtp action to specify envelope from. Requested by Marco Lopes. 07 January 2008 * Use <>s around envelope addresses when using SMTP. Reported by Marco Lopes. 08 December 2007 * Don't let mbox or maildir fetch code exit and free stuff until all the mail is dealt with (queues are empty). Fixes mbox fetching problems reported by akarinotengoku at gmail.com. 03 December 2007 * Bug fix: restore non-blocking mode properly after constructing SSL connection. This bug prevented SSL over a proxy working. 06 November 2007 * Use +FLAGS.SILENT instead of +FLAGS to mark IMAP mail as deleted, as we don't need the new flags. 03 November 2007 * Exchange sometimes includes a FLAGS update as part of its FETCH response, which made fdm complain. Change to accept it without error. Reported by Leo D'Angelo. * Google IMAP has problems with naked flag lists on STORE commands (which are valid). Change to enclose the flags list in brackets. Reported by Andrew Pantyukhin. 25 October 2007 * New option, no-create, prevents fdm creating missing path components or files when delivering to maildirs or mboxes. * Create entire paths if missing when delivering to maildirs or mboxes. 10 October 2007 * Don't accept "+OK N" as well as "+OK N M" in response to STAT. * New option: command-user. This is the user used to run exec/pipe match conditions if one is not specified. The default is the user who ran fdm (root if running as root). 09 October 2007 * Command line cache manipulation. The following commands are available: fdm cache list [path] List details of cache path or all caches in the configuration file if not specified. fdm cache dump path Dump cache keys in the form "key time" where time is is Unix time (seconds from epoch). This allows to easily sort by time: fdm cache dump ~/my/cache|sort -n +2 Or to print the time in a particular date format: fdm cache dump ~/my/cache|while read i; do set -- $i echo $1 `date -r$2 "+%Y-%m-%d% %H:%M:%S"` done And so on. fdm cache add path key fdm cache remove path key Add a key to or remove a key from a cache. fdm cache clear path Clear an entire cache (remove all the keys). This feature suggested by Thomas@BIC. * Restore regress files to distribution. Requested by Mike Erdely for the OpenBSD port. Note that there is no guarantee regressions tests will run on other operating systems! 02 October 2007 * "remove-from-cache" action. * Rename to-cache to add-to-cache (to-cache remains as a compatibility alias). This is to match the planned remove-from-cache and perhaps other similar. * The account/all deprecated support and warnings are now gone. 01 October 2007 * fdm 1.4 released. 25 September 2007 * For POP3 and IMAP, don't have a separate state for waiting-to-purge. Mail could potentially be dropped (in fact, was very likely to be) while waiting for queues to empty in that state. Instead, loop though the next state which ensures all dropped mail is dealt with before attempting to purge. * When tags are replaced in strings, shell metacharacters are now stripped. This is to permit expressions such as: match "^Subject: (.*)" action tag "subject" value "%1" match all ... action exec "echo %[subject]" Without risk of the subject being, for instance, ";rm -Rf ~". This applies to all tags, even those defined manually or by fdm itself, and happens every time any tag is inserted (so in the above, the subject is in fact stripped twice, once when inserted as %1 and once as %[subject] - the second time to no effect). The list of characters to strip can be altered using the strip-characters option. The default is: set strip-characters "\\<>$%^&*|{}[]\"'`;" Stripping may be completely disabled by setting this string to "" (this will return to the old behaviour), or disabled per-tag by prefixing the tag name with :, for example %[:subject] or %:1. Note that this protection is limited: it does not, for instance, prevent use of ".." if using tags to create paths. Care should always be taken when inserting any data extracted from an incoming mail into a shell command. 24 September 2007 * All regexps (match, string, command) are now case insensitive by default and may be prefixed by "case" to enable case sensitivity. * The match string syntax changes were bloat and are reverted. 19 September 2007 * POP3 over pipe. Same as IMAP. 18 September 2007 * Split POP3 core off into pop3-common.c a la IMAP, in preparation for POP3-over-pipe. * Change POP3 old/new mail to work from a list of mail-to-fetch and only ask for that mail, rather than retrieving and checking every mail UID. 17 September 2007 * Quote IMAP folder name to allow spaces and so on. SF bug 1791056. 05 September 2007 * Don't purge if no mails have been dropped. 03 September 2007 * Options to fetch only new or old mail from POP3 or IMAP accounts. Based on request to mailing list, and ensuing discussion, from patnel972-fdm at yahoo.fr. This introduces two new keywords for accounts: new-only and old-only. For POP3 accounts, a cache file must also be specified (similar to NNTP); this holds the list of UIDs for all the mail present in the account on the last fetch. For IMAP, the server-managed \Seen flag is used. Servers should set this flag once a mail has been read (downloaded). The \Recent flag isn't used because it is unset when any client is told about the mail - even a poll is enough. Examples of syntax are: account pop3 server ... new-only cache "~/my/pop3.cache.file" account imap server ... old-only This is useful for people who like to keep mail on the server to be read using a web interface or suchlike. Note that it is up to the user to make sure their account doesn't get full! fdm does not check this or have any abilities to delete or manage mail that isn't fetched. 02 September 2007 * More changes to io.c/command.c to fix issues on Linux introduced by fixes to IMAP-over-pipe. Hopefully all working now. 31 August 2007 * Rewrote user header searching and address matching to clean up the code and work with multiple headers, also fix some fnmatch problems. 30 August 2007 * Fixed silly bug in replace.c. Using the base rather than data offset for %0-%9 so they pointed at the wrong data if a from line had been trimmed. Found by Jo Fahlke, reported via Frank Terbeck through a Debian bug report. * Move command-line macro parsing into parse.y/parse-fn.c and make it actually work again. Found by Jo Fahlke, reported via Frank Terbeck. * account and all tokens are now normal match conditions. So, you can do useless stuff like: match all and all or all ... AND, more importantly, matching accounts now CHANGES to require an operator and follow the normal left-to-right precedence. So: match all account "a*" ... Becomes: match account "a*" ... And: match "a regexp" or age > 10 accounts { "acc1" acc2" } ... Becomes: match accounts { "acc1" "acc2 " } and "a regexp" or age > 10 ... fdm 1.4 will emit a warning and convert the old style into the new style, but in 1.5 the warning will become an error, and in 1.6 the old code will be removed entirely. So update your rulesets! Note that due to limitations in yacc, the line number of the rule in the warning may be off by a few lines (usually one line too far). 25 August 2007 * Break timer stuff off into timer.c. * Fix queue-high == 1 to not hang after first mail. 24 August 2007 * Don't even try to check for command child exit until its std{in,out,err} are closed. Hopefully fixes problems seen on Linux by Frank Terbeck. * Be more consistent about lists when parsing configuration file. * Don't try to strip duplicates from any lists instead of trying for some of them and not others. * remove-header now accepts a list of headers in {}. 23 August 2007 * Yet another fetch reorganisation to try to make it clearer. Move tracking completed mail into fetch code, move mail and state stuff outside, and simplify the API and data structures. Also change the way the fetch poll loop works and fix some potential problems with IMAP-over-pipe. Hopefully few regressions... This loses the IMAP multiple delete combining but that isn't a huge loss. 18 August 2007 * Tidy up io code a little, break some big functions and split headers stuff into dedicated io.h. Also lift fd limit. * Make SMTP delivery work again (blank lines were failing a length check in buffer_add from io_write). SF bug 1776786. 16 August 2007 * Remove header action now allows fnmatch patterns. * Fix a silly bug with removing headers. * Clarify headers/body again. The body offset is now the first byte of the body, so a mail of a single blank line has size == body == 1 (so, body size == 0 rather than 1). "\nBody" always had body == 1 and not having "\n" the same was confusing me. 15 August 2007 * A few POP3 servers supply an APOP cookie and then refuse the APOP command. Handle them with a "no-apop" flag to POP3 account statements to disable APOP. Reported by Frank Terbeck. 10 August 2007 * Combine append into write and exec into pipe even more to get rid of deliver-append.c and deliver-exec.c. * add-from on stdout delivery is gone, an acceptable from line can be prepended using rewrite. 06 August 2007 * TDB is now a mandatory dependency. 03 August 2007 * Fetching from mboxes. 02 August 2007 * Handle IMAP mails properly if they have no trailing newline. * Use APOP for POP3 or CRAM-MD5 for IMAP if offered by server. Note that fdm currently does NOT fall back to plaintext auth if the server offers APOP or CRAM-MD5 but it doesn't work. 01 August 2007 * fdm 1.3c released. * Wrong size for match buffer in pcre.c. SF.net bug 1765524. * Try to buffer as much as possible when reading, this prevents problems since SSL_read seems to buffer data itself which poll can't know about. * Fix a bug with SSL where a "don't stop" error (want read/want write) would make fdm think there was data received when there wasn't, resulting in spurious new lines and fetching being aborted. This somehow failed to show up in the two months since 1.1 was released. Reported by Steven Mestdagh. 31 July 2007 * Accept only ".\r\n" as terminator for POP3 and NNTP, not a '.' followed by anything except '.'. * Don't include a leading space in the POP3 UID. 30 July 2007 * fdm 1.3a and 1.3b released. * Change to using setitimer for SSL_connect timeout. OpenBSD, and possibly others, limit SO_RCVTIMEO to 327 seconds. Also try smaller timeouts if setting the first one fails, to a minimum of 30 seconds. Reported by Steven Mestdagh. * fdm 1.3 released. 25 July 2007 * Tidied and refactored much of file.c and deliver-{mbox,maildir}.c. * Brought back fatal and fatalx as #defines which prepend __func__ and pass through to log_fatal/log_fatalx. 24 July 2007 * Embedding an undefined macro in a string with ${} is no longer an error, it is just treated as empty. This makes ifdef/endif more useful. 17 July 2007 * Only store shared filename (NAME_MAX) in struct shm and construct path into temp dir on-the-fly. Saves (PATH_MAX - NAME_MAX) per struct. * Trailing newlines are now stripped from message_id tag (as they used to be). This makes any existing caches by message-id useless. * Use SO_RCVTIMEO to apply configured timeout when connecting to SSL servers (SSL_connect must block as it is the easiest way to ensure the certificate is received before checking its validity). 16 July 2007 * Outright reject configuration files that use caches unless built with -DDB, rather than waiting until the cache is used. * Rewrite the malloc debugging stuff: lose the call counting, use a splay tree instead of a fixed array and use __builtin_return_address and direct calls from xmalloc.c rather than horrible #define games, even if it means the ultimate output is less useful. 15 July 2007 * Permit each account to start multiple delivery child processes simultaneously (up to the maximum queue length). This doesn't help much in normal cases but with particularly lengthy but non-CPU-intensive delivery actions (try exec "sleep 1" ;-P), it can help a lot. * Introduce some randomness into the lock sleep delay when waiting for mboxes. 14 July 2007 * Use mremap(2) on Linux. 13 July 2007 * Fix stupid bug (grr) in strb.c which caused a segfault if realloc moved the buffer when it was being expanded; also clean up macros a bit when here. 11 July 2007 * Add %[mail_rfc822date] which contains the mail date and time (or current date and time if invalid) in RFC822 format and %[rfc822date] which is the same for the current date/time. I probably need to stop adding tags now $() works. * Additional example from Giorgio Lando (examples/g-lando.conf). * Add two-digit year (year2/mail_year2) and hostname tags. * Simplify fetching: line counting and body detection is now done globally for all fetch types in the mail queuing code, as is checking for empty and oversize mails. * There is now no concept of a body-less mail (m->body == -1). Mails with no separating blank line are assumed to be entirely body (m->body == 0), otherwise the body is the first byte after the separator. * Fix a long-standing bug in openlock (mail.c): if open(2) failed, the lock file was not removed. * NNTPS fetching, suggested by Maximilian Gass. * After rethinking, remove some useless fclose error checks. 08 July 2007 * Check permissions on include files as well as main configuration file. * First new parser bug: include files should be subject to tag replacement, noticed by Frank Terbeck. 05 July 2007 * Move to rewritten log.c which which makes the syslog/stderr hacks I had made to the old version less fugly. 02 July 2007 * If a mail has no body, insert new headers at the start instead of the end. This matches formail's behaviour. Requested by Giorgio Lando. Note there is no change to the regexp "in body" behaviour, although perhaps there should be. * Sort out the localtime(3)/strftime(3) mess by actually reading the man page and time.h. This means July is now the seventh rather than sixth month. Reported by Giorgio Lando. 29 June 2007 * Split parse helper functions out into parse-fn.c and do lots of other cleanup of parse.y and lex.c. * New lexer makes ifdef/ifndef/endif possible, although not completely elegant. Syntax is: ifdef $macro .... endif. Note that stuff inside ifdefs must still be valid syntax! * Scrap use of lex in favour of custom C lexer. This allows (yet another) workaround for include files, to make stuff like this work: $host = $(hostname) include "file.${host}" * Combine multiple IMAP deletions together into one command where possible, although I doubt it makes any actual difference. 28 June 2007 * Shell commands may now be called when parsing the ruleset using $() and %() operators: %year = %(date +%y) $arch = $(uname -m) These are executed at parse time. Sections between the brackets within "s are subject to escape and macro replacement as normal; parts outside quotes or inside 's are not. For example: $SHELL = "test" $cmd = $(echo "${SHELL} $SHELL \${SHELL}") Takes advantage of the fact that fdm requires {}s and the shell does not to yield: added macro "$cmd": "test /bin/ksh /bin/ksh" As with macros, commands may be used at any point a string or number is appropriate. * The mail time tags (mail_year, mail_quarter, etc) now use underscores in their names rather than dashes, for consistency. * Deliver append-string is no more, it is trivially replaced using rewrite. * Built-in cache using TDB (http://sourceforge.net/projects/tdb/). Currently disabled by default, enabled by building with make -DDB. Used as followed; # Declare the cache. $db = "~/.fdm.db" cache $db expire 2 weeks match not string "%[message_id]" to "" { # Filter messages already in the cache. match in-cache $db key "%[message_id]" action mbox "duplicate-mail" # Add message-ids to the cache (any other string can be added # but message-ids are most useful). match all action to-cache $db key "%[message_id]" continue } Note the guard statement - the key can't be empty and news (NNTP) messages don't have a message-id. 27 June 2007 * New tags taken from the date header corresponding to the current time tags: mail_hour, mail_year, etc. If the header is invalid, the current time is used. Request/idea from Maximilian Gass. * Make fdm-sanitize also obfuscate the lengths of login/pass with IMAP. * Bug fix: "and not" rather than "not and" in ruleset -vv output. * "match tag ..." is now completely gone. * "value" keyword is now preferred for add-header action: action "ah" add-header "My-Header" value "ABC" but is not mandatory. * fdm 1.2 released. 08 June 2007 * Check CN against FQDN and user-supplied host when verifying SSL certificates. 21 May 2007 * New layout for most of the fetch code. Now pretty much everything is done using a state machine for each fetch type rather than a mixture of linear code and state machine. Mail is now enqueued/dequeued using callbacks rather than returning status codes. 16 May 2007 * SHM_SYSV is no more. 10 May 2007 * Fix typo in manual and use DESTDIR in *akefile, from Frank Terbeck as a result of Debian package creation. 09 May 2007 * Code tidying in io.c and command.c. 08 May 2007 * Couple of fixes for stupid things in ARRAY_* macros, one of which was hiding a minor bug. Don't know what I was thinking when I wrote them. 04 May 2007 * "match tag ..." is now not supported. * Permit actions to call other actions: action "one" ... action "two" ... action "three" { ... actions { "one" "two" } } A maximum of five levels is permitted, spoiling the fun of: action "x" { action "x" } 30 April 2007 * Optionally verify SSL certificates. This can be turned on with the "verify-certificates" option and disabled per account by appending a "no-verify" flag to the definition. * Option to use PCRE (build with make -DPCRE). 19 April 2007 * Count the number of messages properly when there is no done function (such as for NNTP). 10 April 2007 * Install into bin rather than sbin when using GNUmakefile. From Frank Terbeck. 06 April 2007 * fdm 1.1 released. 04 April 2007 * Set the socket non-blocking in before setting up SSL in connect.c, otherwise SSL_connect might block. 03 April 2007 * Instead of doing complicated things to see if a mmap'd region is okay, just fill it with zeros using write(2). This also avoids FS fragmentation on FreeBSD, per its mmap(2). Also use MAP_NOSYNC. 30 March 2007 * Allow plural and singular to be interchanged in most places, don't insist on "accounts { "abc" }" and "account "abc"". 29 March 2007 * Tags are now done using an action (tag) rather than a special-case match rule. The old way still works but generates a warning which will become an error within a few releases. * Because yacc needs to move back and forwards, just swapping the file out from under it when including can cause problems. So, switch to letting lex do all the work and feed the include file to yacc as if it was inline. This sucks a bit but there aren't many other options. Reported by Frank Terbeck. * Lambda actions: match "regexp" action mbox ... match "regexp" actions { rewrite ... mbox ... } 28 March 2007 * Compound actions, using a list in {}s, eg: action "abc" { rewrite ... mbox ... } * Macros shouldn't be expanded inside single quotes. Fixed. * + may be used to concatenate strings. * Allow short-circuit evaluation of 'and' and 'or' operators. 27 March 2007 * Accept size with either CRLF or LF as when warning about bad size predictions from POP3 servers. Google gives the size with LF and then sends the mail data (as it must do) with CRLF. 26 March 2007 * Fix stupid use of struct strings for uid_ts and make users be printed when printing rules, actions, accounts. * Option to use SYSV shared memory (build with make -DSHM_SYSV). Not a real option, or documented, yet because I'm not sure how to deal with cleaning up on SIGTERM. It might even go away again. * Play some games to ensure that that the full extent of the mmap'd temporary file is actually writable before using it. Otherwise if there is insufficient disk space we risk getting an unexpected SIGBUS later when trying to use it. * When sending delivery done messages, check that the child process isn't dead before trying to talk to it. 25 March 2007 * Handle unlink(2)/fclose(3) failures, led to discovery of a missing fflush before fsync and a double-unlink of a tmp file (bad!), also fixed. Part of bug 1687830 from Markus Elfring. Also fix some closedir(3) return value checks. I'm still on the fence about close(2). SUSv3 says that it can only die on EBADF, EINTR and EIO: the first will cause problems before close, and I don't see how the latter can affect anything given that write(2) (or fsync(2) when applicable) will have previously returned success (fdm already checks their return). OTOH, it would be both tidy and future-proof to check it. 22 March 2007 * Return total number of mails from start function if possible and print "X of Y" when reporting mail fetches with -v. 21 March 2007 * queue-low and queue-high options. Default queue limit is 2. * Default maximum-size now 32 MB and maximum now 1 GB. 20 March 2007 * -q option to quiet unnecessary chatter. * If user/pass is not specified on IMAP or POP3 accounts, attempt to read it from the ~/.netrc file. * Redo child fetch stuff so that exec/pipe matches actually works * Stop exec/pipe matches early if only checking for regexp and it is found. * Sprinkle a few fsyncs, and block SIGTERM while writing to mboxes. 18 March 2007 * Informational messages now go to stdout rather than stderr. 16 March 2007 * Change so that the child uses poll(2) on all the fds rather than letting the fetch-* stuff poll and periodically checking the parent fd. * Make delivery children be handled in the main loop (fdm.c) along with the fetch children. This means that different accounts will not block each other when delivering. I tried allowing multiple simultaneous deliveries for each account but it doesn't work very well, particularly regarding errors. 15 March 2007 * Seriously reduce -v output in favour of -vv and -vvv. * Save mail in a queue as it is fetched and perform matching/delivery on it while waiting for the server to send the next mail. This can give a 20-50% speed increase with some rulesets, particularly with slow POP3 servers. 13 March 2007 * Don't pass stdin to poll(3) instead of closed sockets. Fixes problems with rewrite and empty mails on Linux. Reported & tested by Frank Terbeck. 12 March 2007 * The timeout setting is now used for commands too. * Expand leading ~s into home directories where appropriate. * Section headings are now numbered in MANUAL. 11 March 2007 * You can't use a va_list twice even when it's passed in as an argument. Duh. Fixes segfaults on PPC. Reported by Daniel Wilmer. 08 March 2007 * Try to introduce some consistency into tag replacement in strings. Introduce a new type (struct replstr) which indicates a string that should be replaced before use, and try to make sure replacement happens possibly for all strings where replacement should happen on parse. Hopefully this will make it easier to handle replacement properly in future too. 07 March 2007 * Handle POLLHUP properly in io.c: if it is set and POLLIN isn't set, the fd has closed. This makes stdin delivery work properly on Linux 2.4. 06 March 2007 * Submatches with commands are now added as tags command0 to command9. * pipe actions now use the command.c framework, which means their stderr is logged and stdout discarded. * mail_file tag added by maildir delivery and mbox_file by mbox. Also pass the tags block up and down between parent and child so these tags actually stick. * A new exec action, similar to pipe but stdin is /dev/null. This is useful in combination with the mail_file and mbox_file tags. 04 March 2007 * Bug fix: fill in the correct size for maildir fetched mail rather than using the rounded-up size and adding a ton of nulls. * -D on the command line overrides macro definitions in the configuration file. * Build the attachment list when the first attachment match rule is found rather than for every mail regardless. * Add a message_id tag to each mail. 03 March 2007 * add-header action and lines, body_lines, header_lines tags for IMAP/POP3, suggested by Frank Terbeck. * Linux dirname(3)/basename(3) screws up the buffer. Fixed it thanks to Frank Terbeck. * Fixed bugs in string parsing thanks to Frank Terbeck. 02 March 2007 * Made add_tag use varargs and added a server_uid tag to POP3/IMAP messages. * Added infrastructure to maintain a cache of variable-length strings within a single contiguous block of data (strb.c), so it can be passed easily up to the parent process. Use this for storing mail tags to get rid of the arbitrary tag length limits. 28 February 2007 * Man page cleanups, from Tamas TEVESZ. 27 February 2007 * fdm 1.0 released. 22 February 2007 * Fixed silly typo in NNTP code check. SF bug 1650701. * Included account name in received header. * Added stdout delivery. * New append-string delivery to add data to a mail. 19 February 2007 * Added a remove-header action to remove all instances of a header. Based on a a request by Tobias Ulmer. 09 February 2007 * Reworked the substitution stuff. Each mail now carries a list of tag name, value pairs, some of which are autogenerated (account, action, etc) and others which may be added by the user. They may be inserted in strings using %[name]. The autogenerated tags are aliased to the old single letter tokens. Based on a question from AJ Weber. * Added a timeout option to limit the time for which servers are waited. 08 February 2007 * Added file-umask and file-group options to control permissions and group ownership of created mboxes and maildirs. Altered the permissions checks to take this into account, and extended them to maildirs. Suggestion from AJ Weber. * Made mbox/maildir creation clearer in documentation. 07 February 2007 * Added -D command line option to define a macro. 05 February 2007 * Made options be printed with -v. 27 January 2007 * Fixed attachment parsing so that it works as intended. 26 January 2007 * Started a changelog. * Assigned a number to each rule and changed logging to refer to it. Also tweaked the -vv configuration file output. * Changed some vasprintf to xvasprintf now that the latter exists. * Fixed command.c to trim CR line end if present, this makes IMAP over ssh work. (0.9a) * Fixed miscalculation of length in find_header. (0.9a) * Fixed find_header to locate the first rather than second instance. * Added FQDN and what it resolves to to the domains list by default. * Added a basic Received header with local host and fdm version, may be disabled with the new set no-received option. * Free mmap'd region before mmap'ing it again in shm_realloc, otherwise the actual disk space isn't freed. This affected previous versions too but the mail was very rarely reallocated, now that the header is added it is. * Changed all the descriptions to static buffers and audited use of snprintf. $Id: CHANGES,v 1.214 2011/05/08 20:51:02 nicm Exp $ LocalWords: Terbeck authlib DLOOKUP ISP's Alessi dayofyear Lopes gmail STAT LocalWords: akarinotengoku D'Angelo Pantyukhin BIC Erdely Rf patnel Fahlke vv LocalWords: acc std nBody Mestdagh RCVTIMEO fatalx func shm dir DDB strb rfc LocalWords: Lando openlock Gass formail's ids ABC CN SYSV akefile DPCRE abc LocalWords: mmap'd NOSYNC ts DSHM Elfring SUSv netrc vvv va Wilmer replstr AJ LocalWords: TEVESZ Ulmer mmap'ing Exp sanitize fdm-1.7/GNUmakefile010064400017500001750000000032711207563343500144370ustar00nicholasnicholas# $Id: GNUmakefile,v 1.112 2013/01/16 23:26:21 nicm Exp $ .PHONY: clean VERSION= 1.7 FDEBUG= 1 CC?= gcc YACC= yacc -d CFLAGS+= -DBUILD="\"$(VERSION)\"" LDFLAGS+= -L/usr/local/lib LIBS+= -lssl -lcrypto -ltdb -lz # This sort of sucks but gets rid of the stupid warning and should work on # most platforms... ifeq ($(shell (LC_ALL=C $(CC) -v 2>&1|awk '/gcc version 4/') || true), ) CPPFLAGS:= -I. -I- $(CPPFLAGS) else CPPFLAGS:= -iquote. $(CPPFLAGS) endif ifdef FDEBUG LDFLAGS+= -rdynamic CFLAGS+= -g -ggdb -DDEBUG LIBS+= -ldl CFLAGS+= -Wno-long-long -Wall -W -Wnested-externs -Wformat=2 CFLAGS+= -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations CFLAGS+= -Wwrite-strings -Wshadow -Wpointer-arith -Wsign-compare CFLAGS+= -Wundef -Wbad-function-cast -Winline -Wcast-align endif ifdef COURIER CFLAGS+= -DLOOKUP_COURIER LIBS+= -lcourierauth endif ifdef PCRE CFLAGS+= -DPCRE LIBS+= -lpcre endif PREFIX?= /usr/local BINDIR?= $(PREFIX)/bin MANDIR?= $(PREFIX)/man INSTALLDIR= install -d INSTALLBIN= install -m 755 INSTALLMAN= install -m 644 SRCS= $(shell echo *.c|sed 's|y.tab.c||g'; echo y.tab.c) include config.mk OBJS= $(patsubst %.c,%.o,$(SRCS)) all: fdm lex.o: y.tab.c y.tab.c: parse.y $(YACC) $< fdm: $(OBJS) $(CC) $(LDFLAGS) -o fdm $+ $(LIBS) depend: $(SRCS) $(CC) $(CPPFLAGS) -MM $(SRCS) > .depend clean: rm -f fdm *.o .depend *~ *.core *.log compat/*.o y.tab.[ch] clean-all: clean rm -f config.h config.mk install: all $(INSTALLDIR) $(DESTDIR)$(BINDIR) $(INSTALLBIN) fdm $(DESTDIR)$(BINDIR) $(INSTALLDIR) $(DESTDIR)$(MANDIR)/man1 $(INSTALLMAN) fdm.1 $(DESTDIR)$(MANDIR)/man1 $(INSTALLDIR) $(DESTDIR)$(MANDIR)/man5 $(INSTALLMAN) fdm.conf.5 $(DESTDIR)$(MANDIR)/man5 fdm-1.7/child-deliver.c010064400017500001750000000142141163412665100152400ustar00nicholasnicholas/* $Id: child-deliver.c,v 1.22 2009/05/25 21:39:42 nicm Exp $ */ /* * Copyright (c) 2006 Nicholas Marriott * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include "fdm.h" #include "match.h" int child_deliver(struct child *, struct io *); int child_deliver(struct child *child, struct io *pio) { struct child_deliver_data *data = child->data; struct account *a = data->account; struct mail *m = data->mail; struct msg msg; struct msgbuf msgbuf; int error = 0; #ifdef DEBUG xmalloc_clear(); COUNTFDS(a->name); #endif log_debug2("%s: deliver started, pid %ld", a->name, (long) getpid()); #ifdef HAVE_SETPROCTITLE setproctitle("%s[%lu]", data->name, (u_long) geteuid()); #endif /* Call the hook. */ memset(&msg, 0, sizeof msg); data->hook(0, a, &msg, data, &msg.data.error); /* Inform parent we're done. */ msg.type = MSG_DONE; msg.id = 0; msgbuf.buf = m->tags; msgbuf.len = STRB_SIZE(m->tags); if (privsep_send(pio, &msg, &msgbuf) != 0) fatalx("privsep_send error"); do { if (privsep_recv(pio, &msg, NULL) != 0) fatalx("privsep_recv error"); } while (msg.type != MSG_EXIT); #ifdef DEBUG COUNTFDS(a->name); xmalloc_report(getpid(), a->name); #endif return (error); } void child_deliver_action_hook(pid_t pid, struct account *a, struct msg *msg, struct child_deliver_data *data, int *result) { struct actitem *ti = data->actitem; struct deliver_ctx *dctx = data->dctx; struct mail *m = data->mail; struct mail *md = &dctx->wr_mail; /* Check if this is the parent. */ if (pid != 0) { /* Use new mail if necessary. */ if (ti->deliver->type != DELIVER_WRBACK) { xfree(dctx); return; } if (*result != DELIVER_SUCCESS) mail_destroy(md); else { mail_close(md); if (mail_receive(m, msg, 0) != 0) { log_warn("parent_deliver: can't receive mail"); *result = DELIVER_FAILURE; } } xfree(dctx); return; } dctx->udata = xmalloc(sizeof *dctx->udata); dctx->udata->uid = data->uid; dctx->udata->gid = data->gid; dctx->udata->name = xstrdup(find_tag(m->tags, "user")); dctx->udata->home = xstrdup(find_tag(m->tags, "home")); log_debug2("%s: deliver user is: %s (%lu/%lu), home is: %s", a->name, dctx->udata->name, (u_long) dctx->udata->uid, (u_long) dctx->udata->gid, dctx->udata->home); /* This is the child. do the delivery. */ *result = ti->deliver->deliver(dctx, ti); if (ti->deliver->type != DELIVER_WRBACK || *result != DELIVER_SUCCESS) { user_free(dctx->udata); return; } user_free(dctx->udata); mail_send(md, msg); log_debug2("%s: using new mail, size %zu", a->name, md->size); } void child_deliver_cmd_hook(pid_t pid, struct account *a, unused struct msg *msg, struct child_deliver_data *data, int *result) { struct mail_ctx *mctx = data->mctx; struct mail *m = data->mail; struct match_command_data *cmddata = data->cmddata; int flags, status, found = 0; char *s, *cause, *lbuf, *out, *err, tag[24]; size_t llen; struct cmd *cmd = NULL; struct rmlist rml; u_int i; /* If this is the parent, do nothing. */ if (pid != 0) { xfree(mctx); return; } /* Sort out the command. */ s = replacepath( &cmddata->cmd, m->tags, m, &m->rml, find_tag(m->tags, "home")); if (s == NULL || *s == '\0') { log_warnx("%s: empty command", a->name); goto error; } log_debug2("%s: %s: started (ret=%d re=%s)", a->name, s, cmddata->ret, cmddata->re.str == NULL ? "none" : cmddata->re.str); flags = CMD_ONCE; if (cmddata->pipe) flags |= CMD_IN; if (cmddata->re.str != NULL) flags |= CMD_OUT; cmd = cmd_start(s, flags, m->data, m->size, &cause); if (cmd == NULL) { log_warnx("%s: %s: %s", a->name, s, cause); goto error; } llen = IO_LINESIZE; lbuf = xmalloc(llen); for (;;) { /* Stop early if looking for regexp only. */ if (found && cmddata->ret == -1) { log_debug3("%s: %s: found. stopping early", a->name, s); status = 1; break; } status = cmd_poll( cmd, &out, &err, &lbuf, &llen, conf.timeout, &cause); if (status == -1) { log_warnx("%s: %s: %s", a->name, s, cause); goto error; } if (status != 0) break; if (err != NULL) log_warnx("%s: %s: %s", a->name, s, err); if (out == NULL) continue; log_debug3("%s: %s: out: %s", a->name, s, out); if (found) continue; found = re_string(&cmddata->re, out, &rml, &cause); if (found == -1) { log_warnx("%s: %s", a->name, cause); goto error; } if (found != 1) continue; /* Save the matches. */ if (!rml.valid) continue; for (i = 0; i < NPMATCH; i++) { if (!rml.list[i].valid) break; xsnprintf(tag, sizeof tag, "command%u", i); add_tag(&m->tags, tag, "%.*s", (int) (rml.list[i].eo - rml.list[i].so), out + rml.list[i].so); } } status--; log_debug2("%s: %s: returned %d, found %d", a->name, s, status, found); cmd_free(cmd); xfree(s); xfree(lbuf); status = cmddata->ret == status; if (cmddata->ret != -1 && cmddata->re.str != NULL) *result = (found && status) ? MATCH_TRUE : MATCH_FALSE; else if (cmddata->ret != -1 && cmddata->re.str == NULL) *result = status ? MATCH_TRUE : MATCH_FALSE; else if (cmddata->ret == -1 && cmddata->re.str != NULL) *result = found ? MATCH_TRUE : MATCH_FALSE; else *result = MATCH_ERROR; return; error: if (cause != NULL) xfree(cause); if (cmd != NULL) cmd_free(cmd); if (s != NULL) xfree(s); if (lbuf != NULL) xfree(lbuf); *result = MATCH_ERROR; } fdm-1.7/MANUAL.in010064400017500001750000001614361161771127000136750ustar00nicholasnicholasfdm ============================================================================ *** Introduction fdm is a program to fetch mail and deliver it in various ways depending on a user-supplied ruleset. Mail may be fetched from stdin, IMAP or POP3 servers, or from local maildirs, and filtered based on whether it matches a regexp, its size or age, or the output of a shell command. It can be rewritten by an external process, dropped, left on the server or delivered into maildirs, mboxes, to a file or pipe, or any combination. fdm is designed to be lightweight but powerful, with a compact but clear configuration syntax. It is primarily designed for single-user uses but may also be configured to deliver mail in a multi-user setup. In this case, it uses privilege separation to minimise the amount of code running as the root user. *** Table of contents ## Installation ## Quick start ## The configuration file %% Including other files %% Macros %% Testing macros %% Shell commands ## Invoking fdm %% Temporary files %% Command line arguments %% Running from cron %% The lock file %% Testing and debugging ## Fetching mail %% Mail tags %% POP3 and POP3S %% SSL certificate verification %% The .netrc file %% IMAP and IMAPS %% IMAP or POP3 over a pipe or ssh %% stdin and local mail %% From maildirs and mboxes %% Using NNTP and NNTPS %% New or old mail only ## Defining actions %% Drop and keep %% Maildirs %% Mboxes %% IMAP and IMAPS %% SMTP %% Write, pipe, exec and append %% stdout %% Rewriting mail %% Adding or removing headers %% Tagging %% Compound actions %% Chained actions ## Filtering mail %% Nesting rules %% Lambda actions %% The all condition %% Matched and unmatched %% Matching by account %% Matching a regexp %% Matching bracket expressions %% Matching by age or size %% Using a shell command %% Attachments %% Matching tags %% Using caches %% Cache commands ## Setting options ## Archiving and searching mail ## Using fdm behind a proxy ## Bug reports and queries ## Frequently asked questions ### Installation fdm depends on the Trivial Database library (TDB), available at: http://sourceforge.net/projects/tdb/ Ensure it is installed, then download the source tarball and build fdm with: $ tar -zxvf fdm-?.?.tar.gz $ cd fdm-?.? $ ./configure && make Then run 'make install' to install fdm to the default locations under /usr/local. The PREFIX environment variable may be set to specify an alternative installation location: $ export PREFIX=/opt # defaults to /usr/local $ sudo make install If being run as root, fdm requires a user named "_fdm" to exist. It will drop privileges to this user and its primary group. The user may be added on OpenBSD with, for example: # useradd -u 999 -s /bin/nologin -d /var/empty -g=uid _fdm It is not necessary to add a user if fdm is always started by a non-root user. fdm can be built to use PCRE rather than standard regexps. To do so, add -DPCRE to the make command: $ make -DPCRE Or PCRE=1 if using GNU make: $ make PCRE=1 ### Quick start A simple ~/.fdm.conf file for a single user fetching from POP3, POP3S and IMAP accounts and delivering to one maildir may look similar to: # Set the maximum size of mail. set maximum-size 128M # An action to save to the maildir ~/mail/inbox. action "inbox" maildir "%h/mail/inbox" # Accounts: POP3, POP3S and IMAP. Note the double escaping of the '\' # character in the password. If the port is omitted, the default # ("pop3", "pop3s", "imap" or "imaps" in the services(5) db) is used. account "pop3" pop3 server "my.pop3.server" user "my-username" pass "my-password-with-a-\\-in-it" account "pop3s" pop3s server "pop.googlemail.com" port 995 user "my-account@gmail.com" pass "my-password" # If the 'folder "my-folder"' argument is omitted, fdm will fetch mail # from the inbox. account "imap" imap server "my.imap.server" user "my-username" pass "my-password" folder "my-folder" # Discard mail from Bob Idiot. Note that the regexp is an extended # regexp, and case-insensitive by default. This action is a "lambda" or # unnamed action, it is defined inline as part of the match rule. match "^From:.*bob@idiot\\.net" in headers action drop # Match all other mail and deliver using the 'inbox' action. match all action "inbox" A simple initial configuration file without filtering, perhaps to replace fetchmail or getmail delivering to maildrop, may look similar to: # Set the maximum size of mail. set maximum-size 128M # Action to pipe directly to maildrop. action "maildrop" pipe "/usr/local/bin/maildrop" # Account definitions. account .... # Send all mail to maildrop. match all action "maildrop" To run fdm every half hour from cron, add something like this: */30 * * * * /usr/local/bin/fdm -l fetch See the fdm.conf(5) man page or the rest of this manual for more detail of the configuration file format. ### The configuration file fdm is controlled by its configuration file. It first searches for a .fdm.conf file in the invoking user's home directory. If that fails, fdm attempts to use /etc/fdm.conf. The configuration file may also be specified using the '-f' command line option, see the section on that subject below. This section gives an overview of the configuration file syntax. Further details of syntax, and specific keywords, are covered in later sections. The configuration file has the following general rules: - Keywords are specified as unadorned lowercase words: match, action, all. - Strings are enclosed in double quotes (") or single quotes ('). In double quoted strings, double quotes may be included by escaping them using the backslash character (\). Backslashes must also be escaped ("\\") - this applies to all such strings, including regexps and passwords. The special sequence '\t' is replaced by a tab character. In single quoted strings no escaping is necessary, but it is not possible to include a literal ' or a tab character. - Comments are prefixed by the hash character (#) and continue to the end of the line. - Whitespace is largely ignored. Lines may generally be split, concatenated or indented as preferred. - Lists are usually specified as 'singular item' or 'plural { item item }', for example: 'user "nicholas"', 'users { "nicholas" "bob" }'. The singular/plural distinction is not required, it is recommended only to aid readability: 'user { "nicholas "bob" }' is also accepted. - Regexps are specified as normal strings without additional adornment other than the "s (not wrapped in /s). All regexps are extended regexps. They are case insensitive by default but may be prefixed with the 'case' keyword to indicate case sensitivity is required. - Strings may be concatenated using plus: "a" + "b" is the same as "ab". This is most useful to wrap strings across multiple lines. Definition/option lines generally follow the following basic form: Example lines that may appear in a configuration file are: # This is a comment. set lock-types flock account "stdin" disabled stdin action "strip-full-disclosure" rewrite "sed 's/^\\(Subject:.*\\)\\[Full-disclosure\\] /\\1/'" match "^X-Mailing-List:.*linux-kernel@vger.kernel.org" in headers or "^(To:|Cc:):.*@vger.kernel.org" in headers action "linux-kernel" %%% Including other files The fdm configuration may be split into several files. Additional files may be referenced using the 'include' keyword: include "my-include-file.conf" include "/etc/fdm.d/shared-conf-1.conf" %%% Macros Macros may be defined and used in the configuration file. fdm makes a distinction between macros which may hold a number (numeric macros) and those that hold a string (string macros). Numeric macros are prefixed with the percentage sign (%) and string by the dollar sign ($). Macros are defined using the equals operator (=): %nummacro = 123 $strmacro = "a string" Macros may then be referenced in either a standalone fashion anywhere a string or number is expected, depending on the type of macro: $myfile = "a-file" include $myfile %theage = 12 match age < %theage action "old-mail" Or embedded in a string by enclosing the macro name in {}s: $myfile2 = "a-file2" include "/etc/${myfile2}" %anum = 57 include "/etc/file-number-%{anum}" Macros are not substituted in strings specified using single-quotes. %%% Testing macros The 'ifdef', 'ifndef' and 'endif' keywords may be used to include or omit sections of the configuration file depending on whether a macro is defined. An 'ifdef' is followed by a macro name (including $ or % type specifier) and if that macro exists, all following statements up until the next endif are evaluated (accounts created, rules added, and so on), otherwise they are skipped. 'ifndef' is the inverse: if the macro exists, the statements are skipped, otherwise they are included. An example is: ifdef $dropeverything match all action drop endif These keywords are particularly useful in conjunction with the '-D' command line option. Any statements between 'ifdef'/'ifndef' and 'endif' must still be valid syntax. %%% Shell commands The value of a shell command may be used at any point in the configuration file where fdm expects a string or number. Shell commands are invoked by enclosing them in $() or %(). They are executed when the configuration file is parsed and if $() is used, any output to stdout is treated as a literal string (as if the output was inserted directly in the file enclosed in double quotes); %() attempts to convert the output to a number. For example: $mytz = $(date +%Z) %two = %(expr 1 + 1) $astring = "abc" + $(echo def) Parts of the command within double quotes (") are subject to tag and macro replacement as normal (so it is necessary to use %% if a literal % is required, see the section on tags below); parts outside double quotes or inside single quotes are not. ### Invoking fdm fdm accepts a number of command line arguments and may be invoked as needed from the command line or by a mail transfer agent, such as sendmail, or at regular times using a program such as cron(8). %%% Temporary files As each mail is being processed, it is stored in a temporary file in /tmp, or if the TMPDIR environment variable exists in the directory it points to. fdm tries to queue a number of mails simultaneously, so that older can be delivered while waiting for the server to provide the next. The maximum length of the queue for each account is set by the 'queue-high' option (the default is two) and the maximum mail size accepted by the 'maximum-size' option (the default is 32 MB). In addition, the 'rewrite' action requires an additional temporary mail. Although fdm will fail rather than dropping mail if the disk becomes full, users should bear in mind the possibility and set the size of the temporary directory and the fdm options according to their needs. %%% Command line arguments The fdm command has the following synopsis: fdm [-klmnqv] [-f conffile] [-u user] [-a account] [-x account] [-D name=value] [fetch | poll | cache ...] The meaning of the flags are covered in the fdm(1) man page, but a brief description is given below. The flags are also mentioned at relevant points in the rest of this document. Flag Meaning -k Keep all mail (do not delete it from the server). This is useful for testing delivery rules without risking mail ending up permanently in the wrong place. -l Log to syslog(3) using the 'mail' facility rather than outputting to stderr. -m Ignore the lock file. -n Run a syntax check on the configuration file and exit without fetching any mail. -q Quiet mode. Don't print anything except errors. -v Print verbose debugging output. This option may be specified multiple times for increasing levels of verbosity. Useful levels are -vv to display the result of parsing the configuration file, and -vvvv to copy all traffic to and from POP3 or IMAP servers to stdout (note that -l disables this behaviour). -f conffile Specify the path of the configuration file. -u user Use 'user' as the default user for delivering mail when started as root. -a account Process only accounts with a name matching the given pattern. Note that fnmatch(3) wildcards may be used to match multiple accounts with one option, and that the option may be specified multiple times. -x account Process all accounts except those that match the given pattern. Again, fnmatch(3) wildcards may be used, and the -x option may be specified multiple times. -D name=value Define a macro. The macro name must be prefixed with '$' or '%' to indicate if it is a string or numeric macro. Macros defined on the command line override any macros with the same name defined in the configuration file. If -n is not specified, the flags must be followed by one of the keywords 'fetch' or 'poll' or 'cache'. The 'fetch' keyword will fetch and deliver mail, the 'poll' keyword print an indication of how many mails are present in each account, and the 'cache' keyword is followed by one of a set of cache commands used to manipulate caches from the command-line (see the sections on caches below). 'fetch' or 'poll' or 'cache' may be abbreviated. Examples: $ fdm -v poll $ fdm -vvnf /etc/my-fdm.conf $ fdm -lm -a pop3\* fetch $ fdm -x stdinacct fetch # fdm -u nicholas -vv f %%% Running from cron To fetch mail regularly, fdm must be run from cron. This line in a crontab(5) will run fdm every 30 minutes: */30 * * * * /usr/local/bin/fdm -l fetch The '-l' option sends fdm's output to syslog(3) rather than having cron mail it. To keep a closer eye, adding '-v' options and removing '-l' will have debugging output mailed by cron, or, using a line such as: */30 * * * * fdm -vvvv fetch >>/home/user/.fdm.log 2>&1 Will append extremely verbose fdm output to the ~/.fdm.log file. Note that this log file can become pretty large, so another cronjob may be required to remove it occasionally! %%% The lock file fdm makes use of a lock file to prevent two instances running simultaneously. By default, this lock file is .fdm.lock in the home directory of the user who runs fdm, or /var/db/fdm.lock for root. This default may be overridden in the configuration file with the 'set lock-file' command: set lock-file "/path/to/my/lock-file" Or disabled altogether by being set to the empty string: set lock-file "" The '-m' command line option may be used to force fdm to ignore the lock file and run regardless of its existence and without attempting to create it. %%% Testing and debugging fdm has some features to assist with testing and debugging a ruleset: The '-n' command line option. This is particularly useful in conjunction with '-vv', for example: $ cat test.conf account "pop3" pop3 server "s" user "u" pass "p" action "rw" rewrite "sed 's/\\(Subject:.*\\)\\[XYZ\\]/\1/'" action "mbox" mbox "%h/INBOX" match all actions { "rw" "mbox" } $ fdm -vvnf test.conf version is: fdm 0.6 (20061204-1433) starting at: Tue Dec 5 15:45:41 2006 user is: nicholas, home is: /home2/nicholas loading configuration from test.conf added account: name=pop3 fetch=pop3 server "s" port pop3 user "u" added action: name=rw deliver=rewrite "sed 's/\(Subject:.*\)\[XYZ\]/1/'" added action: name=mbox deliver=mbox "%h/INBOX" finished file test.conf added rule: actions="rw" "mbox" matches=all configuration loaded locking using: flock headers are: "to" "cc" domains are: "yelena" using tmp directory: /tmp Looking at the output, the parsed strings used by fdm can be seen, and it is possible to spot that an escape character has been missed in the command. If '-vvvv' is used, fdm will print all data sent to and received from remote servers to stdout. Note that this is disabled if the '-l' option is given, and includes passwords, usernames and hostnames unmodified. The 'fdm-sanitize' script provided with fdm may be used to remove passwords and usernames from this output, either while it is being collected: fdm -vvvv -a testacct f 2>&1|./fdm-sanitize|tee my-output Or afterwards: ./fdm-sanitize my-output Since fdm fetches multiple accounts simultaneously, which may intersperse debugging output, it is recommended to fetch each account seperately if running the output through fdm-sanitize. If this is not done, it may not be able to detect all usernames or passwords. The '-k' command line option (and the 'keep' keywords on actions and accounts, covered later) prevent fdm from deleting any mail after delivery. This may be used to perform any number of test deliveries without risk of losing mail. ### Fetching mail fdm fetches mail from a set of 'accounts', defined using the 'account' keyword. Each account has a name, a type, a number of account specific parameters and a couple of optional flags. The general form is: account [] [disabled] [] [keep] The item is a string by which the account is referred in filtering rules, log output and for the '-a' and '-x' command line options. The portion specifies the default users to use when delivering mail fetched from this account as root. It has the same syntax as discussed in detail in the section below on defining actions. If the optional 'disabled' keyword is present, fdm ignores the account unless it is specified on the command line using the '-a' flag. The optional 'keep' keyword instructs fdm to keep all mail from this account (not delete it from the server) regardless of the result of the filtering rules. The item may be one of: 'pop3', 'pop3s', 'imap', 'imaps', 'stdin', 'maildir' or 'maildirs'. %%% Mail tags As mail is processed by fdm, it is tagged with a number of name/value pairs. Some tags are added automatically, and mail may also be tagged explicitly by the user (see the later tagging section). Tags may be inserted in strings in a similar manner to macros, except tags are processed when the string is used rather than always as the configuration file is parsed. A tag's value is inserted by wrapping its name in %[], for example: match string "%[account]" to "myacct" action "myacctact" Most of the default tags have a single-letter shorthand which removes the needs for the []s: match string "%a" to "myacct" action "myacctact" Including a nonexistent tag in a string is equivalent to including a tag with an empty value, so "abc%[nonexistent]def" will be translated to "abcdef". The automatically added tags are: Name Shorthand Replaced with account %a The name of the account from which the mail was fetched. home %h The delivery user's home directory. uid %n The delivery user's uid. action %t The name of the action the mail has matched. user %u The delivery user's username. hour %H The current hour (00-23). minute %M The current minute (00-59). second %S The current second (00-59). day %d The current day of the month (00-31). month %m The current month (01-12). year %y The current year as four digits. year2 The current year as two digits. dayofweek %W The current day of the week (0-6, Sunday is 0). dayofyear %Y The current day of the year (000-365). quarter %Q The current quarter (1-4). rfc822date The current time in RFC822 date format. mail_hour The hour from the mail's date header, converted to local time, if it exists and is valid, otherwise the current time. mail_minute The minute from the mail's date header. mail_second The second from the mail's date header. mail_day The day from the mail's date header. mail_month The month from the mail's date header. mail_year The year from the mail's date header as four digits. mail_year2 The same as two digits. mail_rfc822date The mail date in RFC822 format. hostname The local hostname. In addition, the shorthand %% is replaced with a literal %, and %1 to %9 are replaced with the result of any bracket expressions in the last regexp (see later section on regexps). A leading ~ or ~user is expanded in strings where a path or command is expected. Some accounts add additional tags, discussed below. Tags are replaced in almost all strings (including those in single-quotes!), some when the configuration file is parsed and some when the string is used. %%% POP3 and POP3S Mail may be fetched from a POP3 account. A POP3 account is defined by specifying the following parameters: the server host and optionally port, and optionally the user name and password. If the port is not specified, the default port ('pop3' in the services(5) database) is used. If the user name, password, or both is omitted, fdm attempts to look it up the .netrc file, see the next section for details. Examples of a POP3 account definition are: account "pop3acct" pop3 server "pop.isp.com" user "bob" pass "pass" account "gmx" pop3 server "pop.gmx.net" port 110 user "jim" pass "pass" account "acct" pop3 server "10.0.0.1" port "pop3" user "nicholas" keep account "lycos" disabled pop3 server $localserver port 10110 pass "password" Note that the server string is enclosed in double quotes even if it is an IP, and don't forget to escape any " and \ characters in passwords! fdm will attempt to use APOP to obscure the password, if the server offers it. If the server advertises itself as supporting APOP but subsequently refuses to accept it, fdm will not retry with a cleartext password. Use of APOP can be disabled for an account using the 'no-apop' flag, for example: account "acct" pop3 server "server" user "bob" pass "pass" no-apop POP3S is specified in exactly the same way, except using the 'pop3s' keyword for the type, and the default port is 'pop3s' rather than 'pop3': account "pop3sacct" pop3s server "pop.isp.com" user "bob" pass "pass" POP3 accounts automatically tag mail with 'server' and 'port' tags, with the value of the server and port attributes exactly as specified in the account definition. A 'server_uid' tag is also added with the server unique id (UIDL). POP3 adds 'lines', 'body_lines' and 'header_lines' tags with the number of lines in the complete mail and its body and header. These tags are not updated to reflect any changes made to the mail by fdm rules. %%% SSL certificate verification fdm can verify SSL certificates before collecting mail from an SSL server. This is enabled globally with the 'verify-certificates' option: set verify-certificates And may be disabled per-account using the 'no-verify' keyword (this applies to both POP3S and IMAPS accounts): account "pop3sacct" pop3s server "pop.isp.com" no-verify For an introduction to SSL, see: http://httpd.apache.org/docs/2.0/ssl/ssl_intro.html A cert bundle is required to verify SSL certificate chains. For more information see: http://lynx.isc.org/current/README.sslcerts A pregenerated bundle is available courtesy of the MirOS project: http://cvs.mirbsd.de/src/etc/ssl.certs.shar %%% The .netrc file If the user name or password is omitted in POP3 or IMAP account definitions, fdm will attempt to look it up in the .netrc file in the invoking user's home directory. The .netrc file format is shared with ftp(1) and some other programs. It consists of a number of 'machine' sections and optionally one 'default' section containing a username ('login') and password for that host. fdm accepts entries only if the machine name matches the POP3 or IMAP server string exactly. If no matches are found and a 'default' section exists, it is used. An example .netrc file is: machine "my.mail-server.com" login "nicholas" password "abcdef" machine "pop.googlemail.com" password "pass1" default login "bob" password "moo" fdm will abort if the .netrc file is world-writable or world-readable. %%% IMAP and IMAPS IMAP and IMAPS accounts are defined using exactly the same syntax as for POP3 and POP3S, aside from using the 'imap' or 'imaps' keywords and that the default port is 'imap' or 'imaps'. There is also an additional, optional 'folders' option to specify the folders from which mail should be fetched. If omitted, fdm defaults to the inbox. Note that with IMAP and IMAPS, mail is still removed from the server unless the 'keep' option is given, or the '-k' command line option used. Examples of IMAP and IMAPS accounts include: account "imapacct" imap server "imap.server.ca" user "bob" pass "pass" account "oldimap" disabled imaps server "192.168.0.1" port 10993 user "nicholas" pass "pass" folders { "Saved" "MyStuff" } account "workspam" disabled imap server "my-work.ath.cx" user "Nicholas" folder "Junk" By default, fdm prefers the CRAM-MD5 authentication method, since no passwords are sent in the clear. If the server does not advertise CRAM-MD5 capability, the older LOGIN method is used. For IMAPS connections (which use SSL), the LOGIN method is just as secure. Either of these methods may be disabled with the 'no-cram-md5' and 'no-login' options. As with POP3, IMAP adds the 'server', 'port', 'server_uid' and the three line count tags to mail. %%% IMAP or POP3 over a pipe or ssh Mail may be fetched using IMAP or POP3 via a pipe. This is particularly useful for fetching mail over ssh using public keys. For IMAP, a user and password may be supplied, but fdm will only use them if the server asks. If the connection is preauthenticated, the user and password are unnecessary. For POP3, a user and password must be supplied as usual: due to the lack of server name, it cannot be read from the .netrc file. Communication takes place via the pipe program's stdin and stdout. If any output is found on stderr, fdm will print it (or log it with '-l'). Examples are: account "imapssh" imap pipe "ssh jim@myhost /usr/local/libexec/imapd" account "imapssh2" imap pipe "/usr/bin/whatever" user "bob" pass "bah" account "pop3local" pop3 pipe "/usr/local/bin/ipop3d" user "me" pass "foo" %%% stdin and local mail fdm may be configured to fetch mail from stdin, by specifying an account of type 'stdin', for example: account "stdin" disabled stdin This is most useful to have fdm behave as a mail delivery agent. To configure it for single-user use with sendmail, the simplest method it to add: "|/usr/local/bin/fdm -m -a stdin fetch" To the user's ~/.forward file (including the double quotes). Note the use of '-m' to prevent stdin delivery from interfering with any normal cronjob, and '-a' to specify that only the disabled "stdin" account should be fetched. stdin accounts add the three line count tags described in the POP3 section. %%% From maildirs and mboxes Fetching from maildirs allows fdm to be used to filter mail on the local machine. This is covered more detail in the later section on archiving and searching. Maildir accounts are specified as follows: account "mymaildir" maildir "/path/to/dir" account "mymaildirs" maildirs { "/path/to/dir1" "/path/to/dir2" } Shell glob wildcards may be included in the path names to match multiple maildirs, but every directory found must be a valid maildir. Maildir accounts tag mail with a 'maildir' tag which is the basename of the maildir. Fetching from mboxes is similar: account "mybox" mbox "/path/to/mbox" account "mymboxes" mboxes { "/path/to/mbox1" "/path/to/mbox2" } Note that if an mbox is modified (mail is dropped from it), sufficient disk space is required to create a temporary copy of the entire mbox. %%% Using NNTP and NNTPS fdm can fetch news messages from a news server using NNTP or NNTPS. News accounts are specified like so: account "news1" nntp server "news.server.sk" port 119 group "comp.unix.bsd.openbsd.misc" cache "%h/.fdm.cache/%[group]" account "mynews" nntps server "ssl.news.server" port "nntps" user "myuser" pass "mypass" groups { "alt.test" "alt.humor.best-of-usenet" } cache "%h/.fdm.cache" The cache is a file used to store details of the last article fetched. If only one group is supplied in the account definition, %[group] tags are replaced by the name of the group in the cache path. If multiple groups are provided, %[group] is removed. Note that whether a message is kept or deleted is irrelevent to NNTP, articles are always left on the server. The index and message-id of the last article is recorded in the cache file so that older articles are skipped when the a newsgroup is again fetched. This happens regardless of any 'keep' keywords or the '-k' command line option. As with POP3 and IMAP, NNTP accounts add the 'server' and 'port' tags to mail. In addition, a 'group' tag is added with the group name. This can ensure articles are matched purely on the group they are fetched from (trying to do this using headers is unreliable with cross-posted articles). For example: match account "news" { match string "%[group]" to "comp.lang.c" action "news-%[group]" match string "%[group]" to "comp.std.c" action "news-%[group]" match all action drop } %%% New or old mail only With POP3 and IMAP, fdm can be set up to fetch only new or old mail. For POP3 this is achieved by recording the current state of the server in a cache file, which is updated as each mail is fetched. For IMAP it makes use of the 'seen' server flag which is updated by the server after each mail is fetched. These options are specified as in the following examples. For POP3: account "name" pop3 server "blah" new-only cache "~/.fdm-pop3-cache" account "acct" pop3s server "my-server" user "bob" new-only cache "my-server-pop3-cache" no-apop And for IMAP: account "imap" imap server "blah" new-only account "sslimap" imaps server "imaps.somewhere" user "user" pass "pass" old-only no-verify Note that currently, when using this with IMAP, the server is permitted to flag the mail as 'seen' before fdm has successfully delivered it, so there is no guarantee that mail so marked has been delivered, only that it has been fetched. ### Defining actions An action is a particular command to execute on a mail when it matches a filtering rule (see the next section on filtering mail). Actions are named, similar to accounts, and have a similar form: action [] The item may be either: - the keyword 'user' followed by a single username string or uid, such as: user "nicholas" user "1000" - the keyword 'users' followed by a list of users in {}s, for example: users { "1001" "nicholas" } If users are specified, the action will be run once for each user, with fdm changing to that user before executing the action. Note that fdm will execute the action once for each user even when not started as root, but will not be able to change to the user. The user keyword is primarily of use in multiuser configurations. If users are present on an action, they override any specified by the account definition. Users are looked up in the Unix passwd file or optionally (if fdm is built with "make -DCOURIER" or "make COURIER=1") using courier-authlib. The order of lookups may be specified with the lookup-order option: set lookup-order courier passwd set lookup-order passwd If running as root and no user is specified on either the action or on the filtering rule (see the section on filtering below), the default user is used, see the '-u' command line option and the 'default-user' option in the setting options section %%% Drop and keep The simplest actions are the 'drop' and 'keep' actions. They have no parameters and are specified like this: action "mydropaction" drop action "mykeepaction" keep The 'drop' action arranges for mail to be dropped when rule evaluation is complete. Note that using 'drop' does not stop further evaluation if the filtering rule contains a 'continue' keyword, and it may be overridden by a 'keep' option on the account or by the '-k' flag on the command line. The 'keep' action is similar to 'drop', but it arranges for the mail to be kept once rule evaluation is complete, rather than dropped. %%% Maildirs Mails may be saved to a maildir through a 'maildir' action, defined like so: action "mymaildiraction" maildir "/path/to/maildir" If any component of the maildir path does not exist, it is created, unless the no-create option is specified. Mails saved to a maildir are tagged with a 'mail_file' tag containing the full path to the file in which they were saved. %%% Mboxes An action to deliver to an mbox is defined in the same way as for a maildir: action "mymboxaction" mbox "/path/to/mbox" The same % tokens are replaced in the path. If the mbox does not exist, it is created. Mboxes may optionally be gzip compressed by adding the 'compress' keyword: action "mymboxaction" mbox "/path/to/mbox" compress fdm will append .gz to the mbox path (if it is not already present) and append compressed data. If the mbox exists but is not already compressed, uncompressed data will be appended. As with maildirs, if any component of the mbox path does not exist, it is created, unless the no-create option is set. Mails saved to an mbox are tagged with an 'mbox_file' tag with the path of the mbox. %%% IMAP and IMAPS An action may be defined to store mail in an IMAP folder. The specification is similar to the IMAP action. A server host and optionally port (default 'imap' or 'imaps') must be specified. A username and password may be supplied; if they are omitted, fdm will attempt to find a .netrc entry. Examples include: action "myimapaction" imap server "imap.server" action "myimapaction" imaps server "imap.server" port "8993" user "user" pass "pass" folder "folder" action "myimapaction" imaps server "imap.server" user "user" pass "pass" no-verify no-login %%% SMTP An action may be defined to pass mail on over SMTP. The server host must be specified and optionally the port and string to pass to the server with the RCPT TO and MAIL FROM commands. If the port is not specified it defaults to "smtp". Examples include: action "mysmtpaction" smtp server "smtp.server" action "mysmtpaction" smtp server "smtp.server" port 587 action "mysmtpaction" smtp server "smtp.server" port "submission" from "bob@server.com" action "mysmtpaction" smtp server "smtp.server" to "me@somewhere" %%% Write, pipe, exec and append Actions may be defined to write or append a mail to a file, to pipe it to a shell command, or merely to execute a shell command. The append action appends to and write overwrites the file. % tokens are replaced in the file or command as for maildir and mbox actions. Examples are: action "mywriteaction" write "/tmp/file" action "myappendaction" append "/tmp/file" action "mypipeaction" pipe "cat > /dev/null" action "domaildirexec" exec "~/.fdm.d/my-special-script %[mail_file]" Pipe and exec commands are run as the command user (by default the user who invoked fdm). %%% stdout fdm can write mails directly to stdout, using the 'stdout' action: action "so" stdout %%% Rewriting mail Mail may be altered by passing it to a rewrite action. This is similar to the pipe action, but the output of the shell command to stdout is reread by fdm and saved as a new mail. This is useful for such things as passing mail through a spam filter or removing or altering headers with sed. Note that rewrite only makes sense on filtering rules where the continue keyword is specified, or where multiple actions are used (see the next section for details of this). Possible rewrite action definitions are: action "myspamaction" rewrite "bmf -p" action "mysedaction" rewrite "sed 's/x/y/'" %%% Adding or removing headers Simple actions are provided to add a header to a mail: action "lines" add-header "Lines" value "%[lines]" Or to remove all instances of a header from mail: action "del-ua" remove-header "user-agent" action "rmhdr" remove-header "x-stupid-header" action "remove-headers" remove-headers { "X-*" "Another-Header" } %%% Tagging Mails may be assigned one of more tags manually using the tag action type. For example, match account "my*" action tag "myaccts" match "^User-Agent:[ \t]*(.*)" action tag "user-agent" value "%1" The tag is attached to the mail with the specified value, or no value if none is provided. %%% Compound actions Compound actions may be defined which perform multiple single actions. They are similar to standard single actions but multiple actions are provided using {}. For example, action "multiple" { add-header "X-My-Header" value "Yay!" mbox "mbox2" } action "myaction" users { "bob" "jim" } { rewrite "rev" maildir "%h/%u's maildir" } Compound action are executed from top-to-bottom, once for each user. Note that the effects are cumulative: the second example above would deliver a mail rewritten once to 'bob' and rewritten again (ie, twice) to 'jim'. If this is not desired, seperate actions must be used. %%% Chained actions An action may call other named actions by reusing the 'action' keyword: action "abc" action "def" action "an_action" { rewrite "rev" action "another_action" action "yet_more_actions" } There is a hard limit of five chained actions in a sequence to prevent infinite loops. ### Filtering mail Mail is filtered by defining a set of filtering rules. These rules tie together mail fetched from an account and passed to one or more actions. Rules are evaluated from top-to-bottom of the file, and evaluation stops at the first matching rule (unless the continue keyword is specified). The general form of a filtering rule is: match [] [continue] The optional item is specified as for an action definition. If users are specified on a filtering (match) rule, they override any specified on the action or account. The item is set of conditions against which the match may be specified, each condition returns true or false. Conditions are described in the next few sections. Aside from the 'all' condition, which is a special case, conditions may be chained as an expression using 'and' and 'or', in which case they are evaluated from left to right at the same precedence, or prepended with 'not' to invert their outcome. The item is a list of actions to execute when this rule matches. It is in the same list format: 'action "name"' or 'actions { "name1" "name2" }'. It may also be a lambda (inline) action, see the section below. If a rule with the 'continue' keyword matches, evaluation does not stop after the actions are executed, instead subsequent rules are matched. %%% Nesting rules Filtering rules may be nested by using the special form: match [] { match ... } If the conditions on the outer rule match, the inner rules are evaluated. If none of the inner rules match (or they all specify the 'continue' keyword) evaluation continues outside to rules following the nested rule, otherwise it stops. %%% Lambda actions Lambda actions are unnamed actions included inline as part of the filtering rule. This can be convenient for actions which do not need to be used multiple times. Lambda actions are specified as a combination of the rule and an action definition. For example: match all action maildir "mymaildir" match all actions { rewrite "rev" tag "reversed" } continue %%% The all condition The all condition matches all mail. Examples include: match all action "default" match all rewrite "rewaction" continue %%% Matched and unmatched The matched and unmatched conditions are used to match mail that has matched or has not matched previous rules and been passed on with the 'continue' keyword. For example, match "myregexp" action "act1" continue # This rule will match only mails that also matched the first. match matched action "act2" # This rule will match only mails that matched neither of the first two. match unmatched action "act3" %%% Matching by account The account condition matches a list of accounts from which the mail was fetched. It is specified as either a single account ('account "name"') or a list of accounts ('accounts { "name1" "name2" }'). fnmatch(3) wildcards may also be used. Examples include: match "blah" accounts { "pop3" "imap" } action "go!" match matched and account "myacc" action drop %%% Matching a regexp Matching against a regexp is the most common form of condition. It takes the following syntax: [case] [in headers|in body] The 'case' keyword instructs fdm to match the regexp case sensitively rather than the default of case insensitivity. The 'in headers' or 'in body' keywords make fdm search only the headers or body of each mail, the default is to match the regexp against the entire mail. Any multiline headers are unwrapped onto a single line before matching takes place and the process reversed afterwards. The regexp itself is an extended regexp specified as a simple string, but care must be taken to escape \s and "s properly. Examples include: match "^From:.*bob@bobland\\.bob" in headers and account "pop3" action "act" match ".*YAHOO.*BOOTER.*" in body action "junk" %%% Matching bracket expressions The results of any bracket expressions within the last regexp match are remembered, and may be made use of using the 'string' condition, or used to construct an action name, maildir or mbox path, etc. The bracket expressions may be substituted using the %0 to %9 tokens. For example, match "^From:.*[ \t]([a-z]*)@domain" in headers action "all" continue match string "%1" to "bob.*" action "bobmail" match "^From:.*[ \t]([a-z]*)@domain" in headers action "all" continue match all action "%1mail" This is particularly useful in combination with nested rules (see later): bracket expressions in a regexp on the outer rule may be compared on inner rules. Note that %0 to %9 are used only for 'regexp' rules. Regexps that are part of 'command' rules use the 'command0' to 'command9' tags. %%% Matching by age or size Mail may be matched based on its age or size. An age condition is specified as follows: age [<|>] [hours|minutes|seconds|days|months|years] If '<' is used, mail is matched if it is younger than the specified age. If '>', if it is older. The item may be a simple number of seconds, or suffixed with a unit. Examples are: match age < 3 months actions { "act1" "act2" } match age > 100 hours action "tooold" The age is extracted from the 'Date' header, if possible. To match mails for which the header was invalid, the following form may be used: match age invalid action "baddate" The size condition is similar: size [<|>] [K|KB|kilobytes...] Where is a simple number in bytes, or suffixed with 'K', 'M' or 'G' to specify a size in kilobytes, megabytes or gigabytes, such as: match size < 1K action "small" match size > 2G action "whoa" %%% Using a shell command Mail may be matched using the result of a shell command. This condition follows the form: [exec|pipe] returns (, [case] ) If 'exec' is used, the command is executed. If 'pipe', the mail is piped to the command's stdin. The is a simple string. % tokens are replaced as normal. Any of the or or both may be specified. The is a simple number which is compared against the return code from the command, the is a regexp that is matched case insensitively against each line output by the command on stdout. The result of any bracket expressions in the stdout regexp are saved as 'command0' to 'command9' tags on the mail. Any output on stderr is logged by fdm, so 2>&1 must be included in the command in order to apply the regexp to it. Examples: match exec "true" (0, ) action "act" match not pipe "grep Bob" (1, ) action "act" match pipe "myprogram" (, "failed") actions { "act1" "act2" } match exec "blah" (12, "^Out") action "meep" %%% Attachments There are five conditions available to filter based on the size, quantity, type and name of attachments. They are all prefixed with the 'attachment' keyword. Two compare the overall number of attachments: The 'attachment count' conditions matches if the number of attachments is equal to, not equal to, less than or greater than the specified number: match attachment count == 0 action "action" match attachment count != 10 action "action" match attachment count < 2 action "action" match attachment count > 7 action "action" The 'attachment total-size' condition is similar, but compares the total size of all the attachments in a mail: match attachment total-size < 4096 kilobytes action "action" match attachment total-size > 1M action "action" There are also three conditions which matches if any individual attachment fulfils the condition: 'any-size' to match if any attachment is less than or greater than the given size, and 'any-type' and 'any-name' which compare the attachment MIME type and name attribute (if any) using fnmatch(3): match attachment any-size < 2K action "action" match attachment any-type "*/pdf" action "action" match attachment any-name "*.doc" action "action" %%% Matching tags The existence of a tag may be tested for using the 'tagged' condition: match tagged "mytag" action "a" match tagged "ohno" and size >1K action drop Or the tags value matched using the 'string' match type (in a similar way to matching bracket expressions): match string "%[group]" to "comp.lang.c" action "clc" match string "%u" to "bob" action "bob" %%% Using caches fdm has builtin support for maintaining a cache of string keys, including appending to a cache, checking if a key is present in a cache, and expiring keys from a cache once they reach a certain age. These caches should not be confused with the NNTP cache file. Key caches are referenced by filename and must be declared before use: cache "%h/path/to/cache" cache "~/.fdm.db" expire 1 month If the expiry time is not specified, items are never expired from the cache. Once declared, keys may be added to the cache with the 'add-to-cache' action: match all action add-to-cache "~/my-cache" key "%[message_id]" Or removed with the 'remove-from-cache' action: match all action remove-from-cache "~/my-cache" key "%[message_id]" And the existence of a key in the cache may be tested for using the 'in-cache' condition: match in-cache "~/my-cache" key "%[message_id]" action "foundincache" Any string may be used as key, but the message-id is most often useful. Note that the key may not be empty, so care must be taken with messages without message-id (such as news posts fetched with NNTP). Caches may be used to elimate duplicate messages using rules similar to those above: $db = "~/.fdm-duplicates.db" $key = "%[message_id]" cache $db expire 2 weeks match not string $key to "" { match in-cache $db key $key action maildir "%h/mail/duplicates" match all action add-to-cache $db key $key continue } %%% Cache commands fdm includes a number of commands to manipulate caches from the command-line. These are invoked with the 'cache' keyword followed by a command. The following commands are supported: cache add cache remove These add or remove as a key in the cache . cache list [] This lists the number of keys in a cache, or in all caches declared in the configuration file if is omitted. cache dump This dumps the contents of the cache to stdout. Each key is printed followed by a space and the timestamp as Unix time. cache clear Delete all keys from a cache. Examples: $ fdm cache list /export/home/nicholas/.fdm.d/duplicates: 4206 keys $ touch my-cache $ fdm cache dump my-cache $ fdm cache add my-cache test $ fdm cache dump my-cache test 1195072403 ### Setting options fdm has a number of options that control its behaviour. These are defined using the set command: set