* Rewrite support for specific SSL encryption protocols, including
[alpine.git] / alpine / pattern.c
blobcd3b44f87212eb8183fa849f0c383c7163e2c148
1 #if !defined(lint) && !defined(DOS)
2 static char rcsid[] = "$Id: pattern.c 169 2006-10-04 23:26:48Z hubert@u.washington.edu $";
3 #endif
4 /*
5 * ========================================================================
6 * Copyright 2013-2018 Eduardo Chappa
7 * Copyright 2006-2007 University of Washington
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * ========================================================================
18 #include <system.h>
19 #include <general.h>
21 #include "../c-client/c-client.h"
23 #include "../pith/osdep/canaccess.h"
24 #include "../pith/osdep/color.h"
25 #include "../pith/osdep/pipe.h"
27 #include "../pith/charconv/utf8.h"
28 #include "../pith/charconv/filesys.h"
30 #include "../pith/status.h"
31 #include "../pith/pipe.h"
32 #include "../pith/debug.h"
33 #include "../pith/detach.h"
35 #include "pipe.h"
36 #include "pattern.h"
37 #include "signal.h"
40 /* Internal prototypes */
41 int test_message_with_cmd(MAILSTREAM *, long, char *, long, int *);
45 * pattern_filter_command - filter given message
47 void
48 pattern_filter_command(char **cat_cmds, SEARCHSET *srchset, MAILSTREAM *stream, long cat_lim, INTVL_S *cat)
50 char **l;
51 int exitval, i;
52 SEARCHSET *s;
53 MESSAGECACHE *mc;
54 char *cmd = NULL;
55 char *just_arg0 = NULL;
56 char *cmd_start, *cmd_end;
57 int just_one;
59 if(!(cat_cmds && cat_cmds[0]))
60 return;
62 just_one = !(cat_cmds[1]);
64 /* find the first command that exists on this host */
65 for(l = cat_cmds; l && *l; l++){
66 cmd = cpystr(*l);
67 removing_quotes(cmd);
68 if(cmd){
69 for(cmd_start = cmd;
70 *cmd_start && isspace(*cmd_start); cmd_start++)
73 for(cmd_end = cmd_start+1;
74 *cmd_end && !isspace(*cmd_end); cmd_end++)
77 just_arg0 = (char *) fs_get((cmd_end-cmd_start+1)
78 * sizeof(char));
79 strncpy(just_arg0, cmd_start, cmd_end - cmd_start);
80 just_arg0[cmd_end - cmd_start] = '\0';
83 if(valid_filter_command(&just_arg0))
84 break;
85 else{
86 if(just_one){
87 if(can_access(just_arg0, ACCESS_EXISTS) != 0)
88 q_status_message1(SM_ORDER, 0, 3,
89 "\"%s\" does not exist",
90 just_arg0);
91 else
92 q_status_message1(SM_ORDER, 0, 3,
93 "\"%s\" is not executable",
94 just_arg0);
97 if(just_arg0)
98 fs_give((void **) &just_arg0);
99 if(cmd)
100 fs_give((void **) &cmd);
104 if(!just_arg0 && !just_one)
105 q_status_message(SM_ORDER, 0, 3,
106 "None of the category cmds exists and is executable");
109 * If category_cmd isn't executable, it isn't a match.
111 if(!just_arg0 || !cmd){
113 * If we couldn't run the pipe command,
114 * we declare no match
116 for(s = srchset; s; s = s->next)
117 for(i = s->first; i <= s->last; i++)
118 if(i > 0L && stream && i <= stream->nmsgs
119 && (mc=mail_elt(stream, i)) && mc->searched)
120 mc->searched = NIL;
122 else
123 for(s = srchset; s; s = s->next)
124 for(i = s->first; i <= s->last; i++)
125 if(i > 0L && stream && i <= stream->nmsgs
126 && (mc=mail_elt(stream, i)) && mc->searched){
129 * If there was an error, or the exitval is out of
130 * range, then it is not a match.
131 * Default range is (0,0),
132 * which is right for matching
133 * bogofilter spam.
135 if(test_message_with_cmd(stream, i, cmd,
136 cat_lim, &exitval) != 0)
137 mc->searched = NIL;
139 /* test exitval */
140 if(mc->searched){
141 INTVL_S *iv;
143 if(cat){
144 for(iv = cat; iv; iv = iv->next)
145 if((long) exitval >= iv->imin
146 && (long) exitval <= iv->imax)
147 break;
149 if(!iv)
150 mc->searched = NIL; /* not in any interval */
152 else{
153 /* default to interval containing only zero */
154 if(exitval != 0)
155 mc->searched = NIL;
160 if(just_arg0)
161 fs_give((void **) &just_arg0);
163 if(cmd)
164 fs_give((void **) &cmd);
170 * Returns 0 if ok, -1 if not ok.
171 * If ok then exitval contains the exit value of the cmd.
174 test_message_with_cmd(MAILSTREAM *stream, long int msgno, char *cmd,
175 long char_limit, /* limit testing to this many chars from body */
176 int *exitval)
178 PIPE_S *tpipe;
179 gf_io_t pc;
180 int status = 0, flags, err = 0;
181 char *resultfile = NULL, *pipe_err;
183 if(cmd && cmd[0]){
185 flags = PIPE_WRITE | PIPE_NOSHELL | PIPE_STDERR | PIPE_NONEWMAIL;
187 dprint((7, "test_message_with_cmd(msgno=%ld cmd=%s)\n",
188 msgno, cmd));
190 if((tpipe = cmd_pipe_open(cmd, &resultfile, flags, &pc))){
192 prime_raw_pipe_getc(stream, msgno, char_limit, FT_PEEK);
193 gf_filter_init();
194 gf_link_filter(gf_nvtnl_local, NULL);
195 if((pipe_err = gf_pipe(raw_pipe_getc, pc)) != NULL){
196 q_status_message1(SM_ORDER|SM_DING, 3, 3,
197 "Internal Error: %.200s", pipe_err);
198 err++;
202 * Don't call new_mail in close_system_pipe because we're probably
203 * already here from new_mail and we don't want to get loopy.
205 status = close_system_pipe(&tpipe, exitval, pipe_callback);
208 * This is a place where the command can put its output, which we
209 * are not interested in.
211 if(resultfile){
212 our_unlink(resultfile);
213 fs_give((void **) &resultfile);
216 return((err || status) ? -1 : 0);
220 return(-1);