Understand new connect stanza.
[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);
87 /* XXX: Achtung! Too DC-specific! */
88 if((p = strrchr(mbspath, '\\')) == NULL)
89 p = mbspath;
90 else
91 p++;
92 buf = sstrdup(p);
93 free(mbspath);
94 return(buf);
95}
96
97static void dtfreecb(struct dc_transfer *dt)
98{
99 struct dtdata *dtd;
100
101 if((dtd = dt->udata) == NULL)
102 return;
103 if(dtd->ct != NULL)
104 freetransfer(dtd->ct);
105 if(dtd->tag != NULL)
106 free(dtd->tag);
107 free(dtd);
108}
109
110static int lstrargcb(struct dc_response *resp)
111{
112 struct dc_transfer *dt;
113 struct dtdata *dtd;
114 struct dc_intresp *ires;
115
116 dt = resp->data;
117 dtd = dt->udata;
118 if(resp->code == 200)
119 {
120 while((dtd->tag == NULL) && ((ires = dc_interpret(resp)) != NULL))
121 {
122 if(!wcscmp(ires->argv[0].val.str, L"tag"))
123 {
124 dtd->realtag = 1;
125 dtd->tag = icwcstombs(ires->argv[1].val.str, "UTF-8");
126 }
127 dc_freeires(ires);
128 }
129 }
130 if(dtd->tag == NULL)
131 dtd->tag = gettag(dt);
132 dtd->ct = newtransfer(dtd->conduit, dtd->tag, dt->size, dt->curpos);
133 return(1);
134}
135
136static void inittrans(struct conduit *conduit, struct dc_transfer *dt)
137{
138 struct dtdata *dtd;
139
140 dtd = smalloc(sizeof(*dtd));
141 memset(dtd, 0, sizeof(*dtd));
142 dtd->conduit = conduit;
143 dt->udata = dtd;
144 dt->destroycb = dtfreecb;
145 dc_queuecmd(lstrargcb, dt, L"lstrarg", L"%%i", dt->id, NULL);
146}
147
148static void trlistcb(int resp, struct conduit *conduit)
149{
150 struct data *data;
151 struct dc_transfer *dt;
152
153 data = conduit->cdata;
154 if(resp != 200)
155 return;
156 for(dt = dc_transfers; dt != NULL; dt = dt->next)
157 {
158 if(dt->dir != DC_TRNSD_DOWN)
159 continue;
160 inittrans(conduit, dt);
161 }
162}
163
164static void logincb(int err, wchar_t *reason, struct conduit *conduit)
165{
166 struct data *data;
167
168 data = conduit->cdata;
169 if(err != DC_LOGIN_ERR_SUCCESS)
170 {
171 dc_disconnect();
172 disconnected(conduit);
173 return;
174 }
175 condconnected(conduit);
176 dc_gettrlistasync((void (*)(int, void *))trlistcb, conduit);
177 dc_queuecmd(NULL, NULL, L"notify", L"trans:act", L"on", L"trans:prog", L"on", NULL);
178}
179
180static void dcfdcb(struct conduit *conduit, int fd, GdkInputCondition condition)
181{
182 struct data *data;
183 struct dc_response *resp;
184 struct dc_intresp *ires;
185 struct dc_transfer *dt;
186 struct dtdata *dtd;
187
188 data = conduit->cdata;
189 if(((condition & GDK_INPUT_READ) && dc_handleread()) || ((condition & GDK_INPUT_WRITE) && dc_handlewrite()))
190 {
191 disconnected(conduit);
192 return;
193 }
194 while((resp = dc_getresp()) != NULL)
195 {
196 if(!wcscmp(resp->cmdname, L".connect"))
197 {
5e1e52f1 198 if(dc_checkprotocol(resp, DC_LATEST))
d3372da9 199 {
d3372da9 200 dc_disconnect();
201 disconnected(conduit);
5e1e52f1 202 } else {
203 dc_loginasync(NULL, 1, noconv, (void (*)(int, wchar_t *, void *))logincb, conduit);
d3372da9 204 }
205 } else if(!wcscmp(resp->cmdname, L".notify")) {
206 dc_uimisc_handlenotify(resp);
207 switch(resp->code)
208 {
209 case 610:
210 if((ires = dc_interpret(resp)) != NULL)
211 {
212 if((dt = dc_findtransfer(ires->argv[0].val.num)) != NULL)
213 {
214 if(dt->dir == DC_TRNSD_DOWN)
215 inittrans(conduit, dt);
216 }
217 dc_freeires(ires);
218 }
219 break;
220 case 613:
221 if((ires = dc_interpret(resp)) != NULL)
222 {
223 if((dt = dc_findtransfer(ires->argv[0].val.num)) != NULL)
224 {
225 if(((dtd = dt->udata) != NULL) && (dtd->ct != NULL))
226 {
227 if(dtd->ct->size != dt->size)
228 transfersetsize(dtd->ct, dt->size);
229 }
230 }
231 dc_freeires(ires);
232 }
233 break;
234 case 615:
235 if((ires = dc_interpret(resp)) != NULL)
236 {
237 if((dt = dc_findtransfer(ires->argv[0].val.num)) != NULL)
238 {
239 if(((dtd = dt->udata) != NULL) && (dtd->ct != NULL))
240 {
241 if(dtd->ct->pos != dt->curpos)
242 transfersetpos(dtd->ct, dt->curpos);
243 }
244 }
245 dc_freeires(ires);
246 }
247 break;
248 }
249 }
250 dc_freeresp(resp);
251 }
252 updatewrite(conduit);
253}
254
255static int init(struct conduit *conduit)
256{
257 static int inited = 0;
258 struct data *data;
259
260 if(!inited)
261 {
262 dc_init();
263 inited = 1;
264 }
265 data = smalloc(sizeof(*data));
266 memset(data, 0, sizeof(*data));
267 data->fd = -1;
268 data->gdkread = data->gdkwrite = -1;
269 conduit->cdata = data;
270 return(0);
271}
272
273static int connect(struct conduit *conduit)
274{
275 struct data *data;
d3372da9 276
277 data = conduit->cdata;
278 if(inuse != NULL)
279 return(-1);
65bf229b 280 if((data->fd = dc_connect(NULL)) < 0)
d3372da9 281 return(-1);
282 data->gdkread = gdk_input_add(data->fd, GDK_INPUT_READ, (void (*)(gpointer, int, GdkInputCondition))dcfdcb, conduit);
283 updatewrite(conduit);
284 inuse = conduit;
285 return(0);
286}
287
288static void destroy(struct conduit *conduit)
289{
290 struct data *data;
291
292 data = conduit->cdata;
293 if(data->gdkread != -1)
294 gdk_input_remove(data->gdkread);
295 if(data->gdkwrite != -1)
296 gdk_input_remove(data->gdkwrite);
297 if(data->fd >= 0)
298 dc_disconnect();
299 if(inuse == conduit)
300 inuse = NULL;
301 free(data);
302}
303
6431aca0 304static int cancel(struct conduit *conduit, struct transfer *transfer)
305{
306 struct data *data;
307 struct dtdata *dtd;
308 struct dc_transfer *dt;
309
310 data = conduit->cdata;
311 for(dt = dc_transfers; dt != NULL; dt = dt->next)
312 {
313 if(((dtd = dt->udata) != NULL) && (dtd->ct == transfer))
314 {
315 dc_queuecmd(NULL, NULL, L"cancel", L"%%i", dt->id, NULL);
316 return(0);
317 }
318 }
319 errno = -ESRCH;
320 return(-1);
321}
322
d3372da9 323static struct conduitiface st_conduit_dclib =
324{
325 .init = init,
326 .connect = connect,
327 .destroy = destroy,
6431aca0 328 .cancel = cancel,
d3372da9 329};
330
331struct conduitiface *conduit_dclib = &st_conduit_dclib;