Added progress bar for hublist fetching.
[doldaconnect.git] / clients / gtk2 / hublist.c
1 /*
2  *  Dolda Connect - Modular multiuser Direct Connect-style client
3  *  Copyright (C) 2007 Fredrik Tolf (fredrik@dolda2000.com)
4  *  
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *  
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *  
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <unistd.h>
23 #include <regex.h>
24 #include <signal.h>
25 #include <string.h>
26 #include <stdarg.h>
27 #include <gtk/gtk.h>
28 #include <bzlib.h>
29 #include <errno.h>
30 #include <sys/poll.h>
31
32 #ifdef HAVE_CONFIG_H
33 #include <config.h>
34 #endif
35 #include "dolcon.h"
36 #include "hublist.h"
37 #include <http.h>
38
39 static void settags(void);
40
41 static regex_t *filter = NULL;
42 static int itag = -1, otag = -1;
43 static int (*handler)(int, char *, size_t) = NULL;
44 static int state;
45 static struct htconn *hc;
46 static bz_stream *bzs;
47 /* Only needed because of bzlib: */
48 static char *mybuf;
49 static size_t mybufsize, mybufdata;
50
51 #include "mainwnd.gtkh"
52
53 void aborthublist(void)
54 {
55     if(mybuf != NULL) {
56         free(mybuf);
57         mybuf = NULL;
58         mybufsize = mybufdata = 0;
59     }
60     if(hc != NULL) {
61         gtk_widget_hide(main_pubhubbarbox);
62         if(itag != -1)
63             gdk_input_remove(itag);
64         if(otag != -1)
65             gdk_input_remove(otag);
66         itag = otag = -1;
67         freehtconn(hc);
68         hc = NULL;
69         if(bzs != NULL) {
70             BZ2_bzDecompressEnd(bzs);
71             free(bzs);
72         }
73         if(filter != NULL) {
74             regfree(filter);
75             free(filter);
76             filter = NULL;
77         }
78         if(handler != NULL) {
79             handler(PHO_FINI, NULL, 0);
80             handler = NULL;
81         }
82     }
83 }
84
85 int validhub(char *field, ...)
86 {
87     int match;
88     va_list args;
89     
90     if(filter == NULL)
91         return(1);
92     match = 0;
93     va_start(args, field);
94     do {
95         if(!regexec(filter, field, 0, NULL, 0)) {
96             match = 1;
97             break;
98         }
99     } while((field = va_arg(args, char *)) != NULL);
100     va_end(args);
101     return(match);
102 }
103
104 static void fdcb(gpointer data, gint source, GdkInputCondition cond)
105 {
106     int ret, bzret, hret;
107     
108     if(itag != -1)
109         gdk_input_remove(itag);
110     if(otag != -1)
111         gdk_input_remove(otag);
112     itag = otag = -1;
113     ret = htprocess(hc, ((cond & GDK_INPUT_READ)?POLLIN:0) | ((cond & GDK_INPUT_WRITE)?POLLOUT:0));
114     if(ret < 0) {
115         msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Could not read hublist from server: %s"), strerror(errno));
116         aborthublist();
117         return;
118     }
119     if(state == 0) {
120         if(hc->rescode != 0) {
121             if(hc->rescode != 200) {
122                 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("The hublist server returned an error: \"%i %s\""), hc->rescode, hc->resstr);
123                 aborthublist();
124                 return;
125             }
126             state = 1;
127             gtk_progress_bar_set_text(GTK_PROGRESS_BAR(main_pubhubbar), _("Getting list..."));
128         }
129     }
130     if(state == 1) {
131         if(hc->tlen > 0) {
132             gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(main_pubhubbar), ((double)hc->rxd) / ((double)hc->tlen));
133         } else {
134             gtk_progress_bar_set_pulse_step(GTK_PROGRESS_BAR(main_pubhubbar), ((double)hc->databufdata) / 10000.0);
135             gtk_progress_bar_pulse(GTK_PROGRESS_BAR(main_pubhubbar));
136         }
137         if(hc->databufdata > 0) {
138             if(bzs == NULL) {
139                 bufcat(mybuf, hc->databuf, hc->databufdata);
140                 hc->databufdata = 0;
141             } else {
142                 bzs->next_in = hc->databuf;
143                 bzs->avail_in = hc->databufdata;
144                 do {
145                     sizebuf2(mybuf, mybufdata + 1024, 1);
146                     bzs->next_out = mybuf + mybufdata;
147                     bzs->avail_out = mybufsize - mybufdata;
148                     bzret = BZ2_bzDecompress(bzs);
149                     if((bzret != BZ_OK) && (bzret != BZ_STREAM_END)) {
150                         msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Could not decompress hublist (%i)"), hret);
151                         aborthublist();
152                         return;
153                     }
154                     mybufdata = mybufsize - bzs->avail_out;
155                     if(bzret == BZ_STREAM_END) {
156                         ret = 1;
157                         break;
158                     }
159                 } while(bzs->avail_out == 0);
160                 memmove(hc->databuf, bzs->next_in, hc->databufdata -= (bzs->next_in - hc->databuf));
161             }
162             if((hret = handler(PHO_DATA, mybuf, mybufdata)) < 0)
163                 aborthublist();
164             else
165                 memmove(mybuf, mybuf + hret, mybufdata -= hret);
166         }
167         if(ret) {
168             gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(main_pubhubbar), 1);
169             gtk_progress_bar_set_text(GTK_PROGRESS_BAR(main_pubhubbar), _("Finalizing list..."));
170             gdk_window_process_updates(main_pubhubbar->window, FALSE);
171             handler(PHO_EOF, NULL, 0);
172             aborthublist();
173         }
174     }
175     if(hc != NULL)
176         settags();
177 }
178
179 static void settags(void)
180 {
181     if(htpollflags(hc) & POLLIN)
182         itag = gdk_input_add(hc->fd, GDK_INPUT_READ, fdcb, NULL);
183     if(htpollflags(hc) & POLLOUT)
184         otag = gdk_input_add(hc->fd, GDK_INPUT_WRITE, fdcb, NULL);
185 }
186
187 void fetchhublist(char *url, regex_t *flt)
188 {
189     int len;
190     char *p;
191     struct hturlinfo *u;
192     
193     aborthublist();
194     filter = flt;
195     u = parseurl(url);
196     hc = htconnect(u);
197     freeurl(u);
198     state = 0;
199     settags();
200     gtk_widget_show(main_pubhubbarbox);
201     gtk_progress_bar_set_text(GTK_PROGRESS_BAR(main_pubhubbar), _("Connecting..."));
202     gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(main_pubhubbar), 0);
203     gdk_window_process_updates(main_pubhubbarbox->window, TRUE);
204
205     len = strlen(url);
206     p = url + len;
207     if((len > 4) && !strncmp(p - 4, ".bz2", 4)) {
208         p -= 4;
209         len -= 4;
210         bzs = memset(smalloc(sizeof(*bzs)), 0, sizeof(*bzs));
211         if(BZ2_bzDecompressInit(bzs, 0, 0) != BZ_OK) {
212             msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Could not initialize decompression library"));
213             free(bzs);
214             bzs = NULL;
215             aborthublist();
216             return;
217         }
218     }
219     if((len > 4) && !strncmp(p - 4, ".xml", 4)) {
220         p -= 4;
221         len -= 4;
222         handler = pubhubxmlhandler;
223     } else {
224         handler = pubhuboldhandler;
225     }
226     handler(PHO_INIT, NULL, 0);
227 }