smfi.c revision 132943
164562Sgshapiro/* 2132943Sgshapiro * Copyright (c) 1999-2004 Sendmail, Inc. and its suppliers. 364562Sgshapiro * All rights reserved. 464562Sgshapiro * 564562Sgshapiro * By using this file, you agree to the terms and conditions set 664562Sgshapiro * forth in the LICENSE file which can be found at the top level of 764562Sgshapiro * the sendmail distribution. 864562Sgshapiro * 964562Sgshapiro */ 1064562Sgshapiro 1190792Sgshapiro#include <sm/gen.h> 12132943SgshapiroSM_RCSID("@(#)$Id: smfi.c,v 8.72 2004/05/05 00:07:21 msk Exp $") 1390792Sgshapiro#include <sm/varargs.h> 1464562Sgshapiro#include "libmilter.h" 1564562Sgshapiro 16132943Sgshapirostatic int smfi_header __P((SMFICTX *, int, int, char *, char *)); 17132943Sgshapiro 1890792Sgshapiro/* for smfi_set{ml}reply, let's be generous. 256/16 should be sufficient */ 1990792Sgshapiro#define MAXREPLYLEN 980 /* max. length of a reply string */ 2090792Sgshapiro#define MAXREPLIES 32 /* max. number of reply strings */ 2190792Sgshapiro 2264562Sgshapiro/* 23132943Sgshapiro** SMFI_HEADER -- send a header to the MTA 2464562Sgshapiro** 2564562Sgshapiro** Parameters: 2664562Sgshapiro** ctx -- Opaque context structure 27132943Sgshapiro** cmd -- Header modification command 28132943Sgshapiro** hdridx -- Header index 2964562Sgshapiro** headerf -- Header field name 3064562Sgshapiro** headerv -- Header field value 3164562Sgshapiro** 32132943Sgshapiro** 3364562Sgshapiro** Returns: 3464562Sgshapiro** MI_SUCCESS/MI_FAILURE 3564562Sgshapiro*/ 3664562Sgshapiro 37132943Sgshapirostatic int 38132943Sgshapirosmfi_header(ctx, cmd, hdridx, headerf, headerv) 3964562Sgshapiro SMFICTX *ctx; 40132943Sgshapiro int cmd; 41132943Sgshapiro int hdridx; 4264562Sgshapiro char *headerf; 4364562Sgshapiro char *headerv; 4464562Sgshapiro{ 45132943Sgshapiro size_t len, l1, l2, offset; 4664562Sgshapiro int r; 47132943Sgshapiro mi_int32 v; 4864562Sgshapiro char *buf; 4964562Sgshapiro struct timeval timeout; 5064562Sgshapiro 5164562Sgshapiro if (headerf == NULL || *headerf == '\0' || headerv == NULL) 5264562Sgshapiro return MI_FAILURE; 5364562Sgshapiro timeout.tv_sec = ctx->ctx_timeout; 5464562Sgshapiro timeout.tv_usec = 0; 55132943Sgshapiro l1 = strlen(headerf) + 1; 56132943Sgshapiro l2 = strlen(headerv) + 1; 57132943Sgshapiro len = l1 + l2; 58132943Sgshapiro if (hdridx >= 0) 59132943Sgshapiro len += MILTER_LEN_BYTES; 6064562Sgshapiro buf = malloc(len); 6164562Sgshapiro if (buf == NULL) 6264562Sgshapiro return MI_FAILURE; 63132943Sgshapiro offset = 0; 64132943Sgshapiro if (hdridx >= 0) 65132943Sgshapiro { 66132943Sgshapiro v = htonl(hdridx); 67132943Sgshapiro (void) memcpy(&(buf[0]), (void *) &v, MILTER_LEN_BYTES); 68132943Sgshapiro offset += MILTER_LEN_BYTES; 69132943Sgshapiro } 70132943Sgshapiro (void) memcpy(buf + offset, headerf, l1); 71132943Sgshapiro (void) memcpy(buf + offset + l1, headerv, l2); 72132943Sgshapiro r = mi_wr_cmd(ctx->ctx_sd, &timeout, cmd, buf, len); 7364562Sgshapiro free(buf); 7464562Sgshapiro return r; 7564562Sgshapiro} 7664562Sgshapiro 7764562Sgshapiro/* 78132943Sgshapiro** SMFI_ADDHEADER -- send a new header to the MTA 79132943Sgshapiro** 80132943Sgshapiro** Parameters: 81132943Sgshapiro** ctx -- Opaque context structure 82132943Sgshapiro** headerf -- Header field name 83132943Sgshapiro** headerv -- Header field value 84132943Sgshapiro** 85132943Sgshapiro** Returns: 86132943Sgshapiro** MI_SUCCESS/MI_FAILURE 87132943Sgshapiro*/ 88132943Sgshapiro 89132943Sgshapiroint 90132943Sgshapirosmfi_addheader(ctx, headerf, headerv) 91132943Sgshapiro SMFICTX *ctx; 92132943Sgshapiro char *headerf; 93132943Sgshapiro char *headerv; 94132943Sgshapiro{ 95132943Sgshapiro if (!mi_sendok(ctx, SMFIF_ADDHDRS)) 96132943Sgshapiro return MI_FAILURE; 97132943Sgshapiro 98132943Sgshapiro return smfi_header(ctx, SMFIR_ADDHEADER, -1, headerf, headerv); 99132943Sgshapiro} 100132943Sgshapiro 101132943Sgshapiro/* 102132943Sgshapiro** SMFI_INSHEADER -- send a new header to the MTA (to be inserted) 103132943Sgshapiro** 104132943Sgshapiro** Parameters: 105132943Sgshapiro** ctx -- Opaque context structure 106132943Sgshapiro** hdridx -- index into header list where insertion should occur 107132943Sgshapiro** headerf -- Header field name 108132943Sgshapiro** headerv -- Header field value 109132943Sgshapiro** 110132943Sgshapiro** Returns: 111132943Sgshapiro** MI_SUCCESS/MI_FAILURE 112132943Sgshapiro*/ 113132943Sgshapiro 114132943Sgshapiroint 115132943Sgshapirosmfi_insheader(ctx, hdridx, headerf, headerv) 116132943Sgshapiro SMFICTX *ctx; 117132943Sgshapiro int hdridx; 118132943Sgshapiro char *headerf; 119132943Sgshapiro char *headerv; 120132943Sgshapiro{ 121132943Sgshapiro if (!mi_sendok(ctx, SMFIF_ADDHDRS) || hdridx < 0) 122132943Sgshapiro return MI_FAILURE; 123132943Sgshapiro 124132943Sgshapiro return smfi_header(ctx, SMFIR_INSHEADER, hdridx, headerf, headerv); 125132943Sgshapiro} 126132943Sgshapiro 127132943Sgshapiro/* 12864562Sgshapiro** SMFI_CHGHEADER -- send a changed header to the MTA 12964562Sgshapiro** 13064562Sgshapiro** Parameters: 13164562Sgshapiro** ctx -- Opaque context structure 13264562Sgshapiro** headerf -- Header field name 13364562Sgshapiro** hdridx -- Header index value 13464562Sgshapiro** headerv -- Header field value 13564562Sgshapiro** 13664562Sgshapiro** Returns: 13764562Sgshapiro** MI_SUCCESS/MI_FAILURE 13864562Sgshapiro*/ 13964562Sgshapiro 14064562Sgshapiroint 14164562Sgshapirosmfi_chgheader(ctx, headerf, hdridx, headerv) 14264562Sgshapiro SMFICTX *ctx; 14364562Sgshapiro char *headerf; 14464562Sgshapiro mi_int32 hdridx; 14564562Sgshapiro char *headerv; 14664562Sgshapiro{ 147132943Sgshapiro if (!mi_sendok(ctx, SMFIF_CHGHDRS) || hdridx < 0) 14864562Sgshapiro return MI_FAILURE; 14964562Sgshapiro if (headerv == NULL) 15064562Sgshapiro headerv = ""; 151132943Sgshapiro 152132943Sgshapiro return smfi_header(ctx, SMFIR_CHGHEADER, hdridx, headerf, headerv); 15364562Sgshapiro} 15494334Sgshapiro 15590792Sgshapiro/* 15664562Sgshapiro** SMFI_ADDRCPT -- send an additional recipient to the MTA 15764562Sgshapiro** 15864562Sgshapiro** Parameters: 15964562Sgshapiro** ctx -- Opaque context structure 16064562Sgshapiro** rcpt -- recipient address 16164562Sgshapiro** 16264562Sgshapiro** Returns: 16364562Sgshapiro** MI_SUCCESS/MI_FAILURE 16464562Sgshapiro*/ 16564562Sgshapiro 16664562Sgshapiroint 16764562Sgshapirosmfi_addrcpt(ctx, rcpt) 16864562Sgshapiro SMFICTX *ctx; 16964562Sgshapiro char *rcpt; 17064562Sgshapiro{ 17164562Sgshapiro size_t len; 17264562Sgshapiro struct timeval timeout; 17364562Sgshapiro 17464562Sgshapiro if (rcpt == NULL || *rcpt == '\0') 17564562Sgshapiro return MI_FAILURE; 17664562Sgshapiro if (!mi_sendok(ctx, SMFIF_ADDRCPT)) 17764562Sgshapiro return MI_FAILURE; 17864562Sgshapiro timeout.tv_sec = ctx->ctx_timeout; 17964562Sgshapiro timeout.tv_usec = 0; 18064562Sgshapiro len = strlen(rcpt) + 1; 18164562Sgshapiro return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_ADDRCPT, rcpt, len); 18264562Sgshapiro} 18394334Sgshapiro 18490792Sgshapiro/* 18564562Sgshapiro** SMFI_DELRCPT -- send a recipient to be removed to the MTA 18664562Sgshapiro** 18764562Sgshapiro** Parameters: 18864562Sgshapiro** ctx -- Opaque context structure 18964562Sgshapiro** rcpt -- recipient address 19064562Sgshapiro** 19164562Sgshapiro** Returns: 19264562Sgshapiro** MI_SUCCESS/MI_FAILURE 19364562Sgshapiro*/ 19464562Sgshapiro 19564562Sgshapiroint 19664562Sgshapirosmfi_delrcpt(ctx, rcpt) 19764562Sgshapiro SMFICTX *ctx; 19864562Sgshapiro char *rcpt; 19964562Sgshapiro{ 20064562Sgshapiro size_t len; 20164562Sgshapiro struct timeval timeout; 20264562Sgshapiro 20364562Sgshapiro if (rcpt == NULL || *rcpt == '\0') 20464562Sgshapiro return MI_FAILURE; 20564562Sgshapiro if (!mi_sendok(ctx, SMFIF_DELRCPT)) 20664562Sgshapiro return MI_FAILURE; 20764562Sgshapiro timeout.tv_sec = ctx->ctx_timeout; 20864562Sgshapiro timeout.tv_usec = 0; 20964562Sgshapiro len = strlen(rcpt) + 1; 21064562Sgshapiro return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_DELRCPT, rcpt, len); 21164562Sgshapiro} 21294334Sgshapiro 21390792Sgshapiro/* 21464562Sgshapiro** SMFI_REPLACEBODY -- send a body chunk to the MTA 21564562Sgshapiro** 21664562Sgshapiro** Parameters: 21764562Sgshapiro** ctx -- Opaque context structure 21864562Sgshapiro** bodyp -- body chunk 21964562Sgshapiro** bodylen -- length of body chunk 22064562Sgshapiro** 22164562Sgshapiro** Returns: 22264562Sgshapiro** MI_SUCCESS/MI_FAILURE 22364562Sgshapiro*/ 22464562Sgshapiro 22564562Sgshapiroint 22664562Sgshapirosmfi_replacebody(ctx, bodyp, bodylen) 22764562Sgshapiro SMFICTX *ctx; 22890792Sgshapiro unsigned char *bodyp; 22964562Sgshapiro int bodylen; 23064562Sgshapiro{ 23164562Sgshapiro int len, off, r; 23264562Sgshapiro struct timeval timeout; 23364562Sgshapiro 23490792Sgshapiro if (bodylen < 0 || 23590792Sgshapiro (bodyp == NULL && bodylen > 0)) 23664562Sgshapiro return MI_FAILURE; 23764562Sgshapiro if (!mi_sendok(ctx, SMFIF_CHGBODY)) 23864562Sgshapiro return MI_FAILURE; 23964562Sgshapiro timeout.tv_sec = ctx->ctx_timeout; 24064562Sgshapiro timeout.tv_usec = 0; 24164562Sgshapiro 24264562Sgshapiro /* split body chunk if necessary */ 24364562Sgshapiro off = 0; 24464562Sgshapiro while (bodylen > 0) 24564562Sgshapiro { 24664562Sgshapiro len = (bodylen >= MILTER_CHUNK_SIZE) ? MILTER_CHUNK_SIZE : 24764562Sgshapiro bodylen; 24864562Sgshapiro if ((r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_REPLBODY, 24964562Sgshapiro (char *) (bodyp + off), len)) != MI_SUCCESS) 25064562Sgshapiro return r; 25164562Sgshapiro off += len; 25264562Sgshapiro bodylen -= len; 25364562Sgshapiro } 25464562Sgshapiro return MI_SUCCESS; 25564562Sgshapiro} 25694334Sgshapiro 25790792Sgshapiro/* 25890792Sgshapiro** SMFI_QUARANTINE -- quarantine an envelope 25990792Sgshapiro** 26090792Sgshapiro** Parameters: 26190792Sgshapiro** ctx -- Opaque context structure 26290792Sgshapiro** reason -- why? 26390792Sgshapiro** 26490792Sgshapiro** Returns: 26590792Sgshapiro** MI_SUCCESS/MI_FAILURE 26690792Sgshapiro*/ 26790792Sgshapiro 26890792Sgshapiroint 26990792Sgshapirosmfi_quarantine(ctx, reason) 27090792Sgshapiro SMFICTX *ctx; 27190792Sgshapiro char *reason; 27290792Sgshapiro{ 27390792Sgshapiro size_t len; 27490792Sgshapiro int r; 27590792Sgshapiro char *buf; 27690792Sgshapiro struct timeval timeout; 27790792Sgshapiro 27890792Sgshapiro if (reason == NULL || *reason == '\0') 27990792Sgshapiro return MI_FAILURE; 28090792Sgshapiro if (!mi_sendok(ctx, SMFIF_QUARANTINE)) 28190792Sgshapiro return MI_FAILURE; 28290792Sgshapiro timeout.tv_sec = ctx->ctx_timeout; 28390792Sgshapiro timeout.tv_usec = 0; 28490792Sgshapiro len = strlen(reason) + 1; 28590792Sgshapiro buf = malloc(len); 28690792Sgshapiro if (buf == NULL) 28790792Sgshapiro return MI_FAILURE; 28890792Sgshapiro (void) memcpy(buf, reason, len); 28990792Sgshapiro r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_QUARANTINE, buf, len); 29090792Sgshapiro free(buf); 29190792Sgshapiro return r; 29290792Sgshapiro} 29390792Sgshapiro 29490792Sgshapiro/* 29564562Sgshapiro** MYISENHSC -- check whether a string contains an enhanced status code 29664562Sgshapiro** 29764562Sgshapiro** Parameters: 29864562Sgshapiro** s -- string with possible enhanced status code. 29964562Sgshapiro** delim -- delim for enhanced status code. 30064562Sgshapiro** 30164562Sgshapiro** Returns: 30264562Sgshapiro** 0 -- no enhanced status code. 30364562Sgshapiro** >4 -- length of enhanced status code. 30464562Sgshapiro** 30564562Sgshapiro** Side Effects: 30664562Sgshapiro** none. 30764562Sgshapiro*/ 30898121Sgshapiro 30964562Sgshapirostatic int 31064562Sgshapiromyisenhsc(s, delim) 31164562Sgshapiro const char *s; 31264562Sgshapiro int delim; 31364562Sgshapiro{ 31464562Sgshapiro int l, h; 31564562Sgshapiro 31664562Sgshapiro if (s == NULL) 31764562Sgshapiro return 0; 31864562Sgshapiro if (!((*s == '2' || *s == '4' || *s == '5') && s[1] == '.')) 31964562Sgshapiro return 0; 32064562Sgshapiro h = 0; 32164562Sgshapiro l = 2; 32264562Sgshapiro while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h])) 32364562Sgshapiro ++h; 32464562Sgshapiro if (h == 0 || s[l + h] != '.') 32564562Sgshapiro return 0; 32664562Sgshapiro l += h + 1; 32764562Sgshapiro h = 0; 32864562Sgshapiro while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h])) 32964562Sgshapiro ++h; 33064562Sgshapiro if (h == 0 || s[l + h] != delim) 33164562Sgshapiro return 0; 33264562Sgshapiro return l + h; 33364562Sgshapiro} 33490792Sgshapiro 33590792Sgshapiro/* 33664562Sgshapiro** SMFI_SETREPLY -- set the reply code for the next reply to the MTA 33764562Sgshapiro** 33864562Sgshapiro** Parameters: 33964562Sgshapiro** ctx -- Opaque context structure 34064562Sgshapiro** rcode -- The three-digit (RFC 821) SMTP reply code. 34164562Sgshapiro** xcode -- The extended (RFC 2034) reply code. 34264562Sgshapiro** message -- The text part of the SMTP reply. 34364562Sgshapiro** 34464562Sgshapiro** Returns: 34564562Sgshapiro** MI_SUCCESS/MI_FAILURE 34664562Sgshapiro*/ 34764562Sgshapiro 34864562Sgshapiroint 34964562Sgshapirosmfi_setreply(ctx, rcode, xcode, message) 35064562Sgshapiro SMFICTX *ctx; 35164562Sgshapiro char *rcode; 35264562Sgshapiro char *xcode; 35364562Sgshapiro char *message; 35464562Sgshapiro{ 35590792Sgshapiro size_t len; 35664562Sgshapiro char *buf; 35764562Sgshapiro 35864562Sgshapiro if (rcode == NULL || ctx == NULL) 35964562Sgshapiro return MI_FAILURE; 36090792Sgshapiro 36190792Sgshapiro /* ### <sp> \0 */ 36290792Sgshapiro len = strlen(rcode) + 2; 36390792Sgshapiro if (len != 5) 36464562Sgshapiro return MI_FAILURE; 36564562Sgshapiro if ((rcode[0] != '4' && rcode[0] != '5') || 36664562Sgshapiro !isascii(rcode[1]) || !isdigit(rcode[1]) || 36764562Sgshapiro !isascii(rcode[2]) || !isdigit(rcode[2])) 36864562Sgshapiro return MI_FAILURE; 36990792Sgshapiro if (xcode != NULL) 37090792Sgshapiro { 37190792Sgshapiro if (!myisenhsc(xcode, '\0')) 37290792Sgshapiro return MI_FAILURE; 37390792Sgshapiro len += strlen(xcode) + 1; 37490792Sgshapiro } 37590792Sgshapiro if (message != NULL) 37690792Sgshapiro { 37790792Sgshapiro size_t ml; 37890792Sgshapiro 37990792Sgshapiro /* XXX check also for unprintable chars? */ 38090792Sgshapiro if (strpbrk(message, "\r\n") != NULL) 38190792Sgshapiro return MI_FAILURE; 38290792Sgshapiro ml = strlen(message); 38390792Sgshapiro if (ml > MAXREPLYLEN) 38490792Sgshapiro return MI_FAILURE; 38590792Sgshapiro len += ml + 1; 38690792Sgshapiro } 38790792Sgshapiro buf = malloc(len); 38890792Sgshapiro if (buf == NULL) 38990792Sgshapiro return MI_FAILURE; /* oops */ 39090792Sgshapiro (void) sm_strlcpy(buf, rcode, len); 39190792Sgshapiro (void) sm_strlcat(buf, " ", len); 39290792Sgshapiro if (xcode != NULL) 39390792Sgshapiro (void) sm_strlcat(buf, xcode, len); 39490792Sgshapiro if (message != NULL) 39590792Sgshapiro { 39690792Sgshapiro if (xcode != NULL) 39790792Sgshapiro (void) sm_strlcat(buf, " ", len); 39890792Sgshapiro (void) sm_strlcat(buf, message, len); 39990792Sgshapiro } 40090792Sgshapiro if (ctx->ctx_reply != NULL) 40190792Sgshapiro free(ctx->ctx_reply); 40290792Sgshapiro ctx->ctx_reply = buf; 40390792Sgshapiro return MI_SUCCESS; 40490792Sgshapiro} 40590792Sgshapiro 40690792Sgshapiro/* 40790792Sgshapiro** SMFI_SETMLREPLY -- set multiline reply code for the next reply to the MTA 40890792Sgshapiro** 40990792Sgshapiro** Parameters: 41090792Sgshapiro** ctx -- Opaque context structure 41190792Sgshapiro** rcode -- The three-digit (RFC 821) SMTP reply code. 41290792Sgshapiro** xcode -- The extended (RFC 2034) reply code. 41390792Sgshapiro** txt, ... -- The text part of the SMTP reply, 41490792Sgshapiro** MUST be terminated with NULL. 41590792Sgshapiro** 41690792Sgshapiro** Returns: 41790792Sgshapiro** MI_SUCCESS/MI_FAILURE 41890792Sgshapiro*/ 41990792Sgshapiro 42090792Sgshapiroint 42190792Sgshapiro#if SM_VA_STD 42290792Sgshapirosmfi_setmlreply(SMFICTX *ctx, const char *rcode, const char *xcode, ...) 42390792Sgshapiro#else /* SM_VA_STD */ 42490792Sgshapirosmfi_setmlreply(ctx, rcode, xcode, va_alist) 42590792Sgshapiro SMFICTX *ctx; 42690792Sgshapiro const char *rcode; 42790792Sgshapiro const char *xcode; 42890792Sgshapiro va_dcl 42990792Sgshapiro#endif /* SM_VA_STD */ 43090792Sgshapiro{ 43190792Sgshapiro size_t len; 43290792Sgshapiro size_t rlen; 43390792Sgshapiro int args; 43490792Sgshapiro char *buf, *txt; 43590792Sgshapiro const char *xc; 43690792Sgshapiro char repl[16]; 43790792Sgshapiro SM_VA_LOCAL_DECL 43890792Sgshapiro 43990792Sgshapiro if (rcode == NULL || ctx == NULL) 44064562Sgshapiro return MI_FAILURE; 44190792Sgshapiro 44290792Sgshapiro /* ### <sp> */ 44390792Sgshapiro len = strlen(rcode) + 1; 44490792Sgshapiro if (len != 4) 44590792Sgshapiro return MI_FAILURE; 44690792Sgshapiro if ((rcode[0] != '4' && rcode[0] != '5') || 44790792Sgshapiro !isascii(rcode[1]) || !isdigit(rcode[1]) || 44890792Sgshapiro !isascii(rcode[2]) || !isdigit(rcode[2])) 44990792Sgshapiro return MI_FAILURE; 45090792Sgshapiro if (xcode != NULL) 45190792Sgshapiro { 45290792Sgshapiro if (!myisenhsc(xcode, '\0')) 45390792Sgshapiro return MI_FAILURE; 45490792Sgshapiro xc = xcode; 45590792Sgshapiro } 45690792Sgshapiro else 45790792Sgshapiro { 45890792Sgshapiro if (rcode[0] == '4') 45990792Sgshapiro xc = "4.0.0"; 46090792Sgshapiro else 46190792Sgshapiro xc = "5.0.0"; 46290792Sgshapiro } 46390792Sgshapiro 46490792Sgshapiro /* add trailing space */ 46590792Sgshapiro len += strlen(xc) + 1; 46690792Sgshapiro rlen = len; 46790792Sgshapiro args = 0; 46890792Sgshapiro SM_VA_START(ap, xcode); 46990792Sgshapiro while ((txt = SM_VA_ARG(ap, char *)) != NULL) 47090792Sgshapiro { 47190792Sgshapiro size_t tl; 47290792Sgshapiro 47390792Sgshapiro tl = strlen(txt); 47490792Sgshapiro if (tl > MAXREPLYLEN) 47594334Sgshapiro break; 47690792Sgshapiro 47790792Sgshapiro /* this text, reply codes, \r\n */ 47890792Sgshapiro len += tl + 2 + rlen; 47990792Sgshapiro if (++args > MAXREPLIES) 48094334Sgshapiro break; 48190792Sgshapiro 48290792Sgshapiro /* XXX check also for unprintable chars? */ 48390792Sgshapiro if (strpbrk(txt, "\r\n") != NULL) 48494334Sgshapiro break; 48590792Sgshapiro } 48690792Sgshapiro SM_VA_END(ap); 48794334Sgshapiro if (txt != NULL) 48894334Sgshapiro return MI_FAILURE; 48990792Sgshapiro 49090792Sgshapiro /* trailing '\0' */ 49190792Sgshapiro ++len; 49264562Sgshapiro buf = malloc(len); 49364562Sgshapiro if (buf == NULL) 49464562Sgshapiro return MI_FAILURE; /* oops */ 49590792Sgshapiro (void) sm_strlcpyn(buf, len, 3, rcode, args == 1 ? " " : "-", xc); 49690792Sgshapiro (void) sm_strlcpyn(repl, sizeof repl, 4, rcode, args == 1 ? " " : "-", 49790792Sgshapiro xc, " "); 49890792Sgshapiro SM_VA_START(ap, xcode); 49990792Sgshapiro txt = SM_VA_ARG(ap, char *); 50090792Sgshapiro if (txt != NULL) 50190792Sgshapiro { 50290792Sgshapiro (void) sm_strlcat2(buf, " ", txt, len); 50390792Sgshapiro while ((txt = SM_VA_ARG(ap, char *)) != NULL) 50490792Sgshapiro { 50590792Sgshapiro if (--args <= 1) 50690792Sgshapiro repl[3] = ' '; 50790792Sgshapiro (void) sm_strlcat2(buf, "\r\n", repl, len); 50890792Sgshapiro (void) sm_strlcat(buf, txt, len); 50990792Sgshapiro } 51090792Sgshapiro } 51164562Sgshapiro if (ctx->ctx_reply != NULL) 51264562Sgshapiro free(ctx->ctx_reply); 51364562Sgshapiro ctx->ctx_reply = buf; 51490792Sgshapiro SM_VA_END(ap); 51564562Sgshapiro return MI_SUCCESS; 51664562Sgshapiro} 51790792Sgshapiro 51890792Sgshapiro/* 51964562Sgshapiro** SMFI_SETPRIV -- set private data 52064562Sgshapiro** 52164562Sgshapiro** Parameters: 52264562Sgshapiro** ctx -- Opaque context structure 52364562Sgshapiro** privatedata -- pointer to private data 52464562Sgshapiro** 52564562Sgshapiro** Returns: 52664562Sgshapiro** MI_SUCCESS/MI_FAILURE 52764562Sgshapiro*/ 52864562Sgshapiro 52964562Sgshapiroint 53064562Sgshapirosmfi_setpriv(ctx, privatedata) 53164562Sgshapiro SMFICTX *ctx; 53264562Sgshapiro void *privatedata; 53364562Sgshapiro{ 53464562Sgshapiro if (ctx == NULL) 53564562Sgshapiro return MI_FAILURE; 53664562Sgshapiro ctx->ctx_privdata = privatedata; 53764562Sgshapiro return MI_SUCCESS; 53864562Sgshapiro} 53994334Sgshapiro 54090792Sgshapiro/* 54164562Sgshapiro** SMFI_GETPRIV -- get private data 54264562Sgshapiro** 54364562Sgshapiro** Parameters: 54464562Sgshapiro** ctx -- Opaque context structure 54564562Sgshapiro** 54664562Sgshapiro** Returns: 54764562Sgshapiro** pointer to private data 54864562Sgshapiro*/ 54964562Sgshapiro 55064562Sgshapirovoid * 55164562Sgshapirosmfi_getpriv(ctx) 55264562Sgshapiro SMFICTX *ctx; 55364562Sgshapiro{ 55464562Sgshapiro if (ctx == NULL) 55564562Sgshapiro return NULL; 55664562Sgshapiro return ctx->ctx_privdata; 55764562Sgshapiro} 55894334Sgshapiro 55990792Sgshapiro/* 56064562Sgshapiro** SMFI_GETSYMVAL -- get the value of a macro 56164562Sgshapiro** 56264562Sgshapiro** See explanation in mfapi.h about layout of the structures. 56364562Sgshapiro** 56464562Sgshapiro** Parameters: 56564562Sgshapiro** ctx -- Opaque context structure 56664562Sgshapiro** symname -- name of macro 56764562Sgshapiro** 56864562Sgshapiro** Returns: 56964562Sgshapiro** value of macro (NULL in case of failure) 57064562Sgshapiro*/ 57164562Sgshapiro 57264562Sgshapirochar * 57364562Sgshapirosmfi_getsymval(ctx, symname) 57464562Sgshapiro SMFICTX *ctx; 57564562Sgshapiro char *symname; 57664562Sgshapiro{ 57764562Sgshapiro int i; 57864562Sgshapiro char **s; 57964562Sgshapiro char one[2]; 58064562Sgshapiro char braces[4]; 58164562Sgshapiro 58264562Sgshapiro if (ctx == NULL || symname == NULL || *symname == '\0') 58364562Sgshapiro return NULL; 58464562Sgshapiro 58564562Sgshapiro if (strlen(symname) == 3 && symname[0] == '{' && symname[2] == '}') 58664562Sgshapiro { 58764562Sgshapiro one[0] = symname[1]; 58864562Sgshapiro one[1] = '\0'; 58964562Sgshapiro } 59064562Sgshapiro else 59164562Sgshapiro one[0] = '\0'; 59264562Sgshapiro if (strlen(symname) == 1) 59364562Sgshapiro { 59464562Sgshapiro braces[0] = '{'; 59564562Sgshapiro braces[1] = *symname; 59664562Sgshapiro braces[2] = '}'; 59764562Sgshapiro braces[3] = '\0'; 59864562Sgshapiro } 59964562Sgshapiro else 60064562Sgshapiro braces[0] = '\0'; 60164562Sgshapiro 60264562Sgshapiro /* search backwards through the macro array */ 60364562Sgshapiro for (i = MAX_MACROS_ENTRIES - 1 ; i >= 0; --i) 60464562Sgshapiro { 60564562Sgshapiro if ((s = ctx->ctx_mac_ptr[i]) == NULL || 60664562Sgshapiro ctx->ctx_mac_buf[i] == NULL) 60764562Sgshapiro continue; 60864562Sgshapiro while (s != NULL && *s != NULL) 60964562Sgshapiro { 61064562Sgshapiro if (strcmp(*s, symname) == 0) 61164562Sgshapiro return *++s; 61264562Sgshapiro if (one[0] != '\0' && strcmp(*s, one) == 0) 61364562Sgshapiro return *++s; 61464562Sgshapiro if (braces[0] != '\0' && strcmp(*s, braces) == 0) 61564562Sgshapiro return *++s; 61664562Sgshapiro ++s; /* skip over macro value */ 61764562Sgshapiro ++s; /* points to next macro name */ 61864562Sgshapiro } 61964562Sgshapiro } 62064562Sgshapiro return NULL; 62164562Sgshapiro} 62294334Sgshapiro 62394334Sgshapiro/* 62494334Sgshapiro** SMFI_PROGRESS -- send "progress" message to the MTA to prevent premature 62594334Sgshapiro** timeouts during long milter-side operations 62694334Sgshapiro** 62794334Sgshapiro** Parameters: 62894334Sgshapiro** ctx -- Opaque context structure 62994334Sgshapiro** 63094334Sgshapiro** Return value: 63194334Sgshapiro** MI_SUCCESS/MI_FAILURE 63294334Sgshapiro*/ 63394334Sgshapiro 63494334Sgshapiroint 63594334Sgshapirosmfi_progress(ctx) 63694334Sgshapiro SMFICTX *ctx; 63794334Sgshapiro{ 63894334Sgshapiro struct timeval timeout; 63994334Sgshapiro 64094334Sgshapiro if (ctx == NULL) 64194334Sgshapiro return MI_FAILURE; 64294334Sgshapiro 64394334Sgshapiro timeout.tv_sec = ctx->ctx_timeout; 64494334Sgshapiro timeout.tv_usec = 0; 64594334Sgshapiro 64694334Sgshapiro return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_PROGRESS, NULL, 0); 64794334Sgshapiro} 648