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