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 | |
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); |
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 | |
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; |
0931eb36 |
144 | dc_queuecmd(lstrargcb, dt, L"lstrarg", L"%i", dt->id, NULL); |
d3372da9 |
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 | { |
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 | |
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; |
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 | |
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 | |
6431aca0 |
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 | { |
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 |
322 | static struct conduitiface st_conduit_dclib = |
323 | { |
324 | .init = init, |
325 | .connect = connect, |
326 | .destroy = destroy, |
6431aca0 |
327 | .cancel = cancel, |
d3372da9 |
328 | }; |
329 | |
330 | struct conduitiface *conduit_dclib = &st_conduit_dclib; |