/* $Id: replace.c,v 1.46 2007/09/25 17:45:38 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 #include "fdm.h" #define ALIAS_IDX(ch) /* LINTED */ \ (((ch) >= 'a' && (ch) <= 'z') ? (ch) - 'a' : \ (((ch) >= 'A' && (ch) <= 'Z') ? 26 + (ch) - 'A' : -1)) static const char *aliases[] = { "account", /* a */ NULL, /* b */ NULL, /* c */ "day", /* d */ NULL, /* e */ NULL, /* f */ NULL, /* g */ "home", /* h */ NULL, /* i */ NULL, /* j */ NULL, /* l */ NULL, /* l */ "month", /* m */ "uid", /* n */ NULL, /* o */ NULL, /* p */ NULL, /* q */ NULL, /* r */ "source", /* s */ "action", /* t */ "user", /* u */ NULL, /* v */ NULL, /* w */ NULL, /* x */ "year", /* y */ NULL, /* z */ NULL, /* A */ NULL, /* B */ NULL, /* C */ NULL, /* D */ NULL, /* E */ NULL, /* F */ NULL, /* G */ "hour", /* H */ NULL, /* I */ NULL, /* J */ NULL, /* K */ NULL, /* L */ "minute", /* M */ NULL, /* N */ NULL, /* O */ NULL, /* P */ "quarter", /* Q */ NULL, /* R */ "second", /* S */ NULL, /* T */ NULL, /* U */ NULL, /* V */ "dayofweek", /* W */ NULL, /* X */ "dayofyear", /* Y */ NULL, /* Z */ }; char *replace(char *, struct strb *, struct mail *, struct rmlist *); const char *submatch(char, struct mail *, struct rmlist *, size_t *); void printflike3 add_tag(struct strb **tags, const char *key, const char *value, ...) { va_list ap; va_start(ap, value); strb_vadd(tags, key, value, ap); va_end(ap); } const char * find_tag(struct strb *tags, const char *key) { struct strbent *sbe; sbe = strb_find(tags, key); if (sbe == NULL) return (NULL); return (STRB_VALUE(tags, sbe)); } const char * match_tag(struct strb *tags, const char *pattern) { struct strbent *sbe; sbe = strb_match(tags, pattern); if (sbe == NULL) return (NULL); return (STRB_VALUE(tags, sbe)); } void default_tags(struct strb **tags, const char *src) { char rtime[128]; struct tm *tm; time_t t; strb_clear(tags); add_tag(tags, "home", "%s", conf.info.home); add_tag(tags, "uid", "%s", conf.info.uid); add_tag(tags, "user", "%s", conf.info.user); if (src != NULL) add_tag(tags, "source", "%s", src); if (conf.info.host != NULL) add_tag(tags, "hostname", "%s", conf.info.host); t = time(NULL); if ((tm = localtime(&t)) != NULL) { /* * Okay, in a struct tm, everything is zero-based (including * month!) except day of the month which is one-based. * * To make thing clearer, strftime(3) measures everything as * you would expect... except that day of the week runs from * 0-6 but day of the year runs from 1-366. * * Fun fun fun. */ add_tag(tags, "hour", "%.2d", tm->tm_hour); add_tag(tags, "minute", "%.2d", tm->tm_min); add_tag(tags, "second", "%.2d", tm->tm_sec); add_tag(tags, "day", "%.2d", tm->tm_mday); add_tag(tags, "month", "%.2d", tm->tm_mon + 1); add_tag(tags, "year", "%.4d", 1900 + tm->tm_year); add_tag(tags, "year2", "%.2d", tm->tm_year % 100); add_tag(tags, "dayofweek", "%d", tm->tm_wday); add_tag(tags, "dayofyear", "%.2d", tm->tm_yday + 1); add_tag(tags, "quarter", "%d", tm->tm_mon / 3 + 1); } if (rfc822time(t, rtime, sizeof rtime) != NULL) add_tag(tags, "rfc822date", "%s", rtime); } void update_tags(struct strb **tags) { add_tag(tags, "home", "%s", conf.info.home); add_tag(tags, "uid", "%s", conf.info.uid); add_tag(tags, "user", "%s", conf.info.user); } char * replacestr(struct replstr *rs, struct strb *tags, struct mail *m, struct rmlist *rml) { return (replace(rs->str, tags, m, rml)); } char * replacepath(struct replpath *rp, struct strb *tags, struct mail *m, struct rmlist *rml) { char *s, *ss; s = replace(rp->str, tags, m, rml); ss = expand_path(s); if (ss == NULL) return (s); xfree(s); return (ss); } const char * submatch(char ch, struct mail *m, struct rmlist *rml, size_t *len) { struct rm *rm; if (rml == NULL || !rml->valid || m == NULL) return (NULL); rm = &rml->list[((u_char) ch) - '0']; if (!rm->valid) return (NULL); *len = rm->eo - rm->so; return (m->data + rm->so); } char * replace(char *src, struct strb *tags, struct mail *m, struct rmlist *rml) { const char *tptr, *alias; char *ptr, *tend, *dst, ch; size_t i, off, len, tlen; int strip; if (src == NULL) return (NULL); if (*src == '\0') return (xstrdup("")); off = 0; len = REPLBUFSIZE; dst = xmalloc(len); strip = 1; for (ptr = src; *ptr != '\0'; ptr++) { switch (*ptr) { case '%': break; default: ENSURE_FOR(dst, len, off, 1); dst[off++] = *ptr; continue; } switch (ch = *++ptr) { case '\0': goto out; case '%': ENSURE_FOR(dst, len, off, 1); dst[off++] = '%'; continue; case '[': if ((tend = strchr(ptr, ']')) == NULL) { ENSURE_FOR(dst, len, off, 2); dst[off++] = '%'; dst[off++] = '['; continue; } ptr++; if (*ptr == ':') { strip = 0; ptr++; } if (ptr == tend) continue; *tend = '\0'; if ((tptr = find_tag(tags, ptr)) == NULL) { *tend = ']'; ptr = tend; continue; } tlen = strlen(tptr); *tend = ']'; ptr = tend; break; case ':': ch = *++ptr; if (ch >= '0' && ch <= '9') { tptr = submatch(ch, m, rml, &tlen); if (tptr == NULL) continue; strip = 0; break; } ENSURE_FOR(dst, len, off, 1); dst[off++] = ch; continue; default: if (ch >= '0' && ch <= '9') { tptr = submatch(ch, m, rml, &tlen); if (tptr == NULL) continue; break; } alias = NULL; if (ALIAS_IDX((u_char) ch) != -1) alias = aliases[ALIAS_IDX((u_char) ch)]; if (alias == NULL) continue; if ((tptr = find_tag(tags, alias)) == NULL) continue; tlen = strlen(tptr); break; } if (tlen == 0) continue; ENSURE_FOR(dst, len, off, tlen); if (!strip) { memcpy(dst + off, tptr, tlen); off += tlen; continue; } for (i = 0; i < tlen; i++) { if (strchr(conf.strip_chars, tptr[i]) == NULL) dst[off++] = tptr[i]; } } out: ENSURE_FOR(dst, len, off, 1); dst[off] = '\0'; return (dst); }