Optionally install baseconv.
[doldaconnect.git] / clients / gnome-trans-applet / conduit-pipe.c
1 #ifdef HAVE_CONFIG_H
2 #include <config.h>
3 #endif
4 #include <string.h>
5 #include <unistd.h>
6 #include <stdlib.h>
7 #include <stdio.h>
8 #include <errno.h>
9 #include <signal.h>
10 #include <fcntl.h>
11 #include <panel-applet.h>
12 #include <doldaconnect/utils.h>
13
14 #include "conduit.h"
15
16 #define SUBPROCCMD "ksu fredrik -q -e /home/fredrik/bin/dctrmon"
17
18 struct data
19 {
20     pid_t subproc;
21     int fd;
22     int gdktag;
23     char *inbuf;
24     size_t inbufsize, inbufdata;
25 };
26
27 static void pipefdcb(struct conduit *conduit, int fd, GdkInputCondition condition)
28 {
29     struct data *data;
30     int ret;
31     char *p, *p2, *cmd;
32     char **args;
33     size_t argssize, argsdata;
34     struct transfer *transfer;
35     
36     data = (struct data *)conduit->cdata;
37     if(conduit->state == CNDS_SYN)
38         condconnected(conduit);
39     sizebuf2(data->inbuf, data->inbufdata + 80, 1);
40     ret = read(data->fd, data->inbuf + data->inbufdata, data->inbufsize - data->inbufdata);
41     if(ret < 0)
42     {
43         if((errno == EINTR) || (errno == EAGAIN)) /* Shouldn't happen, but, oh well... */
44             return;
45         perror("conduit-pipe: read");
46         gdk_input_remove(data->gdktag);
47         close(data->fd);
48         kill(-data->subproc, SIGHUP);
49         data->gdktag = -1;
50         data->fd = -1;
51         data->subproc = 0;
52         conddisconn(conduit);
53     }
54     if(ret == 0)
55     {
56         gdk_input_remove(data->gdktag);
57         close(data->fd);
58         kill(-data->subproc, SIGHUP);
59         data->gdktag = -1;
60         data->fd = -1;
61         data->subproc = 0;
62         conddisconn(conduit);
63     }
64     data->inbufdata += ret;
65     while((p = memchr(data->inbuf, '\n', data->inbufdata)) != NULL)
66     {
67         *p = 0;
68         cmd = sstrdup(data->inbuf);
69         memmove(data->inbuf, p + 1, data->inbufdata -= (p - data->inbuf) + 1);
70         args = NULL;
71         argssize = argsdata = 0;
72         p = cmd;
73         do
74         {
75             if((p2 = strchr(p, '\t')) != NULL)
76                 *(p2++) = 0;
77             addtobuf(args, p);
78             p = p2;
79         } while(p2 != NULL);
80         if(!strcmp(args[0], "N") && (argsdata >= 4))
81         {
82             transfer = newtransfer(conduit, args[1], atoi(args[2]), atoi(args[3]));
83         }
84         if(!strcmp(args[0], "D") && (argsdata >= 2))
85         {
86             if((transfer = findtransferbytag(conduit, args[1])) != NULL)
87                 freetransfer(transfer);
88         }
89         if(!strcmp(args[0], "S") && (argsdata >= 3))
90         {
91             if((transfer = findtransferbytag(conduit, args[1])) != NULL)
92                 transfersetsize(transfer, atoi(args[2]));
93         }
94         if(!strcmp(args[0], "P") && (argsdata >= 3))
95         {
96             if((transfer = findtransferbytag(conduit, args[1])) != NULL)
97                 transfersetpos(transfer, atoi(args[2]));
98         }
99         free(args);
100         free(cmd);
101     }
102 }
103
104 static int init(struct conduit *conduit)
105 {
106     static int inited = 0;
107     struct data *data;
108     
109     if(!inited)
110     {
111         signal(SIGCHLD, SIG_IGN);
112         inited = 1;
113     }
114     data = smalloc(sizeof(*data));
115     memset(data, 0, sizeof(*data));
116     data->fd = -1;
117     data->inbuf = NULL;
118     data->inbufsize = data->inbufdata = 0;
119     data->gdktag = -1;
120     conduit->cdata = data;
121     return(0);
122 }
123
124 static int connect(struct conduit *conduit)
125 {
126     struct data *data;
127     pid_t pid;
128     int pfd[2];
129     
130     data = conduit->cdata;
131     if(pipe(pfd))
132         return(-1);
133     if((pid = fork()) < 0)
134     {
135         close(pfd[0]);
136         close(pfd[1]);
137         return(-1);
138     }
139     if(!pid)
140     {
141         int devnull;
142         
143         setpgrp();
144         if((devnull = open("/dev/null", O_RDWR)) < 0)
145             exit(127);
146         close(pfd[0]);
147         dup2(pfd[1], 1);
148         close(pfd[1]);
149         dup2(devnull, 0);
150         close(devnull);
151         /* Leave stderr as is */
152         execl("/bin/sh", "sh", "-c", SUBPROCCMD, NULL);
153         exit(127);
154     }
155     close(pfd[1]);
156     fcntl(pfd[0], F_SETFL, fcntl(pfd[0], F_GETFL) | O_NONBLOCK);
157     data->subproc = pid;
158     data->fd = pfd[0];
159     data->gdktag = gdk_input_add(pfd[0], GDK_INPUT_READ, (void (*)(gpointer, gint, GdkInputCondition))pipefdcb, conduit);
160     data->inbufdata = 0;
161     return(0);
162 }
163
164 static void destroy(struct conduit *conduit)
165 {
166     struct data *data;
167     
168     data = conduit->cdata;
169     if(data == NULL)
170         return;
171     if(data->gdktag >= 0)
172         gdk_input_remove(data->gdktag);
173     if(data->subproc > 0)
174         kill(-data->subproc, SIGHUP);
175     if(data->fd >= 0)
176         close(data->fd);
177     if(data->inbuf != NULL)
178         free(data->inbuf);
179     free(data);
180     conduit->cdata = NULL;
181 }
182
183 static struct conduitiface st_conduit_pipe =
184 {
185     .init = init,
186     .connect = connect,
187     .destroy = destroy,
188 };
189
190 struct conduitiface *conduit_pipe = &st_conduit_pipe;