10Sstevel@tonic-gate /*
2*4518Sjbeck * Copyright (c) 1999-2007 Sendmail, Inc. and its suppliers.
30Sstevel@tonic-gate * All rights reserved.
40Sstevel@tonic-gate *
50Sstevel@tonic-gate * By using this file, you agree to the terms and conditions set
60Sstevel@tonic-gate * forth in the LICENSE file which can be found at the top level of
70Sstevel@tonic-gate * the sendmail distribution.
80Sstevel@tonic-gate *
90Sstevel@tonic-gate */
100Sstevel@tonic-gate
110Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
120Sstevel@tonic-gate
130Sstevel@tonic-gate #include <sm/gen.h>
14*4518Sjbeck SM_RCSID("@(#)$Id: smfi.c,v 8.83 2007/04/23 16:44:39 ca Exp $")
150Sstevel@tonic-gate #include <sm/varargs.h>
160Sstevel@tonic-gate #include "libmilter.h"
170Sstevel@tonic-gate
180Sstevel@tonic-gate static int smfi_header __P((SMFICTX *, int, int, char *, char *));
190Sstevel@tonic-gate static int myisenhsc __P((const char *, int));
200Sstevel@tonic-gate
210Sstevel@tonic-gate /* for smfi_set{ml}reply, let's be generous. 256/16 should be sufficient */
220Sstevel@tonic-gate #define MAXREPLYLEN 980 /* max. length of a reply string */
230Sstevel@tonic-gate #define MAXREPLIES 32 /* max. number of reply strings */
240Sstevel@tonic-gate
250Sstevel@tonic-gate /*
260Sstevel@tonic-gate ** SMFI_HEADER -- send a header to the MTA
270Sstevel@tonic-gate **
280Sstevel@tonic-gate ** Parameters:
290Sstevel@tonic-gate ** ctx -- Opaque context structure
300Sstevel@tonic-gate ** cmd -- Header modification command
310Sstevel@tonic-gate ** hdridx -- Header index
320Sstevel@tonic-gate ** headerf -- Header field name
330Sstevel@tonic-gate ** headerv -- Header field value
340Sstevel@tonic-gate **
350Sstevel@tonic-gate ** Returns:
360Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE
370Sstevel@tonic-gate */
380Sstevel@tonic-gate
390Sstevel@tonic-gate static int
smfi_header(ctx,cmd,hdridx,headerf,headerv)400Sstevel@tonic-gate smfi_header(ctx, cmd, hdridx, headerf, headerv)
410Sstevel@tonic-gate SMFICTX *ctx;
420Sstevel@tonic-gate int cmd;
430Sstevel@tonic-gate int hdridx;
440Sstevel@tonic-gate char *headerf;
450Sstevel@tonic-gate char *headerv;
460Sstevel@tonic-gate {
470Sstevel@tonic-gate size_t len, l1, l2, offset;
480Sstevel@tonic-gate int r;
490Sstevel@tonic-gate mi_int32 v;
500Sstevel@tonic-gate char *buf;
510Sstevel@tonic-gate struct timeval timeout;
520Sstevel@tonic-gate
530Sstevel@tonic-gate if (headerf == NULL || *headerf == '\0' || headerv == NULL)
540Sstevel@tonic-gate return MI_FAILURE;
550Sstevel@tonic-gate timeout.tv_sec = ctx->ctx_timeout;
560Sstevel@tonic-gate timeout.tv_usec = 0;
570Sstevel@tonic-gate l1 = strlen(headerf) + 1;
580Sstevel@tonic-gate l2 = strlen(headerv) + 1;
590Sstevel@tonic-gate len = l1 + l2;
600Sstevel@tonic-gate if (hdridx >= 0)
610Sstevel@tonic-gate len += MILTER_LEN_BYTES;
620Sstevel@tonic-gate buf = malloc(len);
630Sstevel@tonic-gate if (buf == NULL)
640Sstevel@tonic-gate return MI_FAILURE;
650Sstevel@tonic-gate offset = 0;
660Sstevel@tonic-gate if (hdridx >= 0)
670Sstevel@tonic-gate {
680Sstevel@tonic-gate v = htonl(hdridx);
690Sstevel@tonic-gate (void) memcpy(&(buf[0]), (void *) &v, MILTER_LEN_BYTES);
700Sstevel@tonic-gate offset += MILTER_LEN_BYTES;
710Sstevel@tonic-gate }
720Sstevel@tonic-gate (void) memcpy(buf + offset, headerf, l1);
730Sstevel@tonic-gate (void) memcpy(buf + offset + l1, headerv, l2);
740Sstevel@tonic-gate r = mi_wr_cmd(ctx->ctx_sd, &timeout, cmd, buf, len);
750Sstevel@tonic-gate free(buf);
760Sstevel@tonic-gate return r;
770Sstevel@tonic-gate }
780Sstevel@tonic-gate
790Sstevel@tonic-gate /*
800Sstevel@tonic-gate ** SMFI_ADDHEADER -- send a new header to the MTA
810Sstevel@tonic-gate **
820Sstevel@tonic-gate ** Parameters:
830Sstevel@tonic-gate ** ctx -- Opaque context structure
840Sstevel@tonic-gate ** headerf -- Header field name
850Sstevel@tonic-gate ** headerv -- Header field value
860Sstevel@tonic-gate **
870Sstevel@tonic-gate ** Returns:
880Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE
890Sstevel@tonic-gate */
900Sstevel@tonic-gate
910Sstevel@tonic-gate int
smfi_addheader(ctx,headerf,headerv)920Sstevel@tonic-gate smfi_addheader(ctx, headerf, headerv)
930Sstevel@tonic-gate SMFICTX *ctx;
940Sstevel@tonic-gate char *headerf;
950Sstevel@tonic-gate char *headerv;
960Sstevel@tonic-gate {
970Sstevel@tonic-gate if (!mi_sendok(ctx, SMFIF_ADDHDRS))
980Sstevel@tonic-gate return MI_FAILURE;
990Sstevel@tonic-gate
1000Sstevel@tonic-gate return smfi_header(ctx, SMFIR_ADDHEADER, -1, headerf, headerv);
1010Sstevel@tonic-gate }
1020Sstevel@tonic-gate
1030Sstevel@tonic-gate /*
1040Sstevel@tonic-gate ** SMFI_INSHEADER -- send a new header to the MTA (to be inserted)
1050Sstevel@tonic-gate **
1060Sstevel@tonic-gate ** Parameters:
1070Sstevel@tonic-gate ** ctx -- Opaque context structure
1080Sstevel@tonic-gate ** hdridx -- index into header list where insertion should occur
1090Sstevel@tonic-gate ** headerf -- Header field name
1100Sstevel@tonic-gate ** headerv -- Header field value
1110Sstevel@tonic-gate **
1120Sstevel@tonic-gate ** Returns:
1130Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE
1140Sstevel@tonic-gate */
1150Sstevel@tonic-gate
1160Sstevel@tonic-gate int
smfi_insheader(ctx,hdridx,headerf,headerv)1170Sstevel@tonic-gate smfi_insheader(ctx, hdridx, headerf, headerv)
1180Sstevel@tonic-gate SMFICTX *ctx;
1190Sstevel@tonic-gate int hdridx;
1200Sstevel@tonic-gate char *headerf;
1210Sstevel@tonic-gate char *headerv;
1220Sstevel@tonic-gate {
1230Sstevel@tonic-gate if (!mi_sendok(ctx, SMFIF_ADDHDRS) || hdridx < 0)
1240Sstevel@tonic-gate return MI_FAILURE;
1250Sstevel@tonic-gate
1260Sstevel@tonic-gate return smfi_header(ctx, SMFIR_INSHEADER, hdridx, headerf, headerv);
1270Sstevel@tonic-gate }
1280Sstevel@tonic-gate
1290Sstevel@tonic-gate /*
1300Sstevel@tonic-gate ** SMFI_CHGHEADER -- send a changed header to the MTA
1310Sstevel@tonic-gate **
1320Sstevel@tonic-gate ** Parameters:
1330Sstevel@tonic-gate ** ctx -- Opaque context structure
1340Sstevel@tonic-gate ** headerf -- Header field name
1350Sstevel@tonic-gate ** hdridx -- Header index value
1360Sstevel@tonic-gate ** headerv -- Header field value
1370Sstevel@tonic-gate **
1380Sstevel@tonic-gate ** Returns:
1390Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE
1400Sstevel@tonic-gate */
1410Sstevel@tonic-gate
1420Sstevel@tonic-gate int
smfi_chgheader(ctx,headerf,hdridx,headerv)1430Sstevel@tonic-gate smfi_chgheader(ctx, headerf, hdridx, headerv)
1440Sstevel@tonic-gate SMFICTX *ctx;
1450Sstevel@tonic-gate char *headerf;
1460Sstevel@tonic-gate mi_int32 hdridx;
1470Sstevel@tonic-gate char *headerv;
1480Sstevel@tonic-gate {
1490Sstevel@tonic-gate if (!mi_sendok(ctx, SMFIF_CHGHDRS) || hdridx < 0)
1500Sstevel@tonic-gate return MI_FAILURE;
1510Sstevel@tonic-gate if (headerv == NULL)
1520Sstevel@tonic-gate headerv = "";
1530Sstevel@tonic-gate
1540Sstevel@tonic-gate return smfi_header(ctx, SMFIR_CHGHEADER, hdridx, headerf, headerv);
1550Sstevel@tonic-gate }
1560Sstevel@tonic-gate
1573544Sjbeck #if 0
1583544Sjbeck /*
1593544Sjbeck ** BUF_CRT_SEND -- construct buffer to send from arguments
1603544Sjbeck **
1613544Sjbeck ** Parameters:
1623544Sjbeck ** ctx -- Opaque context structure
1633544Sjbeck ** cmd -- command
1643544Sjbeck ** arg0 -- first argument
1653544Sjbeck ** argv -- list of arguments (NULL terminated)
1663544Sjbeck **
1673544Sjbeck ** Returns:
1683544Sjbeck ** MI_SUCCESS/MI_FAILURE
1693544Sjbeck */
1703544Sjbeck
1713544Sjbeck static int
1723544Sjbeck buf_crt_send __P((SMFICTX *, int cmd, char *, char **));
1733544Sjbeck
1743544Sjbeck static int
1753544Sjbeck buf_crt_send(ctx, cmd, arg0, argv)
1763544Sjbeck SMFICTX *ctx;
1773544Sjbeck int cmd;
1783544Sjbeck char *arg0;
1793544Sjbeck char **argv;
1803544Sjbeck {
1813544Sjbeck size_t len, l0, l1, offset;
1823544Sjbeck int r;
1833544Sjbeck char *buf, *arg, **argvl;
1843544Sjbeck struct timeval timeout;
1853544Sjbeck
1863544Sjbeck if (arg0 == NULL || *arg0 == '\0')
1873544Sjbeck return MI_FAILURE;
1883544Sjbeck timeout.tv_sec = ctx->ctx_timeout;
1893544Sjbeck timeout.tv_usec = 0;
1903544Sjbeck l0 = strlen(arg0) + 1;
1913544Sjbeck len = l0;
1923544Sjbeck argvl = argv;
1933544Sjbeck while (argvl != NULL && (arg = *argv) != NULL && *arg != '\0')
1943544Sjbeck {
1953544Sjbeck l1 = strlen(arg) + 1;
1963544Sjbeck len += l1;
1973544Sjbeck SM_ASSERT(len > l1);
1983544Sjbeck }
1993544Sjbeck
2003544Sjbeck buf = malloc(len);
2013544Sjbeck if (buf == NULL)
2023544Sjbeck return MI_FAILURE;
2033544Sjbeck (void) memcpy(buf, arg0, l0);
2043544Sjbeck offset = l0;
2053544Sjbeck
2063544Sjbeck argvl = argv;
2073544Sjbeck while (argvl != NULL && (arg = *argv) != NULL && *arg != '\0')
2083544Sjbeck {
2093544Sjbeck l1 = strlen(arg) + 1;
2103544Sjbeck SM_ASSERT(offset < len);
2113544Sjbeck SM_ASSERT(offset + l1 <= len);
2123544Sjbeck (void) memcpy(buf + offset, arg, l1);
2133544Sjbeck offset += l1;
2143544Sjbeck SM_ASSERT(offset > l1);
2153544Sjbeck }
2163544Sjbeck
2173544Sjbeck r = mi_wr_cmd(ctx->ctx_sd, &timeout, cmd, buf, len);
2183544Sjbeck free(buf);
2193544Sjbeck return r;
2203544Sjbeck }
2213544Sjbeck #endif /* 0 */
2223544Sjbeck
2233544Sjbeck /*
2243544Sjbeck ** SEND2 -- construct buffer to send from arguments
2253544Sjbeck **
2263544Sjbeck ** Parameters:
2273544Sjbeck ** ctx -- Opaque context structure
2283544Sjbeck ** cmd -- command
2293544Sjbeck ** arg0 -- first argument
2303544Sjbeck ** argv -- list of arguments (NULL terminated)
2313544Sjbeck **
2323544Sjbeck ** Returns:
2333544Sjbeck ** MI_SUCCESS/MI_FAILURE
2343544Sjbeck */
2353544Sjbeck
2363544Sjbeck static int
2373544Sjbeck send2 __P((SMFICTX *, int cmd, char *, char *));
2383544Sjbeck
2393544Sjbeck static int
send2(ctx,cmd,arg0,arg1)2403544Sjbeck send2(ctx, cmd, arg0, arg1)
2413544Sjbeck SMFICTX *ctx;
2423544Sjbeck int cmd;
2433544Sjbeck char *arg0;
2443544Sjbeck char *arg1;
2453544Sjbeck {
2463544Sjbeck size_t len, l0, l1, offset;
2473544Sjbeck int r;
2483544Sjbeck char *buf;
2493544Sjbeck struct timeval timeout;
2503544Sjbeck
2513544Sjbeck if (arg0 == NULL || *arg0 == '\0')
2523544Sjbeck return MI_FAILURE;
2533544Sjbeck timeout.tv_sec = ctx->ctx_timeout;
2543544Sjbeck timeout.tv_usec = 0;
2553544Sjbeck l0 = strlen(arg0) + 1;
2563544Sjbeck len = l0;
2573544Sjbeck if (arg1 != NULL)
2583544Sjbeck {
2593544Sjbeck l1 = strlen(arg1) + 1;
2603544Sjbeck len += l1;
2613544Sjbeck SM_ASSERT(len > l1);
2623544Sjbeck }
2633544Sjbeck
2643544Sjbeck buf = malloc(len);
2653544Sjbeck if (buf == NULL)
2663544Sjbeck return MI_FAILURE;
2673544Sjbeck (void) memcpy(buf, arg0, l0);
2683544Sjbeck offset = l0;
2693544Sjbeck
2703544Sjbeck if (arg1 != NULL)
2713544Sjbeck {
2723544Sjbeck l1 = strlen(arg1) + 1;
2733544Sjbeck SM_ASSERT(offset < len);
2743544Sjbeck SM_ASSERT(offset + l1 <= len);
2753544Sjbeck (void) memcpy(buf + offset, arg1, l1);
2763544Sjbeck offset += l1;
2773544Sjbeck SM_ASSERT(offset > l1);
2783544Sjbeck }
2793544Sjbeck
2803544Sjbeck r = mi_wr_cmd(ctx->ctx_sd, &timeout, cmd, buf, len);
2813544Sjbeck free(buf);
2823544Sjbeck return r;
2833544Sjbeck }
2843544Sjbeck
2853544Sjbeck /*
2863544Sjbeck ** SMFI_CHGFROM -- change enveloper sender ("from") address
2873544Sjbeck **
2883544Sjbeck ** Parameters:
2893544Sjbeck ** ctx -- Opaque context structure
2903544Sjbeck ** from -- new envelope sender address ("MAIL From")
2913544Sjbeck ** args -- ESMTP arguments
2923544Sjbeck **
2933544Sjbeck ** Returns:
2943544Sjbeck ** MI_SUCCESS/MI_FAILURE
2953544Sjbeck */
2963544Sjbeck
2973544Sjbeck int
smfi_chgfrom(ctx,from,args)2983544Sjbeck smfi_chgfrom(ctx, from, args)
2993544Sjbeck SMFICTX *ctx;
3003544Sjbeck char *from;
3013544Sjbeck char *args;
3023544Sjbeck {
3033544Sjbeck if (from == NULL || *from == '\0')
3043544Sjbeck return MI_FAILURE;
3053544Sjbeck if (!mi_sendok(ctx, SMFIF_CHGFROM))
3063544Sjbeck return MI_FAILURE;
3073544Sjbeck return send2(ctx, SMFIR_CHGFROM, from, args);
3083544Sjbeck }
3093544Sjbeck
3103544Sjbeck /*
3113544Sjbeck ** SMFI_SETSYMLIST -- set list of macros that the MTA should send.
3123544Sjbeck **
3133544Sjbeck ** Parameters:
3143544Sjbeck ** ctx -- Opaque context structure
3153544Sjbeck ** where -- SMTP stage
3163544Sjbeck ** macros -- list of macros
3173544Sjbeck **
3183544Sjbeck ** Returns:
3193544Sjbeck ** MI_SUCCESS/MI_FAILURE
3203544Sjbeck */
3213544Sjbeck
3223544Sjbeck int
smfi_setsymlist(ctx,where,macros)3233544Sjbeck smfi_setsymlist(ctx, where, macros)
3243544Sjbeck SMFICTX *ctx;
3253544Sjbeck int where;
3263544Sjbeck char *macros;
3273544Sjbeck {
3283544Sjbeck SM_ASSERT(ctx != NULL);
3293544Sjbeck
3303544Sjbeck if (macros == NULL || *macros == '\0')
3313544Sjbeck return MI_FAILURE;
3323544Sjbeck if (where < SMFIM_FIRST || where > SMFIM_LAST)
3333544Sjbeck return MI_FAILURE;
3343544Sjbeck if (where < 0 || where >= MAX_MACROS_ENTRIES)
3353544Sjbeck return MI_FAILURE;
3363544Sjbeck
3373544Sjbeck if (ctx->ctx_mac_list[where] != NULL)
3383544Sjbeck return MI_FAILURE;
3393544Sjbeck
3403544Sjbeck ctx->ctx_mac_list[where] = strdup(macros);
3413544Sjbeck if (ctx->ctx_mac_list[where] == NULL)
3423544Sjbeck return MI_FAILURE;
3433544Sjbeck
3443544Sjbeck return MI_SUCCESS;
3453544Sjbeck }
3463544Sjbeck
3473544Sjbeck /*
3483544Sjbeck ** SMFI_ADDRCPT_PAR -- send an additional recipient to the MTA
3493544Sjbeck **
3503544Sjbeck ** Parameters:
3513544Sjbeck ** ctx -- Opaque context structure
3523544Sjbeck ** rcpt -- recipient address
3533544Sjbeck ** args -- ESMTP arguments
3543544Sjbeck **
3553544Sjbeck ** Returns:
3563544Sjbeck ** MI_SUCCESS/MI_FAILURE
3573544Sjbeck */
3583544Sjbeck
3593544Sjbeck int
smfi_addrcpt_par(ctx,rcpt,args)3603544Sjbeck smfi_addrcpt_par(ctx, rcpt, args)
3613544Sjbeck SMFICTX *ctx;
3623544Sjbeck char *rcpt;
3633544Sjbeck char *args;
3643544Sjbeck {
3653544Sjbeck if (rcpt == NULL || *rcpt == '\0')
3663544Sjbeck return MI_FAILURE;
3673544Sjbeck if (!mi_sendok(ctx, SMFIF_ADDRCPT_PAR))
3683544Sjbeck return MI_FAILURE;
3693544Sjbeck return send2(ctx, SMFIR_ADDRCPT_PAR, rcpt, args);
3703544Sjbeck }
3713544Sjbeck
3720Sstevel@tonic-gate /*
3730Sstevel@tonic-gate ** SMFI_ADDRCPT -- send an additional recipient to the MTA
3740Sstevel@tonic-gate **
3750Sstevel@tonic-gate ** Parameters:
3760Sstevel@tonic-gate ** ctx -- Opaque context structure
3770Sstevel@tonic-gate ** rcpt -- recipient address
3780Sstevel@tonic-gate **
3790Sstevel@tonic-gate ** Returns:
3800Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE
3810Sstevel@tonic-gate */
3820Sstevel@tonic-gate
3830Sstevel@tonic-gate int
smfi_addrcpt(ctx,rcpt)3840Sstevel@tonic-gate smfi_addrcpt(ctx, rcpt)
3850Sstevel@tonic-gate SMFICTX *ctx;
3860Sstevel@tonic-gate char *rcpt;
3870Sstevel@tonic-gate {
3880Sstevel@tonic-gate size_t len;
3890Sstevel@tonic-gate struct timeval timeout;
3900Sstevel@tonic-gate
3910Sstevel@tonic-gate if (rcpt == NULL || *rcpt == '\0')
3920Sstevel@tonic-gate return MI_FAILURE;
3930Sstevel@tonic-gate if (!mi_sendok(ctx, SMFIF_ADDRCPT))
3940Sstevel@tonic-gate return MI_FAILURE;
3950Sstevel@tonic-gate timeout.tv_sec = ctx->ctx_timeout;
3960Sstevel@tonic-gate timeout.tv_usec = 0;
3970Sstevel@tonic-gate len = strlen(rcpt) + 1;
3980Sstevel@tonic-gate return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_ADDRCPT, rcpt, len);
3990Sstevel@tonic-gate }
4000Sstevel@tonic-gate
4010Sstevel@tonic-gate /*
4020Sstevel@tonic-gate ** SMFI_DELRCPT -- send a recipient to be removed to the MTA
4030Sstevel@tonic-gate **
4040Sstevel@tonic-gate ** Parameters:
4050Sstevel@tonic-gate ** ctx -- Opaque context structure
4060Sstevel@tonic-gate ** rcpt -- recipient address
4070Sstevel@tonic-gate **
4080Sstevel@tonic-gate ** Returns:
4090Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE
4100Sstevel@tonic-gate */
4110Sstevel@tonic-gate
4120Sstevel@tonic-gate int
smfi_delrcpt(ctx,rcpt)4130Sstevel@tonic-gate smfi_delrcpt(ctx, rcpt)
4140Sstevel@tonic-gate SMFICTX *ctx;
4150Sstevel@tonic-gate char *rcpt;
4160Sstevel@tonic-gate {
4170Sstevel@tonic-gate size_t len;
4180Sstevel@tonic-gate struct timeval timeout;
4190Sstevel@tonic-gate
4200Sstevel@tonic-gate if (rcpt == NULL || *rcpt == '\0')
4210Sstevel@tonic-gate return MI_FAILURE;
4220Sstevel@tonic-gate if (!mi_sendok(ctx, SMFIF_DELRCPT))
4230Sstevel@tonic-gate return MI_FAILURE;
4240Sstevel@tonic-gate timeout.tv_sec = ctx->ctx_timeout;
4250Sstevel@tonic-gate timeout.tv_usec = 0;
4260Sstevel@tonic-gate len = strlen(rcpt) + 1;
4270Sstevel@tonic-gate return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_DELRCPT, rcpt, len);
4280Sstevel@tonic-gate }
4290Sstevel@tonic-gate
4300Sstevel@tonic-gate /*
4310Sstevel@tonic-gate ** SMFI_REPLACEBODY -- send a body chunk to the MTA
4320Sstevel@tonic-gate **
4330Sstevel@tonic-gate ** Parameters:
4340Sstevel@tonic-gate ** ctx -- Opaque context structure
4350Sstevel@tonic-gate ** bodyp -- body chunk
4360Sstevel@tonic-gate ** bodylen -- length of body chunk
4370Sstevel@tonic-gate **
4380Sstevel@tonic-gate ** Returns:
4390Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE
4400Sstevel@tonic-gate */
4410Sstevel@tonic-gate
4420Sstevel@tonic-gate int
smfi_replacebody(ctx,bodyp,bodylen)4430Sstevel@tonic-gate smfi_replacebody(ctx, bodyp, bodylen)
4440Sstevel@tonic-gate SMFICTX *ctx;
4450Sstevel@tonic-gate unsigned char *bodyp;
4460Sstevel@tonic-gate int bodylen;
4470Sstevel@tonic-gate {
4480Sstevel@tonic-gate int len, off, r;
4490Sstevel@tonic-gate struct timeval timeout;
4500Sstevel@tonic-gate
4510Sstevel@tonic-gate if (bodylen < 0 ||
4520Sstevel@tonic-gate (bodyp == NULL && bodylen > 0))
4530Sstevel@tonic-gate return MI_FAILURE;
4540Sstevel@tonic-gate if (!mi_sendok(ctx, SMFIF_CHGBODY))
4550Sstevel@tonic-gate return MI_FAILURE;
4560Sstevel@tonic-gate timeout.tv_sec = ctx->ctx_timeout;
4570Sstevel@tonic-gate timeout.tv_usec = 0;
4580Sstevel@tonic-gate
4590Sstevel@tonic-gate /* split body chunk if necessary */
4600Sstevel@tonic-gate off = 0;
461616Sjbeck do
4620Sstevel@tonic-gate {
4630Sstevel@tonic-gate len = (bodylen >= MILTER_CHUNK_SIZE) ? MILTER_CHUNK_SIZE :
4640Sstevel@tonic-gate bodylen;
4650Sstevel@tonic-gate if ((r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_REPLBODY,
4660Sstevel@tonic-gate (char *) (bodyp + off), len)) != MI_SUCCESS)
4670Sstevel@tonic-gate return r;
4680Sstevel@tonic-gate off += len;
4690Sstevel@tonic-gate bodylen -= len;
470616Sjbeck } while (bodylen > 0);
4710Sstevel@tonic-gate return MI_SUCCESS;
4720Sstevel@tonic-gate }
4730Sstevel@tonic-gate
4740Sstevel@tonic-gate /*
4750Sstevel@tonic-gate ** SMFI_QUARANTINE -- quarantine an envelope
4760Sstevel@tonic-gate **
4770Sstevel@tonic-gate ** Parameters:
4780Sstevel@tonic-gate ** ctx -- Opaque context structure
4790Sstevel@tonic-gate ** reason -- why?
4800Sstevel@tonic-gate **
4810Sstevel@tonic-gate ** Returns:
4820Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE
4830Sstevel@tonic-gate */
4840Sstevel@tonic-gate
4850Sstevel@tonic-gate int
smfi_quarantine(ctx,reason)4860Sstevel@tonic-gate smfi_quarantine(ctx, reason)
4870Sstevel@tonic-gate SMFICTX *ctx;
4880Sstevel@tonic-gate char *reason;
4890Sstevel@tonic-gate {
4900Sstevel@tonic-gate size_t len;
4910Sstevel@tonic-gate int r;
4920Sstevel@tonic-gate char *buf;
4930Sstevel@tonic-gate struct timeval timeout;
4940Sstevel@tonic-gate
4950Sstevel@tonic-gate if (reason == NULL || *reason == '\0')
4960Sstevel@tonic-gate return MI_FAILURE;
4970Sstevel@tonic-gate if (!mi_sendok(ctx, SMFIF_QUARANTINE))
4980Sstevel@tonic-gate return MI_FAILURE;
4990Sstevel@tonic-gate timeout.tv_sec = ctx->ctx_timeout;
5000Sstevel@tonic-gate timeout.tv_usec = 0;
5010Sstevel@tonic-gate len = strlen(reason) + 1;
5020Sstevel@tonic-gate buf = malloc(len);
5030Sstevel@tonic-gate if (buf == NULL)
5040Sstevel@tonic-gate return MI_FAILURE;
5050Sstevel@tonic-gate (void) memcpy(buf, reason, len);
5060Sstevel@tonic-gate r = mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_QUARANTINE, buf, len);
5070Sstevel@tonic-gate free(buf);
5080Sstevel@tonic-gate return r;
5090Sstevel@tonic-gate }
5100Sstevel@tonic-gate
5110Sstevel@tonic-gate /*
5120Sstevel@tonic-gate ** MYISENHSC -- check whether a string contains an enhanced status code
5130Sstevel@tonic-gate **
5140Sstevel@tonic-gate ** Parameters:
5150Sstevel@tonic-gate ** s -- string with possible enhanced status code.
5160Sstevel@tonic-gate ** delim -- delim for enhanced status code.
5170Sstevel@tonic-gate **
5180Sstevel@tonic-gate ** Returns:
5190Sstevel@tonic-gate ** 0 -- no enhanced status code.
5200Sstevel@tonic-gate ** >4 -- length of enhanced status code.
5210Sstevel@tonic-gate **
5220Sstevel@tonic-gate ** Side Effects:
5230Sstevel@tonic-gate ** none.
5240Sstevel@tonic-gate */
5250Sstevel@tonic-gate
5260Sstevel@tonic-gate static int
myisenhsc(s,delim)5270Sstevel@tonic-gate myisenhsc(s, delim)
5280Sstevel@tonic-gate const char *s;
5290Sstevel@tonic-gate int delim;
5300Sstevel@tonic-gate {
5310Sstevel@tonic-gate int l, h;
5320Sstevel@tonic-gate
5330Sstevel@tonic-gate if (s == NULL)
5340Sstevel@tonic-gate return 0;
5350Sstevel@tonic-gate if (!((*s == '2' || *s == '4' || *s == '5') && s[1] == '.'))
5360Sstevel@tonic-gate return 0;
5370Sstevel@tonic-gate h = 0;
5380Sstevel@tonic-gate l = 2;
5390Sstevel@tonic-gate while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
5400Sstevel@tonic-gate ++h;
5410Sstevel@tonic-gate if (h == 0 || s[l + h] != '.')
5420Sstevel@tonic-gate return 0;
5430Sstevel@tonic-gate l += h + 1;
5440Sstevel@tonic-gate h = 0;
5450Sstevel@tonic-gate while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
5460Sstevel@tonic-gate ++h;
5470Sstevel@tonic-gate if (h == 0 || s[l + h] != delim)
5480Sstevel@tonic-gate return 0;
5490Sstevel@tonic-gate return l + h;
5500Sstevel@tonic-gate }
5510Sstevel@tonic-gate
5520Sstevel@tonic-gate /*
5530Sstevel@tonic-gate ** SMFI_SETREPLY -- set the reply code for the next reply to the MTA
5540Sstevel@tonic-gate **
5550Sstevel@tonic-gate ** Parameters:
5560Sstevel@tonic-gate ** ctx -- Opaque context structure
5570Sstevel@tonic-gate ** rcode -- The three-digit (RFC 821) SMTP reply code.
5580Sstevel@tonic-gate ** xcode -- The extended (RFC 2034) reply code.
5590Sstevel@tonic-gate ** message -- The text part of the SMTP reply.
5600Sstevel@tonic-gate **
5610Sstevel@tonic-gate ** Returns:
5620Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE
5630Sstevel@tonic-gate */
5640Sstevel@tonic-gate
5650Sstevel@tonic-gate int
smfi_setreply(ctx,rcode,xcode,message)5660Sstevel@tonic-gate smfi_setreply(ctx, rcode, xcode, message)
5670Sstevel@tonic-gate SMFICTX *ctx;
5680Sstevel@tonic-gate char *rcode;
5690Sstevel@tonic-gate char *xcode;
5700Sstevel@tonic-gate char *message;
5710Sstevel@tonic-gate {
5720Sstevel@tonic-gate size_t len;
5730Sstevel@tonic-gate char *buf;
5740Sstevel@tonic-gate
5750Sstevel@tonic-gate if (rcode == NULL || ctx == NULL)
5760Sstevel@tonic-gate return MI_FAILURE;
5770Sstevel@tonic-gate
5780Sstevel@tonic-gate /* ### <sp> \0 */
5790Sstevel@tonic-gate len = strlen(rcode) + 2;
5800Sstevel@tonic-gate if (len != 5)
5810Sstevel@tonic-gate return MI_FAILURE;
5820Sstevel@tonic-gate if ((rcode[0] != '4' && rcode[0] != '5') ||
5830Sstevel@tonic-gate !isascii(rcode[1]) || !isdigit(rcode[1]) ||
5840Sstevel@tonic-gate !isascii(rcode[2]) || !isdigit(rcode[2]))
5850Sstevel@tonic-gate return MI_FAILURE;
5860Sstevel@tonic-gate if (xcode != NULL)
5870Sstevel@tonic-gate {
5880Sstevel@tonic-gate if (!myisenhsc(xcode, '\0'))
5890Sstevel@tonic-gate return MI_FAILURE;
5900Sstevel@tonic-gate len += strlen(xcode) + 1;
5910Sstevel@tonic-gate }
5920Sstevel@tonic-gate if (message != NULL)
5930Sstevel@tonic-gate {
5940Sstevel@tonic-gate size_t ml;
5950Sstevel@tonic-gate
5960Sstevel@tonic-gate /* XXX check also for unprintable chars? */
5970Sstevel@tonic-gate if (strpbrk(message, "\r\n") != NULL)
5980Sstevel@tonic-gate return MI_FAILURE;
5990Sstevel@tonic-gate ml = strlen(message);
6000Sstevel@tonic-gate if (ml > MAXREPLYLEN)
6010Sstevel@tonic-gate return MI_FAILURE;
6020Sstevel@tonic-gate len += ml + 1;
6030Sstevel@tonic-gate }
6040Sstevel@tonic-gate buf = malloc(len);
6050Sstevel@tonic-gate if (buf == NULL)
6060Sstevel@tonic-gate return MI_FAILURE; /* oops */
6070Sstevel@tonic-gate (void) sm_strlcpy(buf, rcode, len);
6080Sstevel@tonic-gate (void) sm_strlcat(buf, " ", len);
6090Sstevel@tonic-gate if (xcode != NULL)
6100Sstevel@tonic-gate (void) sm_strlcat(buf, xcode, len);
6110Sstevel@tonic-gate if (message != NULL)
6120Sstevel@tonic-gate {
6130Sstevel@tonic-gate if (xcode != NULL)
6140Sstevel@tonic-gate (void) sm_strlcat(buf, " ", len);
6150Sstevel@tonic-gate (void) sm_strlcat(buf, message, len);
6160Sstevel@tonic-gate }
6170Sstevel@tonic-gate if (ctx->ctx_reply != NULL)
6180Sstevel@tonic-gate free(ctx->ctx_reply);
6190Sstevel@tonic-gate ctx->ctx_reply = buf;
6200Sstevel@tonic-gate return MI_SUCCESS;
6210Sstevel@tonic-gate }
6220Sstevel@tonic-gate
6230Sstevel@tonic-gate /*
6240Sstevel@tonic-gate ** SMFI_SETMLREPLY -- set multiline reply code for the next reply to the MTA
6250Sstevel@tonic-gate **
6260Sstevel@tonic-gate ** Parameters:
6270Sstevel@tonic-gate ** ctx -- Opaque context structure
6280Sstevel@tonic-gate ** rcode -- The three-digit (RFC 821) SMTP reply code.
6290Sstevel@tonic-gate ** xcode -- The extended (RFC 2034) reply code.
6300Sstevel@tonic-gate ** txt, ... -- The text part of the SMTP reply,
6310Sstevel@tonic-gate ** MUST be terminated with NULL.
6320Sstevel@tonic-gate **
6330Sstevel@tonic-gate ** Returns:
6340Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE
6350Sstevel@tonic-gate */
6360Sstevel@tonic-gate
6370Sstevel@tonic-gate int
6380Sstevel@tonic-gate #if SM_VA_STD
smfi_setmlreply(SMFICTX * ctx,const char * rcode,const char * xcode,...)6390Sstevel@tonic-gate smfi_setmlreply(SMFICTX *ctx, const char *rcode, const char *xcode, ...)
6400Sstevel@tonic-gate #else /* SM_VA_STD */
6410Sstevel@tonic-gate smfi_setmlreply(ctx, rcode, xcode, va_alist)
6420Sstevel@tonic-gate SMFICTX *ctx;
6430Sstevel@tonic-gate const char *rcode;
6440Sstevel@tonic-gate const char *xcode;
6450Sstevel@tonic-gate va_dcl
6460Sstevel@tonic-gate #endif /* SM_VA_STD */
6470Sstevel@tonic-gate {
6480Sstevel@tonic-gate size_t len;
6490Sstevel@tonic-gate size_t rlen;
6500Sstevel@tonic-gate int args;
6510Sstevel@tonic-gate char *buf, *txt;
6520Sstevel@tonic-gate const char *xc;
6530Sstevel@tonic-gate char repl[16];
6540Sstevel@tonic-gate SM_VA_LOCAL_DECL
6550Sstevel@tonic-gate
6560Sstevel@tonic-gate if (rcode == NULL || ctx == NULL)
6570Sstevel@tonic-gate return MI_FAILURE;
6580Sstevel@tonic-gate
6590Sstevel@tonic-gate /* ### <sp> */
6600Sstevel@tonic-gate len = strlen(rcode) + 1;
6610Sstevel@tonic-gate if (len != 4)
6620Sstevel@tonic-gate return MI_FAILURE;
6630Sstevel@tonic-gate if ((rcode[0] != '4' && rcode[0] != '5') ||
6640Sstevel@tonic-gate !isascii(rcode[1]) || !isdigit(rcode[1]) ||
6650Sstevel@tonic-gate !isascii(rcode[2]) || !isdigit(rcode[2]))
6660Sstevel@tonic-gate return MI_FAILURE;
6670Sstevel@tonic-gate if (xcode != NULL)
6680Sstevel@tonic-gate {
6690Sstevel@tonic-gate if (!myisenhsc(xcode, '\0'))
6700Sstevel@tonic-gate return MI_FAILURE;
6710Sstevel@tonic-gate xc = xcode;
6720Sstevel@tonic-gate }
6730Sstevel@tonic-gate else
6740Sstevel@tonic-gate {
6750Sstevel@tonic-gate if (rcode[0] == '4')
6760Sstevel@tonic-gate xc = "4.0.0";
6770Sstevel@tonic-gate else
6780Sstevel@tonic-gate xc = "5.0.0";
6790Sstevel@tonic-gate }
6800Sstevel@tonic-gate
6810Sstevel@tonic-gate /* add trailing space */
6820Sstevel@tonic-gate len += strlen(xc) + 1;
6830Sstevel@tonic-gate rlen = len;
6840Sstevel@tonic-gate args = 0;
6850Sstevel@tonic-gate SM_VA_START(ap, xcode);
6860Sstevel@tonic-gate while ((txt = SM_VA_ARG(ap, char *)) != NULL)
6870Sstevel@tonic-gate {
6880Sstevel@tonic-gate size_t tl;
6890Sstevel@tonic-gate
6900Sstevel@tonic-gate tl = strlen(txt);
6910Sstevel@tonic-gate if (tl > MAXREPLYLEN)
6920Sstevel@tonic-gate break;
6930Sstevel@tonic-gate
6940Sstevel@tonic-gate /* this text, reply codes, \r\n */
6950Sstevel@tonic-gate len += tl + 2 + rlen;
6960Sstevel@tonic-gate if (++args > MAXREPLIES)
6970Sstevel@tonic-gate break;
6980Sstevel@tonic-gate
6990Sstevel@tonic-gate /* XXX check also for unprintable chars? */
7000Sstevel@tonic-gate if (strpbrk(txt, "\r\n") != NULL)
7010Sstevel@tonic-gate break;
7020Sstevel@tonic-gate }
7030Sstevel@tonic-gate SM_VA_END(ap);
7040Sstevel@tonic-gate if (txt != NULL)
7050Sstevel@tonic-gate return MI_FAILURE;
7060Sstevel@tonic-gate
7070Sstevel@tonic-gate /* trailing '\0' */
7080Sstevel@tonic-gate ++len;
7090Sstevel@tonic-gate buf = malloc(len);
7100Sstevel@tonic-gate if (buf == NULL)
7110Sstevel@tonic-gate return MI_FAILURE; /* oops */
7120Sstevel@tonic-gate (void) sm_strlcpyn(buf, len, 3, rcode, args == 1 ? " " : "-", xc);
7130Sstevel@tonic-gate (void) sm_strlcpyn(repl, sizeof repl, 4, rcode, args == 1 ? " " : "-",
7140Sstevel@tonic-gate xc, " ");
7150Sstevel@tonic-gate SM_VA_START(ap, xcode);
7160Sstevel@tonic-gate txt = SM_VA_ARG(ap, char *);
7170Sstevel@tonic-gate if (txt != NULL)
7180Sstevel@tonic-gate {
7190Sstevel@tonic-gate (void) sm_strlcat2(buf, " ", txt, len);
7200Sstevel@tonic-gate while ((txt = SM_VA_ARG(ap, char *)) != NULL)
7210Sstevel@tonic-gate {
7220Sstevel@tonic-gate if (--args <= 1)
7230Sstevel@tonic-gate repl[3] = ' ';
7240Sstevel@tonic-gate (void) sm_strlcat2(buf, "\r\n", repl, len);
7250Sstevel@tonic-gate (void) sm_strlcat(buf, txt, len);
7260Sstevel@tonic-gate }
7270Sstevel@tonic-gate }
7280Sstevel@tonic-gate if (ctx->ctx_reply != NULL)
7290Sstevel@tonic-gate free(ctx->ctx_reply);
7300Sstevel@tonic-gate ctx->ctx_reply = buf;
7310Sstevel@tonic-gate SM_VA_END(ap);
7320Sstevel@tonic-gate return MI_SUCCESS;
7330Sstevel@tonic-gate }
7340Sstevel@tonic-gate
7350Sstevel@tonic-gate /*
7360Sstevel@tonic-gate ** SMFI_SETPRIV -- set private data
7370Sstevel@tonic-gate **
7380Sstevel@tonic-gate ** Parameters:
7390Sstevel@tonic-gate ** ctx -- Opaque context structure
7400Sstevel@tonic-gate ** privatedata -- pointer to private data
7410Sstevel@tonic-gate **
7420Sstevel@tonic-gate ** Returns:
7430Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE
7440Sstevel@tonic-gate */
7450Sstevel@tonic-gate
7460Sstevel@tonic-gate int
smfi_setpriv(ctx,privatedata)7470Sstevel@tonic-gate smfi_setpriv(ctx, privatedata)
7480Sstevel@tonic-gate SMFICTX *ctx;
7490Sstevel@tonic-gate void *privatedata;
7500Sstevel@tonic-gate {
7510Sstevel@tonic-gate if (ctx == NULL)
7520Sstevel@tonic-gate return MI_FAILURE;
7530Sstevel@tonic-gate ctx->ctx_privdata = privatedata;
7540Sstevel@tonic-gate return MI_SUCCESS;
7550Sstevel@tonic-gate }
7560Sstevel@tonic-gate
7570Sstevel@tonic-gate /*
7580Sstevel@tonic-gate ** SMFI_GETPRIV -- get private data
7590Sstevel@tonic-gate **
7600Sstevel@tonic-gate ** Parameters:
7610Sstevel@tonic-gate ** ctx -- Opaque context structure
7620Sstevel@tonic-gate **
7630Sstevel@tonic-gate ** Returns:
7640Sstevel@tonic-gate ** pointer to private data
7650Sstevel@tonic-gate */
7660Sstevel@tonic-gate
7670Sstevel@tonic-gate void *
smfi_getpriv(ctx)7680Sstevel@tonic-gate smfi_getpriv(ctx)
7690Sstevel@tonic-gate SMFICTX *ctx;
7700Sstevel@tonic-gate {
7710Sstevel@tonic-gate if (ctx == NULL)
7720Sstevel@tonic-gate return NULL;
7730Sstevel@tonic-gate return ctx->ctx_privdata;
7740Sstevel@tonic-gate }
7750Sstevel@tonic-gate
7760Sstevel@tonic-gate /*
7770Sstevel@tonic-gate ** SMFI_GETSYMVAL -- get the value of a macro
7780Sstevel@tonic-gate **
7790Sstevel@tonic-gate ** See explanation in mfapi.h about layout of the structures.
7800Sstevel@tonic-gate **
7810Sstevel@tonic-gate ** Parameters:
7820Sstevel@tonic-gate ** ctx -- Opaque context structure
7830Sstevel@tonic-gate ** symname -- name of macro
7840Sstevel@tonic-gate **
7850Sstevel@tonic-gate ** Returns:
7860Sstevel@tonic-gate ** value of macro (NULL in case of failure)
7870Sstevel@tonic-gate */
7880Sstevel@tonic-gate
7890Sstevel@tonic-gate char *
smfi_getsymval(ctx,symname)7900Sstevel@tonic-gate smfi_getsymval(ctx, symname)
7910Sstevel@tonic-gate SMFICTX *ctx;
7920Sstevel@tonic-gate char *symname;
7930Sstevel@tonic-gate {
7940Sstevel@tonic-gate int i;
7950Sstevel@tonic-gate char **s;
7960Sstevel@tonic-gate char one[2];
7970Sstevel@tonic-gate char braces[4];
7980Sstevel@tonic-gate
7990Sstevel@tonic-gate if (ctx == NULL || symname == NULL || *symname == '\0')
8000Sstevel@tonic-gate return NULL;
8010Sstevel@tonic-gate
8020Sstevel@tonic-gate if (strlen(symname) == 3 && symname[0] == '{' && symname[2] == '}')
8030Sstevel@tonic-gate {
8040Sstevel@tonic-gate one[0] = symname[1];
8050Sstevel@tonic-gate one[1] = '\0';
8060Sstevel@tonic-gate }
8070Sstevel@tonic-gate else
8080Sstevel@tonic-gate one[0] = '\0';
8090Sstevel@tonic-gate if (strlen(symname) == 1)
8100Sstevel@tonic-gate {
8110Sstevel@tonic-gate braces[0] = '{';
8120Sstevel@tonic-gate braces[1] = *symname;
8130Sstevel@tonic-gate braces[2] = '}';
8140Sstevel@tonic-gate braces[3] = '\0';
8150Sstevel@tonic-gate }
8160Sstevel@tonic-gate else
8170Sstevel@tonic-gate braces[0] = '\0';
8180Sstevel@tonic-gate
8190Sstevel@tonic-gate /* search backwards through the macro array */
8200Sstevel@tonic-gate for (i = MAX_MACROS_ENTRIES - 1 ; i >= 0; --i)
8210Sstevel@tonic-gate {
8220Sstevel@tonic-gate if ((s = ctx->ctx_mac_ptr[i]) == NULL ||
8230Sstevel@tonic-gate ctx->ctx_mac_buf[i] == NULL)
8240Sstevel@tonic-gate continue;
8250Sstevel@tonic-gate while (s != NULL && *s != NULL)
8260Sstevel@tonic-gate {
8270Sstevel@tonic-gate if (strcmp(*s, symname) == 0)
8280Sstevel@tonic-gate return *++s;
8290Sstevel@tonic-gate if (one[0] != '\0' && strcmp(*s, one) == 0)
8300Sstevel@tonic-gate return *++s;
8310Sstevel@tonic-gate if (braces[0] != '\0' && strcmp(*s, braces) == 0)
8320Sstevel@tonic-gate return *++s;
8330Sstevel@tonic-gate ++s; /* skip over macro value */
8340Sstevel@tonic-gate ++s; /* points to next macro name */
8350Sstevel@tonic-gate }
8360Sstevel@tonic-gate }
8370Sstevel@tonic-gate return NULL;
8380Sstevel@tonic-gate }
8390Sstevel@tonic-gate
8400Sstevel@tonic-gate /*
8410Sstevel@tonic-gate ** SMFI_PROGRESS -- send "progress" message to the MTA to prevent premature
8420Sstevel@tonic-gate ** timeouts during long milter-side operations
8430Sstevel@tonic-gate **
8440Sstevel@tonic-gate ** Parameters:
8450Sstevel@tonic-gate ** ctx -- Opaque context structure
8460Sstevel@tonic-gate **
8470Sstevel@tonic-gate ** Return value:
8480Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE
8490Sstevel@tonic-gate */
8500Sstevel@tonic-gate
8510Sstevel@tonic-gate int
smfi_progress(ctx)8520Sstevel@tonic-gate smfi_progress(ctx)
8530Sstevel@tonic-gate SMFICTX *ctx;
8540Sstevel@tonic-gate {
8550Sstevel@tonic-gate struct timeval timeout;
8560Sstevel@tonic-gate
8570Sstevel@tonic-gate if (ctx == NULL)
8580Sstevel@tonic-gate return MI_FAILURE;
8590Sstevel@tonic-gate
8600Sstevel@tonic-gate timeout.tv_sec = ctx->ctx_timeout;
8610Sstevel@tonic-gate timeout.tv_usec = 0;
8620Sstevel@tonic-gate
8630Sstevel@tonic-gate return mi_wr_cmd(ctx->ctx_sd, &timeout, SMFIR_PROGRESS, NULL, 0);
8640Sstevel@tonic-gate }
8653544Sjbeck
8663544Sjbeck /*
8673544Sjbeck ** SMFI_VERSION -- return (runtime) version of libmilter
8683544Sjbeck **
8693544Sjbeck ** Parameters:
8703544Sjbeck ** major -- (pointer to) major version
8713544Sjbeck ** minor -- (pointer to) minor version
8723544Sjbeck ** patchlevel -- (pointer to) patchlevel version
8733544Sjbeck **
8743544Sjbeck ** Return value:
8753544Sjbeck ** MI_SUCCESS
8763544Sjbeck */
8773544Sjbeck
8783544Sjbeck int
smfi_version(major,minor,patchlevel)8793544Sjbeck smfi_version(major, minor, patchlevel)
8803544Sjbeck unsigned int *major;
8813544Sjbeck unsigned int *minor;
8823544Sjbeck unsigned int *patchlevel;
8833544Sjbeck {
8843544Sjbeck if (major != NULL)
8853544Sjbeck *major = SM_LM_VRS_MAJOR(SMFI_VERSION);
8863544Sjbeck if (minor != NULL)
8873544Sjbeck *minor = SM_LM_VRS_MINOR(SMFI_VERSION);
8883544Sjbeck if (patchlevel != NULL)
889*4518Sjbeck *patchlevel = SM_LM_VRS_PLVL(SMFI_VERSION);
8903544Sjbeck return MI_SUCCESS;
8913544Sjbeck }
892