Fixed hublist decompression error message bug.
[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             bzs = NULL;
73         }
74         if(filter != NULL) {
75             regfree(filter);
76             free(filter);
77             filter = NULL;
78         }
79         if(handler != NULL) {
80             handler(PHO_FINI, NULL, 0);
81             handler = NULL;
82         }
83     }
84 }
85
86 int validhub(char *field, ...)
87 {
88     int match;
89     va_list args;
90     
91     if(filter == NULL)
92         return(1);
93     match = 0;
94     va_start(args, field);
95     do {
96         if(!regexec(filter, field, 0, NULL, 0)) {
97             match = 1;
98             break;
99         }
100     } while((field = va_arg(args, char *)) != NULL);
101     va_end(args);
102     return(match);
103 }
104
105 static void fdcb(gpointer data, gint source, GdkInputCondition cond)
106 {
107     int ret, bzret, hret;
108     
109     if(itag != -1)
110         gdk_input_remove(itag);
111     if(otag != -1)
112         gdk_input_remove(otag);
113     itag = otag = -1;
114     ret = htprocess(hc, ((cond & GDK_INPUT_READ)?POLLIN:0) | ((cond & GDK_INPUT_WRITE)?POLLOUT:0));
115     if(ret < 0) {
116         msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Could not read hublist from server: %s"), strerror(errno));
117         aborthublist();
118         return;
119     }
120     if(state == 0) {
121         if(hc->rescode != 0) {
122             if(hc->rescode != 200) {
123                 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("The hublist server returned an error: \"%i %s\""), hc->rescode, hc->resstr);
124                 aborthublist();
125                 return;
126             }
127             state = 1;
128             gtk_progress_bar_set_text(GTK_PROGRESS_BAR(main_pubhubbar), _("Getting list..."));
129         }
130     }
131     if(state == 1) {
132         if(hc->tlen > 0) {
133             gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(main_pubhubbar), ((double)hc->rxd) / ((double)hc->tlen));
134         } else {
135             gtk_progress_bar_set_pulse_step(GTK_PROGRESS_BAR(main_pubhubbar), ((double)hc->databufdata) / 10000.0);
136             gtk_progress_bar_pulse(GTK_PROGRESS_BAR(main_pubhubbar));
137         }
138         if(hc->databufdata > 0) {
139             if(bzs == NULL) {
140                 bufcat(mybuf, hc->databuf, hc->databufdata);
141                 hc->databufdata = 0;
142             } else {
143                 bzs->next_in = hc->databuf;
144                 bzs->avail_in = hc->databufdata;
145                 do {
146                     sizebuf2(mybuf, mybufdata + 1024, 1);
147                     bzs->next_out = mybuf + mybufdata;
148                     bzs->avail_out = mybufsize - mybufdata;
149                     bzret = BZ2_bzDecompress(bzs);
150                     if((bzret != BZ_OK) && (bzret != BZ_STREAM_END)) {
151                         msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Could not decompress hublist (%i)"), bzret);
152                         aborthublist();
153                         return;
154                     }
155                     mybufdata = mybufsize - bzs->avail_out;
156                     if(bzret == BZ_STREAM_END) {
157                         ret = 1;
158                         break;
159                     }
160                 } while(bzs->avail_out == 0);
161                 memmove(hc->databuf, bzs->next_in, hc->databufdata -= (bzs->next_in - hc->databuf));
162             }
163             if((hret = handler(PHO_DATA, mybuf, mybufdata)) < 0)
164                 aborthublist();
165             else
166                 memmove(mybuf, mybuf + hret, mybufdata -= hret);
167         }
168         if(ret) {
169             gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(main_pubhubbar), 1);
170             gtk_progress_bar_set_text(GTK_PROGRESS_BAR(main_pubhubbar), _("Finalizing list..."));
171             gdk_window_process_updates(main_pubhubbar->window, FALSE);
172             handler(PHO_EOF, NULL, 0);
173             aborthublist();
174         }
175     }
176     if(hc != NULL)
177         settags();
178 }
179
180 static void settags(void)
181 {
182     if(htpollflags(hc) & POLLIN)
183         itag = gdk_input_add(hc->fd, GDK_INPUT_READ, fdcb, NULL);
184     if(htpollflags(hc) & POLLOUT)
185         otag = gdk_input_add(hc->fd, GDK_INPUT_WRITE, fdcb, NULL);
186 }
187
188 void fetchhublist(char *url, regex_t *flt)
189 {
190     int len;
191     char *p;
192     struct hturlinfo *u;
193     
194     aborthublist();
195     filter = flt;
196     u = parseurl(url);
197     hc = htconnect(u);
198     freeurl(u);
199     if(hc == NULL) {
200         msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Could not read hublist from server: %s"), strerror(errno));
201         return;
202     }
203     hc->autoredir = 1;
204     state = 0;
205     settags();
206     gtk_widget_show(main_pubhubbarbox);
207     gtk_progress_bar_set_text(GTK_PROGRESS_BAR(main_pubhubbar), _("Connecting..."));
208     gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(main_pubhubbar), 0);
209     gdk_window_process_updates(main_pubhubbarbox->window, TRUE);
210
211     len = strlen(url);
212     p = url + len;
213     if((len > 4) && !strncmp(p - 4, ".bz2", 4)) {
214         /* Because using Transfer-Encoding would just be too good! */
215         p -= 4;
216         len -= 4;
217         bzs = memset(smalloc(sizeof(*bzs)), 0, sizeof(*bzs));
218         if(BZ2_bzDecompressInit(bzs, 0, 0) != BZ_OK) {
219             msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Could not initialize decompression library"));
220             free(bzs);
221             bzs = NULL;
222             aborthublist();
223             return;
224         }
225     }
226     if((len > 4) && !strncmp(p - 4, ".xml", 4)) {
227         /* Because using Content-Type would just be too good! */
228         p -= 4;
229         len -= 4;
230         handler = pubhubxmlhandler;
231     } else {
232         handler = pubhuboldhandler;
233     }
234     handler(PHO_INIT, NULL, 0);
235 }