Add pushtigertree.
[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     /* 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;