Made remote paths deconstructible
[doldaconnect.git] / clients / gnome-trans-applet / conduit-dclib.c
CommitLineData
d3372da9 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
15struct data
16{
17 int fd;
18 int gdkread, gdkwrite;
19};
20
21struct dtdata
22{
23 struct conduit *conduit;
24 struct transfer *ct;
25 char *tag;
26 int realtag;
27};
28
29static struct conduit *inuse = NULL;
30
31static void dcfdcb(struct conduit *conduit, int fd, GdkInputCondition condition);
32
33static 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
53static 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
74static int noconv(int type, wchar_t *text, char **resp, void *data)
75{
76 return(1);
77}
78
79static 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);
040118de 87 if((p = strrchr(mbspath, '/')) == NULL)
d3372da9 88 p = mbspath;
89 else
90 p++;
91 buf = sstrdup(p);
92 free(mbspath);
93 return(buf);
94}
95
96static 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
109static 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
135static 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;
0931eb36 144 dc_queuecmd(lstrargcb, dt, L"lstrarg", L"%i", dt->id, NULL);
d3372da9 145}
146
147static 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
163static 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
179static 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 {
5e1e52f1 197 if(dc_checkprotocol(resp, DC_LATEST))
d3372da9 198 {
d3372da9 199 dc_disconnect();
200 disconnected(conduit);
5e1e52f1 201 } else {
202 dc_loginasync(NULL, 1, noconv, (void (*)(int, wchar_t *, void *))logincb, conduit);
d3372da9 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
254static 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
272static int connect(struct conduit *conduit)
273{
274 struct data *data;
d3372da9 275
276 data = conduit->cdata;
277 if(inuse != NULL)
278 return(-1);
65bf229b 279 if((data->fd = dc_connect(NULL)) < 0)
d3372da9 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
287static 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
6431aca0 303static 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 {
0931eb36 314 dc_queuecmd(NULL, NULL, L"cancel", L"%i", dt->id, NULL);
6431aca0 315 return(0);
316 }
317 }
318 errno = -ESRCH;
319 return(-1);
320}
321
d3372da9 322static struct conduitiface st_conduit_dclib =
323{
324 .init = init,
325 .connect = connect,
326 .destroy = destroy,
6431aca0 327 .cancel = cancel,
d3372da9 328};
329
330struct conduitiface *conduit_dclib = &st_conduit_dclib;