e324a94c8f544d40e01ff7f8b1ceba44e8189da7
[apps/madmutt.git] / lib-sys / filter.c
1 /*
2  * Copyright notice from original mutt:
3  * Copyright (C) 1996-2000 Michael R. Elkins.
4  *
5  * This file is part of mutt-ng, see http://www.muttng.org/.
6  * It's licensed under the GNU General Public License,
7  * please see the file GPL in the top level source directory.
8  */
9
10 #if HAVE_CONFIG_H
11 # include "config.h"
12 #endif
13
14 #include <unistd.h>
15 #include <stdlib.h>
16 #include <sys/wait.h>
17 #include <stdio.h>
18
19 #include <lib-lib/lib-lib.h>
20
21 #include "mutt_signal.h"
22 #include "unix.h"
23
24 /* Invokes a commmand on a pipe and optionally connects its stdin and stdout
25  * to the specified handles.
26  */
27 pid_t
28 mutt_create_filter_fd (const char *cmd, FILE ** in, FILE ** out, FILE ** err,
29                        int fdin, int fdout, int fderr)
30 {
31   int pin[2], pout[2], perr[2], thepid;
32
33   if (in) {
34     *in = 0;
35     if (pipe (pin) == -1)
36       return (-1);
37   }
38
39   if (out) {
40     *out = 0;
41     if (pipe (pout) == -1) {
42       if (in) {
43         close (pin[0]);
44         close (pin[1]);
45       }
46       return (-1);
47     }
48   }
49
50   if (err) {
51     *err = 0;
52     if (pipe (perr) == -1) {
53       if (in) {
54         close (pin[0]);
55         close (pin[1]);
56       }
57       if (out) {
58         close (pout[0]);
59         close (pout[1]);
60       }
61       return (-1);
62     }
63   }
64
65   mutt_block_signals_system ();
66
67   if ((thepid = fork ()) == 0) {
68     mutt_unblock_signals_system (0);
69
70     if (in) {
71       close (pin[1]);
72       dup2 (pin[0], 0);
73       close (pin[0]);
74     }
75     else if (fdin != -1) {
76       dup2 (fdin, 0);
77       close (fdin);
78     }
79
80     if (out) {
81       close (pout[0]);
82       dup2 (pout[1], 1);
83       close (pout[1]);
84     }
85     else if (fdout != -1) {
86       dup2 (fdout, 1);
87       close (fdout);
88     }
89
90     if (err) {
91       close (perr[0]);
92       dup2 (perr[1], 2);
93       close (perr[1]);
94     }
95     else if (fderr != -1) {
96       dup2 (fderr, 2);
97       close (fderr);
98     }
99
100     execl ("/bin/sh", "sh", "-c", cmd, NULL);
101     _exit (127);
102   }
103   else if (thepid == -1) {
104     mutt_unblock_signals_system (1);
105
106     if (in) {
107       close (pin[0]);
108       close (pin[1]);
109     }
110
111     if (out) {
112       close (pout[0]);
113       close (pout[1]);
114     }
115
116     if (err) {
117       close (perr[0]);
118       close (perr[1]);
119     }
120
121     return (-1);
122   }
123
124   if (out) {
125     close (pout[1]);
126     *out = fdopen (pout[0], "r");
127   }
128
129   if (in) {
130     close (pin[0]);
131     *in = fdopen (pin[1], "w");
132   }
133
134   if (err) {
135     close (perr[1]);
136     *err = fdopen (perr[0], "r");
137   }
138
139   return (thepid);
140 }
141
142 pid_t mutt_create_filter (const char *s, FILE ** in, FILE ** out, FILE ** err)
143 {
144   return (mutt_create_filter_fd (s, in, out, err, -1, -1, -1));
145 }
146
147 int mutt_wait_filter (pid_t pid)
148 {
149   int rc;
150
151   waitpid (pid, &rc, 0);
152   mutt_unblock_signals_system (1);
153   rc = WIFEXITED (rc) ? WEXITSTATUS (rc) : -1;
154
155   return rc;
156 }
157
158 /* This function allows the user to specify a command to read stdout from in
159    place of a normal file.  If the last character in the string is a pipe (|),
160    then we assume it is a commmand to run instead of a normal file. */
161 FILE *mutt_open_read (const char *path, pid_t * thepid)
162 {
163     int len = m_strlen(path);
164     FILE *f;
165
166     if (path[len - 1] == '|') {
167         char *s = m_strdup(path);
168
169         /* read from a pipe */
170
171         s[len - 1] = 0;
172         mutt_endwin (NULL);
173         *thepid = mutt_create_filter (s, NULL, &f, NULL);
174         p_delete(&s);
175     } else {
176         f = fopen (path, "r");
177         if (!f)
178             return NULL;
179         *thepid = -1;
180     }
181
182     return (f);
183 }
184