/* This file is part of gacopyz. Copyright (C) 2006, 2007 Sergey Poznyakoff This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include int gacopyz_setpriv (SMFICTX *ctx, void *data) { if (!ctx) return MI_FAILURE; ctx->privdata = data; return MI_SUCCESS; } void * gacopyz_getpriv (SMFICTX *ctx) { if (!ctx) return NULL; return ctx->privdata; } char * gacopyz_getsymval(SMFICTX *ctx, char *name) { int i; int len; if (!ctx || !name) return NULL; if (name[0] == '{') name++; len = strlen(name); if (len == 0) return NULL; if (name[len-1] == '}') len--; for (i = maci_max - 1; i >= 0; i--) { if (ctx->macros[i].argv) { char **p; for (p = ctx->macros[i].argv; *p; p += 2) { if (strlen(*p) == len && memcmp(*p, name, len) == 0) return *++p; } } } return NULL; } static int enhanced_code_p(const char *p) { int count = 0; if (!((*p == '2' || *p == '4' || *p == '5') && p[1] == '.')) return 0; while (*p) { int i; for (i = 0; isascii(*p) && isdigit(*p); i++, p++) { if (i == 3) return 0; } if (*p) { if (*p++ != '.') return 0; } count++; } return count == 3; } static int format_message(char **buf, const char *rcode, const char *xcode, const char *message) { size_t xcodelen, pfxlen, len, numlines, i; const char *p; char *q; pfxlen = strlen(rcode) + 1; if (xcode != NULL) pfxlen += (xcodelen = strlen(xcode)) + 1; numlines = 0; len = 0; for (p = message; *p; p++) { if (*p == '\r') { if (p[1] == '\n') p++; numlines++; } else if (*p == '\n') numlines++; else len++; } if (p > message && p[-1] != '\n') numlines++; len += numlines * (pfxlen + 2); *buf = malloc(len + 1); if (!*buf) return MI_FAILURE; q = *buf; p = message; for (i = 1; i <= numlines; i++) { strcpy(q, rcode); q += 3; if (xcode) { *q++ = (i < numlines) ? '-' : ' '; memcpy(q, xcode, xcodelen); q += xcodelen; *q++ = ' '; } else *q++ = (i < numlines) ? '-' : ' '; while (*p && !(*p == '\r' || *p == '\n')) *q++ = *p++; if (numlines > 1 && i != numlines) { *q++ = '\r'; *q++ = '\n'; } if (*p == '\r') p++; if (*p == '\n') p++; } *q = 0; return MI_SUCCESS; } #define MLBUF_INIT_ALLOC 512 #define MLBUF_INCR_ALLOC 128 int _gacopyz_setmlreply_va(SMFICTX *ctx, size_t max, const char *rcode, const char *xcode, va_list ap) { size_t bufsize = MLBUF_INIT_ALLOC, i, lasti, numlines; char *buf, *p; size_t xcodelen, pfxlen; if (rcode == NULL || ctx == NULL) return MI_FAILURE; if ((rcode[0] != '4' && rcode[0] != '5') || !isascii(rcode[1]) || !isdigit(rcode[1]) || !isascii(rcode[2]) || !isdigit(rcode[2])) return MI_FAILURE; pfxlen = strlen(rcode); if (strlen(rcode) != 3) return MI_FAILURE; if (xcode != NULL) { if (!enhanced_code_p(xcode)) return MI_FAILURE; } else { if (rcode[0] == '4') xcode = "4.0.0"; else xcode = "5.0.0"; } if (xcode != NULL) pfxlen += (xcodelen = strlen(xcode)) + 1; free(ctx->reply); ctx->reply = NULL; buf = malloc(bufsize); if (!buf) return MI_FAILURE; i = 0; lasti = 0; numlines = 0; for (p = va_arg(ap, char*); p && (max == 0 || numlines < max); numlines++) { size_t s = strlen(p) + pfxlen + 2; if (strpbrk(p, "\r\n") != NULL) break; if (i + s > bufsize) { char *newbuf; size_t delta = (i + s - bufsize + MLBUF_INCR_ALLOC) / MLBUF_INCR_ALLOC; bufsize += delta * MLBUF_INCR_ALLOC; newbuf = realloc(buf, bufsize); if (!newbuf) { free(buf); return MI_FAILURE; } buf = newbuf; } strcpy(buf + i, rcode); i += 3; buf[i] = '-'; lasti= i++; memcpy(buf + i, xcode, xcodelen); i += xcodelen; buf[i++] = ' '; strcpy(buf + i, p); i += strlen(p); p = va_arg(ap, char*); if (p) { buf[i++] = '\r'; buf[i++] = '\n'; } } buf[i] = 0; buf[lasti] = ' '; ctx->reply = buf; return MI_SUCCESS; } int gacopyz_setreply(SMFICTX *ctx, const char *rcode, const char *xcode, const char *message) { if (rcode == NULL || ctx == NULL) return MI_FAILURE; if ((rcode[0] != '4' && rcode[0] != '5') || !isascii(rcode[1]) || !isdigit(rcode[1]) || !isascii(rcode[2]) || !isdigit(rcode[2])) return MI_FAILURE; if (strlen(rcode) != 3) return MI_FAILURE; if (xcode != NULL) { if (!enhanced_code_p(xcode)) return MI_FAILURE; } free(ctx->reply); ctx->reply = NULL; return format_message(&ctx->reply, rcode, xcode, message); } int gacopyz_setmlreply_va(SMFICTX *ctx, const char *rcode, const char *xcode, va_list ap) { return _gacopyz_setmlreply_va(ctx, 0, rcode, xcode, ap); return MI_SUCCESS; } int gacopyz_setmlreply_v(SMFICTX *ctx, const char *rcode, const char *xcode, ...) { int rc; va_list ap; va_start(ap, xcode); rc = gacopyz_setmlreply_va(ctx, rcode, xcode, ap); va_end(ap); return MI_SUCCESS; }