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