Fixed HTTP-client query-string handling bug.
[doldaconnect.git] / clients / gnome-trans-applet / conduit-dclib.c
1 #ifdef HAVE_CONFIG_H
2 #include <config.h>
3 #endif
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <string.h>
7 #include <errno.h>
8 #include <panel-applet.h>
9 #include <doldaconnect/uilib.h>
10 #include <doldaconnect/uimisc.h>
11 #include <doldaconnect/utils.h>
12
13 #include "conduit.h"
14
15 struct data
16 {
17     int fd;
18     int gdkread, gdkwrite;
19 };
20
21 struct dtdata
22 {
23     struct conduit *conduit;
24     struct transfer *ct;
25     char *tag;
26     int realtag;
27 };
28
29 static struct conduit *inuse = NULL;
30
31 static void dcfdcb(struct conduit *conduit, int fd, GdkInputCondition condition);
32
33 static void updatewrite(struct conduit *conduit)
34 {
35     struct data *data;
36     
37     data = conduit->cdata;
38     if(data->fd < 0)
39         return;
40     if(dc_wantwrite())
41     {
42         if(data->gdkwrite == -1)
43             data->gdkwrite = gdk_input_add(data->fd, GDK_INPUT_WRITE, (void (*)(gpointer, int, GdkInputCondition))dcfdcb, conduit);
44     } else {
45         if(data->gdkwrite != -1)
46         {
47             gdk_input_remove(data->gdkwrite);
48             data->gdkwrite = -1;
49         }
50     }
51 }
52
53 static void disconnected(struct conduit *conduit)
54 {
55     struct data *data;
56     
57     data = conduit->cdata;
58     if(inuse == conduit)
59         inuse = NULL;
60     if(data->gdkread != -1)
61     {
62         gdk_input_remove(data->gdkread);
63         data->gdkread = -1;
64     }
65     if(data->gdkwrite != -1)
66     {
67         gdk_input_remove(data->gdkwrite);
68         data->gdkwrite = -1;
69     }
70     data->fd = -1;
71     conddisconn(conduit);
72 }
73
74 static int noconv(int type, wchar_t *text, char **resp, void *data)
75 {
76     return(1);
77 }
78
79 static char *gettag(struct dc_transfer *dt)
80 {
81     char *mbspath, *p, *buf;
82     
83     if(dt->path == NULL)
84         return(NULL);
85     if((mbspath = icwcstombs(dt->path, "UTF-8")) == NULL)
86         return(NULL);
87     if((p = strrchr(mbspath, '/')) == NULL)
88         p = mbspath;
89     else
90         p++;
91     buf = sstrdup(p);
92     free(mbspath);
93     return(buf);
94 }
95
96 static void dtfreecb(struct dc_transfer *dt)
97 {
98     struct dtdata *dtd;
99     
100     if((dtd = dt->udata) == NULL)
101         return;
102     if(dtd->ct != NULL)
103         freetransfer(dtd->ct);
104     if(dtd->tag != NULL)
105         free(dtd->tag);
106     free(dtd);
107 }
108
109 static int lstrargcb(struct dc_response *resp)
110 {
111     struct dc_transfer *dt;
112     struct dtdata *dtd;
113     struct dc_intresp *ires;
114     
115     dt = resp->data;
116     dtd = dt->udata;
117     if(resp->code == 200)
118     {
119         while((dtd->tag == NULL) && ((ires = dc_interpret(resp)) != NULL))
120         {
121             if(!wcscmp(ires->argv[0].val.str, L"tag"))
122             {
123                 dtd->realtag = 1;
124                 dtd->tag = icwcstombs(ires->argv[1].val.str, "UTF-8");
125             }
126             dc_freeires(ires);
127         }
128     }
129     if(dtd->tag == NULL)
130         dtd->tag = gettag(dt);
131     dtd->ct = newtransfer(dtd->conduit, dtd->tag, dt->size, dt->curpos);
132     return(1);
133 }
134
135 static void inittrans(struct conduit *conduit, struct dc_transfer *dt)
136 {
137     struct dtdata *dtd;
138
139     dtd = smalloc(sizeof(*dtd));
140     memset(dtd, 0, sizeof(*dtd));
141     dtd->conduit = conduit;
142     dt->udata = dtd;
143     dt->destroycb = dtfreecb;
144     dc_queuecmd(lstrargcb, dt, L"lstrarg", L"%i", dt->id, NULL);
145 }
146
147 static void trlistcb(int resp, struct conduit *conduit)
148 {
149     struct data *data;
150     struct dc_transfer *dt;
151     
152     data = conduit->cdata;
153     if(resp != 200)
154         return;
155     for(dt = dc_transfers; dt != NULL; dt = dt->next)
156     {
157         if(dt->dir != DC_TRNSD_DOWN)
158             continue;
159         inittrans(conduit, dt);
160     }
161 }
162
163 static void logincb(int err, wchar_t *reason, struct conduit *conduit)
164 {
165     struct data *data;
166     
167     data = conduit->cdata;
168     if(err != DC_LOGIN_ERR_SUCCESS)
169     {
170         dc_disconnect();
171         disconnected(conduit);
172         return;
173     }
174     condconnected(conduit);
175     dc_gettrlistasync((void (*)(int, void *))trlistcb, conduit);
176     dc_queuecmd(NULL, NULL, L"notify", L"trans:act", L"on", L"trans:prog", L"on", NULL);
177 }
178
179 static void dcfdcb(struct conduit *conduit, int fd, GdkInputCondition condition)
180 {
181     struct data *data;
182     struct dc_response *resp;
183     struct dc_intresp *ires;
184     struct dc_transfer *dt;
185     struct dtdata *dtd;
186     
187     data = conduit->cdata;
188     if(((condition & GDK_INPUT_READ) && dc_handleread()) || ((condition & GDK_INPUT_WRITE) && dc_handlewrite()))
189     {
190         disconnected(conduit);
191         return;
192     }
193     while((resp = dc_getresp()) != NULL)
194     {
195         if(!wcscmp(resp->cmdname, L".connect"))
196         {
197             if(dc_checkprotocol(resp, DC_LATEST))
198             {
199                 dc_disconnect();
200                 disconnected(conduit);
201             } else {
202                 dc_loginasync(NULL, 1, noconv, (void (*)(int, wchar_t *, void *))logincb, conduit);
203             }
204         } else if(!wcscmp(resp->cmdname, L".notify")) {
205             dc_uimisc_handlenotify(resp);
206             switch(resp->code)
207             {
208             case 610:
209                 if((ires = dc_interpret(resp)) != NULL)
210                 {
211                     if((dt = dc_findtransfer(ires->argv[0].val.num)) != NULL)
212                     {
213                         if(dt->dir == DC_TRNSD_DOWN)
214                             inittrans(conduit, dt);
215                     }
216                     dc_freeires(ires);
217                 }
218                 break;
219             case 613:
220                 if((ires = dc_interpret(resp)) != NULL)
221                 {
222                     if((dt = dc_findtransfer(ires->argv[0].val.num)) != NULL)
223                     {
224                         if(((dtd = dt->udata) != NULL) && (dtd->ct != NULL))
225                         {
226                             if(dtd->ct->size != dt->size)
227                                 transfersetsize(dtd->ct, dt->size);
228                         }
229                     }
230                     dc_freeires(ires);
231                 }
232                 break;
233             case 615:
234                 if((ires = dc_interpret(resp)) != NULL)
235                 {
236                     if((dt = dc_findtransfer(ires->argv[0].val.num)) != NULL)
237                     {
238                         if(((dtd = dt->udata) != NULL) && (dtd->ct != NULL))
239                         {
240                             if(dtd->ct->pos != dt->curpos)
241                                 transfersetpos(dtd->ct, dt->curpos);
242                         }
243                     }
244                     dc_freeires(ires);
245                 }
246                 break;
247             }
248         }
249         dc_freeresp(resp);
250     }
251     updatewrite(conduit);
252 }
253
254 static int init(struct conduit *conduit)
255 {
256     static int inited = 0;
257     struct data *data;
258     
259     if(!inited)
260     {
261         dc_init();
262         inited = 1;
263     }
264     data = smalloc(sizeof(*data));
265     memset(data, 0, sizeof(*data));
266     data->fd = -1;
267     data->gdkread = data->gdkwrite = -1;
268     conduit->cdata = data;
269     return(0);
270 }
271
272 static int connect(struct conduit *conduit)
273 {
274     struct data *data;
275     
276     data = conduit->cdata;
277     if(inuse != NULL)
278         return(-1);
279     if((data->fd = dc_connect(NULL)) < 0)
280         return(-1);
281     data->gdkread = gdk_input_add(data->fd, GDK_INPUT_READ, (void (*)(gpointer, int, GdkInputCondition))dcfdcb, conduit);
282     updatewrite(conduit);
283     inuse = conduit;
284     return(0);
285 }
286
287 static void destroy(struct conduit *conduit)
288 {
289     struct data *data;
290     
291     data = conduit->cdata;
292     if(data->gdkread != -1)
293         gdk_input_remove(data->gdkread);
294     if(data->gdkwrite != -1)
295         gdk_input_remove(data->gdkwrite);
296     if(data->fd >= 0)
297         dc_disconnect();
298     if(inuse == conduit)
299         inuse = NULL;
300     free(data);
301 }
302
303 static int cancel(struct conduit *conduit, struct transfer *transfer)
304 {
305     struct data *data;
306     struct dtdata *dtd;
307     struct dc_transfer *dt;
308     
309     data = conduit->cdata;
310     for(dt = dc_transfers; dt != NULL; dt = dt->next)
311     {
312         if(((dtd = dt->udata) != NULL) && (dtd->ct == transfer))
313         {
314             dc_queuecmd(NULL, NULL, L"cancel", L"%i", dt->id, NULL);
315             return(0);
316         }
317     }
318     errno = -ESRCH;
319     return(-1);
320 }
321
322 static struct conduitiface st_conduit_dclib =
323 {
324     .init = init,
325     .connect = connect,
326     .destroy = destroy,
327     .cancel = cancel,
328 };
329
330 struct conduitiface *conduit_dclib = &st_conduit_dclib;