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); |
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 | |
97 | static 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 | |
110 | static 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 | |
136 | static 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 | |
148 | static 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 | |
164 | static 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 | |
180 | static 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 | { |
198 | if(resp->code == 200) |
199 | { |
200 | dc_loginasync(NULL, 1, noconv, (void (*)(int, wchar_t *, void *))logincb, conduit); |
201 | } else { |
202 | dc_disconnect(); |
203 | disconnected(conduit); |
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 | |
255 | static 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 | |
273 | static int connect(struct conduit *conduit) |
274 | { |
275 | struct data *data; |
276 | char *host; |
277 | |
278 | data = conduit->cdata; |
279 | if(inuse != NULL) |
280 | return(-1); |
281 | if((host = getenv("DCSERVER")) == NULL) |
282 | host = "localhost"; |
283 | if((data->fd = dc_connect(host, -1)) < 0) |
284 | return(-1); |
285 | data->gdkread = gdk_input_add(data->fd, GDK_INPUT_READ, (void (*)(gpointer, int, GdkInputCondition))dcfdcb, conduit); |
286 | updatewrite(conduit); |
287 | inuse = conduit; |
288 | return(0); |
289 | } |
290 | |
291 | static void destroy(struct conduit *conduit) |
292 | { |
293 | struct data *data; |
294 | |
295 | data = conduit->cdata; |
296 | if(data->gdkread != -1) |
297 | gdk_input_remove(data->gdkread); |
298 | if(data->gdkwrite != -1) |
299 | gdk_input_remove(data->gdkwrite); |
300 | if(data->fd >= 0) |
301 | dc_disconnect(); |
302 | if(inuse == conduit) |
303 | inuse = NULL; |
304 | free(data); |
305 | } |
306 | |
307 | static struct conduitiface st_conduit_dclib = |
308 | { |
309 | .init = init, |
310 | .connect = connect, |
311 | .destroy = destroy, |
312 | }; |
313 | |
314 | struct conduitiface *conduit_dclib = &st_conduit_dclib; |