7391a99175da91eadb96867f38c1989b51468bd2
[apps/madmutt.git] / filter.c
1 /*
2  * Copyright (C) 1996-2000 Michael R. Elkins.
3  * 
4  *     This program is free software; you can redistribute it and/or modify
5  *     it under the terms of the GNU General Public License as published by
6  *     the Free Software Foundation; either version 2 of the License, or
7  *     (at your option) any later version.
8  * 
9  *     This program is distributed in the hope that it will be useful,
10  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *     GNU General Public License for more details.
13  * 
14  *     You should have received a copy of the GNU General Public License
15  *     along with this program; if not, write to the Free Software
16  *     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
17  */
18
19 #if HAVE_CONFIG_H
20 # include "config.h"
21 #endif
22
23 #include "mutt.h"
24
25 #include <unistd.h>
26 #include <stdlib.h>
27 #include <sys/wait.h>
28
29 /* Invokes a commmand on a pipe and optionally connects its stdin and stdout
30  * to the specified handles.
31  */
32 pid_t
33 mutt_create_filter_fd (const char *cmd, FILE ** in, FILE ** out, FILE ** err,
34                        int fdin, int fdout, int fderr)
35 {
36   int pin[2], pout[2], perr[2], thepid;
37
38   if (in) {
39     *in = 0;
40     if (pipe (pin) == -1)
41       return (-1);
42   }
43
44   if (out) {
45     *out = 0;
46     if (pipe (pout) == -1) {
47       if (in) {
48         close (pin[0]);
49         close (pin[1]);
50       }
51       return (-1);
52     }
53   }
54
55   if (err) {
56     *err = 0;
57     if (pipe (perr) == -1) {
58       if (in) {
59         close (pin[0]);
60         close (pin[1]);
61       }
62       if (out) {
63         close (pout[0]);
64         close (pout[1]);
65       }
66       return (-1);
67     }
68   }
69
70   mutt_block_signals_system ();
71
72   if ((thepid = fork ()) == 0) {
73     mutt_unblock_signals_system (0);
74
75     if (in) {
76       close (pin[1]);
77       dup2 (pin[0], 0);
78       close (pin[0]);
79     }
80     else if (fdin != -1) {
81       dup2 (fdin, 0);
82       close (fdin);
83     }
84
85     if (out) {
86       close (pout[0]);
87       dup2 (pout[1], 1);
88       close (pout[1]);
89     }
90     else if (fdout != -1) {
91       dup2 (fdout, 1);
92       close (fdout);
93     }
94
95     if (err) {
96       close (perr[0]);
97       dup2 (perr[1], 2);
98       close (perr[1]);
99     }
100     else if (fderr != -1) {
101       dup2 (fderr, 2);
102       close (fderr);
103     }
104
105     execl (EXECSHELL, "sh", "-c", cmd, NULL);
106     _exit (127);
107   }
108   else if (thepid == -1) {
109     mutt_unblock_signals_system (1);
110
111     if (in) {
112       close (pin[0]);
113       close (pin[1]);
114     }
115
116     if (out) {
117       close (pout[0]);
118       close (pout[1]);
119     }
120
121     if (err) {
122       close (perr[0]);
123       close (perr[1]);
124     }
125
126     return (-1);
127   }
128
129   if (out) {
130     close (pout[1]);
131     *out = fdopen (pout[0], "r");
132   }
133
134   if (in) {
135     close (pin[0]);
136     *in = fdopen (pin[1], "w");
137   }
138
139   if (err) {
140     close (perr[1]);
141     *err = fdopen (perr[0], "r");
142   }
143
144   return (thepid);
145 }
146
147 pid_t mutt_create_filter (const char *s, FILE ** in, FILE ** out, FILE ** err)
148 {
149   return (mutt_create_filter_fd (s, in, out, err, -1, -1, -1));
150 }
151
152 int mutt_wait_filter (pid_t pid)
153 {
154   int rc;
155
156   waitpid (pid, &rc, 0);
157   mutt_unblock_signals_system (1);
158   rc = WIFEXITED (rc) ? WEXITSTATUS (rc) : -1;
159
160   return rc;
161 }