#include #include #include #include #include "extern.h" #include "byte.h" #include "str.h" #include "stralloc.h" #include "fmt.h" #include "open.h" /* * varsub * * Substitute backslash and variable strings in the source string, * returning the string with substitutions. If a variable * substitution fails, the variable name is added to the text. */ /* * Escaping and unescaping of text. Supported sequences are * \r carriage return * \a bell * \n new line * \t tab * \xHH hexidecimal sequence * \d * \dd Octal digits * \ddd */ static int unescape(char *p, int max, char *result) { char ch; int n; if (max <= 0) return 0; ch = *p++; if ((n = byte_chr("rant", 4, ch)) < 4) { *result = "\r\a\n\t"[n]; return 1; } if (ch == 'x' && max > 2 && isxdigit(p[0]) && isxdigit(p[1])) { char hex = 0; ch = *p++; hex = ((ch <= '9' ? (ch - '0') : (ch <= 'F') ? (ch - 'A' + 10) : (ch - 'a' + 10)) << 4); ch = *p++; hex += ((ch <= '9') ? (ch - '0') : (ch <= 'F') ? (ch - 'A' + 10) : (ch - 'a' + 10)); *result = hex; return 3; } if (ch >= '0' && ch <= '7') { char octal = (ch - '0'); for (n = 1; n < 3 && n < max; ++n) { ch = *p++; if (ch < '0' || ch > '7') break; octal <<= 3; octal += (ch - '0'); } *result = octal; return n; } *result = ch; return 1; } static stralloc new, varname; void varsub(stralloc *sa, char **argv) { char *p, *r, **s, delim; int n, cnt; char buf[512], ch; static int seeded; if (!seeded) { srandom(getpid()); seeded = 1; } p = sa->s; cnt = 0; if (!stralloc_copys(&new, "")) nomem(); while (cnt < sa->len) { ch = p[cnt]; ++cnt; if (ch == '$') { delim = 0; n = cnt - 1; if (p[cnt] == '{') { delim = '}'; ++cnt; } if (!stralloc_copys(&varname, "")) nomem(); while (cnt != sa->len) { ch = p[cnt]; if (ch == delim) ++cnt; if (!isalnum(ch)) break; ++cnt; if (!stralloc_append(&varname, &ch)) nomem(); } if (!stralloc_0(&varname)) nomem(); r = NULL; for (s = argv; s && *s; s += 2) if (byte_diff(varname.s, varname.len, *s) == 0) { r = s[1]; break; } if (!r && (!delim || ch == delim) && (r = getenv(varname.s)) == NULL) { *buf = 0; if (byte_diff(varname.s, 3, "ME") == 0) { int fd; char *me = "/var/qmail/control/me"; if (((fd = open_read(me + 11)) >= 0) || ((fd = open_read(me)) >= 0)) { if ((n = read(fd, buf, sizeof(buf) - 1)) > 0) { buf[n] = 0; buf[str_chr(buf, '\n')] = 0; buf[str_chr(buf, '\r')] = 0; } else buf[0] = 0; close(fd); } } else if (byte_diff(varname.s, 4, "PID") == 0) { buf[fmt_uint(buf, getpid())] = 0; } else if (byte_diff(varname.s, 8, "SECONDS") == 0) { buf[fmt_ulong(buf, time(0))] = 0; } else if (byte_diff(varname.s, 7, "RANDOM") == 0) { buf[fmt_ulong(buf, random())] = 0; } else if (byte_diff(varname.s, 5, "DATE") == 0) { struct tm *tm; time_t now; time(&now); if ((r = getenv("DATEFMT")) == NULL) r = "%a, %d %b %Y %H:%M:%S %z"; if ((tm = localtime(&now)) != NULL) if ((n = strftime(buf, sizeof(buf), r, tm)) <= 0) *buf = 0; } r = *buf ? buf : NULL; } if (r) { if (!stralloc_cats(&new, r)) nomem(); } else if (!stralloc_catb(&new, p + n, cnt - n)) nomem(); continue; } if (ch == '\\') cnt += unescape(p + cnt, sa->len - cnt, &ch); if (!stralloc_append(&new, &ch)) nomem(); } if (!stralloc_copyb(sa, new.s, new.len)) nomem(); }