2 * Copyright (c) 1999-2002 Sendmail, Inc. and its suppliers.
5 * By using this file, you agree to the terms and conditions set
6 * forth in the LICENSE file which can be found at the top level of
7 * the sendmail distribution.
12 SM_RCSID("@(#)$Id: smfi.c,v 8.64 2002/04/30 22:22:02 msk Exp $")
13 #include <sm/varargs.h>
14 #include "libmilter.h"
16 /* for smfi_set{ml}reply, let's be generous. 256/16 should be sufficient */
17 #define MAXREPLYLEN 980 /* max. length of a reply string */
18 #define MAXREPLIES 32 /* max. number of reply strings */
21 ** SMFI_ADDHEADER -- send a new header to the MTA
24 ** ctx -- Opaque context structure
25 ** headerf -- Header field name
26 ** headerv -- Header field value
29 ** MI_SUCCESS/MI_FAILURE
33 smfi_addheader(ctx, headerf, headerv)
38 /* do we want to copy the stuff or have a special mi_wr_cmd call? */
42 struct timeval timeout;
44 if (headerf == NULL || *headerf == '\0' || headerv == NULL)
46 if (!mi_sendok(ctx, SMFIF_ADDHDRS))
48 timeout.tv_sec = ctx->ctx_timeout;
56 (void) memcpy(buf, headerf, l1 + 1);
57 (void) memcpy(buf + l1 + 1, headerv, l2 + 1);
58 r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_ADDHEADER, buf, len);
64 ** SMFI_CHGHEADER -- send a changed header to the MTA
67 ** ctx -- Opaque context structure
68 ** headerf -- Header field name
69 ** hdridx -- Header index value
70 ** headerv -- Header field value
73 ** MI_SUCCESS/MI_FAILURE
77 smfi_chgheader(ctx, headerf, hdridx, headerv)
83 /* do we want to copy the stuff or have a special mi_wr_cmd call? */
88 struct timeval timeout;
90 if (headerf == NULL || *headerf == '\0')
94 if (!mi_sendok(ctx, SMFIF_CHGHDRS))
96 timeout.tv_sec = ctx->ctx_timeout;
100 l1 = strlen(headerf);
101 l2 = strlen(headerv);
102 len = l1 + l2 + 2 + MILTER_LEN_BYTES;
107 (void) memcpy(&(buf[0]), (void *) &v, MILTER_LEN_BYTES);
108 (void) memcpy(buf + MILTER_LEN_BYTES, headerf, l1 + 1);
109 (void) memcpy(buf + MILTER_LEN_BYTES + l1 + 1, headerv, l2 + 1);
110 r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_CHGHEADER, buf, len);
116 ** SMFI_ADDRCPT -- send an additional recipient to the MTA
119 ** ctx -- Opaque context structure
120 ** rcpt -- recipient address
123 ** MI_SUCCESS/MI_FAILURE
127 smfi_addrcpt(ctx, rcpt)
132 struct timeval timeout;
134 if (rcpt == NULL || *rcpt == '\0')
136 if (!mi_sendok(ctx, SMFIF_ADDRCPT))
138 timeout.tv_sec = ctx->ctx_timeout;
140 len = strlen(rcpt) + 1;
141 return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_ADDRCPT, rcpt, len);
145 ** SMFI_DELRCPT -- send a recipient to be removed to the MTA
148 ** ctx -- Opaque context structure
149 ** rcpt -- recipient address
152 ** MI_SUCCESS/MI_FAILURE
156 smfi_delrcpt(ctx, rcpt)
161 struct timeval timeout;
163 if (rcpt == NULL || *rcpt == '\0')
165 if (!mi_sendok(ctx, SMFIF_DELRCPT))
167 timeout.tv_sec = ctx->ctx_timeout;
169 len = strlen(rcpt) + 1;
170 return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_DELRCPT, rcpt, len);
174 ** SMFI_REPLACEBODY -- send a body chunk to the MTA
177 ** ctx -- Opaque context structure
178 ** bodyp -- body chunk
179 ** bodylen -- length of body chunk
182 ** MI_SUCCESS/MI_FAILURE
186 smfi_replacebody(ctx, bodyp, bodylen)
188 unsigned char *bodyp;
192 struct timeval timeout;
195 (bodyp == NULL && bodylen > 0))
197 if (!mi_sendok(ctx, SMFIF_CHGBODY))
199 timeout.tv_sec = ctx->ctx_timeout;
202 /* split body chunk if necessary */
206 len = (bodylen >= MILTER_CHUNK_SIZE) ? MILTER_CHUNK_SIZE :
208 if ((r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_REPLBODY,
209 (char *) (bodyp + off), len)) != MI_SUCCESS)
219 ** SMFI_QUARANTINE -- quarantine an envelope
222 ** ctx -- Opaque context structure
226 ** MI_SUCCESS/MI_FAILURE
230 smfi_quarantine(ctx, reason)
237 struct timeval timeout;
239 if (reason == NULL || *reason == '\0')
241 if (!mi_sendok(ctx, SMFIF_QUARANTINE))
243 timeout.tv_sec = ctx->ctx_timeout;
245 len = strlen(reason) + 1;
249 (void) memcpy(buf, reason, len);
250 r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_QUARANTINE, buf, len);
254 #endif /* _FFR_QUARANTINE */
257 ** MYISENHSC -- check whether a string contains an enhanced status code
260 ** s -- string with possible enhanced status code.
261 ** delim -- delim for enhanced status code.
264 ** 0 -- no enhanced status code.
265 ** >4 -- length of enhanced status code.
280 if (!((*s == '2' || *s == '4' || *s == '5') && s[1] == '.'))
284 while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
286 if (h == 0 || s[l + h] != '.')
290 while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
292 if (h == 0 || s[l + h] != delim)
298 ** SMFI_SETREPLY -- set the reply code for the next reply to the MTA
301 ** ctx -- Opaque context structure
302 ** rcode -- The three-digit (RFC 821) SMTP reply code.
303 ** xcode -- The extended (RFC 2034) reply code.
304 ** message -- The text part of the SMTP reply.
307 ** MI_SUCCESS/MI_FAILURE
311 smfi_setreply(ctx, rcode, xcode, message)
320 if (rcode == NULL || ctx == NULL)
324 len = strlen(rcode) + 2;
327 if ((rcode[0] != '4' && rcode[0] != '5') ||
328 !isascii(rcode[1]) || !isdigit(rcode[1]) ||
329 !isascii(rcode[2]) || !isdigit(rcode[2]))
333 if (!myisenhsc(xcode, '\0'))
335 len += strlen(xcode) + 1;
341 /* XXX check also for unprintable chars? */
342 if (strpbrk(message, "\r\n") != NULL)
344 ml = strlen(message);
345 if (ml > MAXREPLYLEN)
351 return MI_FAILURE; /* oops */
352 (void) sm_strlcpy(buf, rcode, len);
353 (void) sm_strlcat(buf, " ", len);
355 (void) sm_strlcat(buf, xcode, len);
359 (void) sm_strlcat(buf, " ", len);
360 (void) sm_strlcat(buf, message, len);
362 if (ctx->ctx_reply != NULL)
363 free(ctx->ctx_reply);
364 ctx->ctx_reply = buf;
370 ** SMFI_SETMLREPLY -- set multiline reply code for the next reply to the MTA
373 ** ctx -- Opaque context structure
374 ** rcode -- The three-digit (RFC 821) SMTP reply code.
375 ** xcode -- The extended (RFC 2034) reply code.
376 ** txt, ... -- The text part of the SMTP reply,
377 ** MUST be terminated with NULL.
380 ** MI_SUCCESS/MI_FAILURE
385 smfi_setmlreply(SMFICTX *ctx, const char *rcode, const char *xcode, ...)
386 #else /* SM_VA_STD */
387 smfi_setmlreply(ctx, rcode, xcode, va_alist)
392 #endif /* SM_VA_STD */
402 if (rcode == NULL || ctx == NULL)
406 len = strlen(rcode) + 1;
409 if ((rcode[0] != '4' && rcode[0] != '5') ||
410 !isascii(rcode[1]) || !isdigit(rcode[1]) ||
411 !isascii(rcode[2]) || !isdigit(rcode[2]))
415 if (!myisenhsc(xcode, '\0'))
427 /* add trailing space */
428 len += strlen(xc) + 1;
431 SM_VA_START(ap, xcode);
432 while ((txt = SM_VA_ARG(ap, char *)) != NULL)
437 if (tl > MAXREPLYLEN)
440 /* this text, reply codes, \r\n */
441 len += tl + 2 + rlen;
442 if (++args > MAXREPLIES)
445 /* XXX check also for unprintable chars? */
446 if (strpbrk(txt, "\r\n") != NULL)
457 return MI_FAILURE; /* oops */
458 (void) sm_strlcpyn(buf, len, 3, rcode, args == 1 ? " " : "-", xc);
459 (void) sm_strlcpyn(repl, sizeof repl, 4, rcode, args == 1 ? " " : "-",
461 SM_VA_START(ap, xcode);
462 txt = SM_VA_ARG(ap, char *);
465 (void) sm_strlcat2(buf, " ", txt, len);
466 while ((txt = SM_VA_ARG(ap, char *)) != NULL)
470 (void) sm_strlcat2(buf, "\r\n", repl, len);
471 (void) sm_strlcat(buf, txt, len);
474 if (ctx->ctx_reply != NULL)
475 free(ctx->ctx_reply);
476 ctx->ctx_reply = buf;
480 #endif /* _FFR_MULTILINE */
483 ** SMFI_SETPRIV -- set private data
486 ** ctx -- Opaque context structure
487 ** privatedata -- pointer to private data
490 ** MI_SUCCESS/MI_FAILURE
494 smfi_setpriv(ctx, privatedata)
500 ctx->ctx_privdata = privatedata;
505 ** SMFI_GETPRIV -- get private data
508 ** ctx -- Opaque context structure
511 ** pointer to private data
520 return ctx->ctx_privdata;
524 ** SMFI_GETSYMVAL -- get the value of a macro
526 ** See explanation in mfapi.h about layout of the structures.
529 ** ctx -- Opaque context structure
530 ** symname -- name of macro
533 ** value of macro (NULL in case of failure)
537 smfi_getsymval(ctx, symname)
546 if (ctx == NULL || symname == NULL || *symname == '\0')
549 if (strlen(symname) == 3 && symname[0] == '{' && symname[2] == '}')
556 if (strlen(symname) == 1)
559 braces[1] = *symname;
566 /* search backwards through the macro array */
567 for (i = MAX_MACROS_ENTRIES - 1 ; i >= 0; --i)
569 if ((s = ctx->ctx_mac_ptr[i]) == NULL ||
570 ctx->ctx_mac_buf[i] == NULL)
572 while (s != NULL && *s != NULL)
574 if (strcmp(*s, symname) == 0)
576 if (one[0] != '\0' && strcmp(*s, one) == 0)
578 if (braces[0] != '\0' && strcmp(*s, braces) == 0)
580 ++s; /* skip over macro value */
581 ++s; /* points to next macro name */
587 #if _FFR_SMFI_PROGRESS
589 ** SMFI_PROGRESS -- send "progress" message to the MTA to prevent premature
590 ** timeouts during long milter-side operations
593 ** ctx -- Opaque context structure
596 ** MI_SUCCESS/MI_FAILURE
603 struct timeval timeout;
608 timeout.tv_sec = ctx->ctx_timeout;
611 return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_PROGRESS, NULL, 0);
613 #endif /* _FFR_SMFI_PROGRESS */