Use the HTTP library to fetch hublists.
[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 void aborthublist(void)
52 {
53     if(mybuf != NULL) {
54         free(mybuf);
55         mybuf = NULL;
56         mybufsize = mybufdata = 0;
57     }
58     if(hc != NULL) {
59         if(itag != -1)
60             gdk_input_remove(itag);
61         if(otag != -1)
62             gdk_input_remove(otag);
63         itag = otag = -1;
64         freehtconn(hc);
65         hc = NULL;
66         if(bzs != NULL) {
67             BZ2_bzDecompressEnd(bzs);
68             free(bzs);
69         }
70         if(filter != NULL) {
71             regfree(filter);
72             free(filter);
73             filter = NULL;
74         }
75         if(handler != NULL) {
76             handler(PHO_FINI, NULL, 0);
77             handler = NULL;
78         }
79     }
80 }
81
82 int validhub(char *field, ...)
83 {
84     int match;
85     va_list args;
86     
87     if(filter == NULL)
88         return(1);
89     match = 0;
90     va_start(args, field);
91     do {
92         if(!regexec(filter, field, 0, NULL, 0)) {
93             match = 1;
94             break;
95         }
96     } while((field = va_arg(args, char *)) != NULL);
97     va_end(args);
98     return(match);
99 }
100
101 static void fdcb(gpointer data, gint source, GdkInputCondition cond)
102 {
103     int ret, bzret, hret;
104     
105     if(itag != -1)
106         gdk_input_remove(itag);
107     if(otag != -1)
108         gdk_input_remove(otag);
109     itag = otag = -1;
110     ret = htprocess(hc, ((cond & GDK_INPUT_READ)?POLLIN:0) | ((cond & GDK_INPUT_WRITE)?POLLOUT:0));
111     if(ret < 0) {
112         msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Could not read hublist from server: %s"), strerror(errno));
113         aborthublist();
114         return;
115     }
116     if(state == 0) {
117         if(hc->rescode != 0) {
118             if(hc->rescode != 200) {
119                 msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("The hublist server returned an error: \"%i %s\""), hc->rescode, hc->resstr);
120                 aborthublist();
121                 return;
122             }
123             state = 1;
124         }
125     }
126     if(state == 1) {
127         if(hc->databufdata > 0) {
128             if(bzs == NULL) {
129                 bufcat(mybuf, hc->databuf, hc->databufdata);
130                 hc->databufdata = 0;
131             } else {
132                 bzs->next_in = hc->databuf;
133                 bzs->avail_in = hc->databufdata;
134                 do {
135                     sizebuf2(mybuf, mybufdata + 1024, 1);
136                     bzs->next_out = mybuf + mybufdata;
137                     bzs->avail_out = mybufsize - mybufdata;
138                     bzret = BZ2_bzDecompress(bzs);
139                     if((bzret != BZ_OK) && (bzret != BZ_STREAM_END)) {
140                         msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Could not decompress hublist (%i)"), hret);
141                         aborthublist();
142                         return;
143                     }
144                     mybufdata = mybufsize - bzs->avail_out;
145                     if(bzret == BZ_STREAM_END) {
146                         ret = 1;
147                         break;
148                     }
149                 } while(bzs->avail_out == 0);
150                 memmove(hc->databuf, bzs->next_in, hc->databufdata -= (bzs->next_in - hc->databuf));
151             }
152             if((hret = handler(PHO_DATA, mybuf, mybufdata)) < 0)
153                 aborthublist();
154             else
155                 memmove(mybuf, mybuf + hret, mybufdata -= hret);
156         }
157         if(ret) {
158             handler(PHO_EOF, NULL, 0);
159             aborthublist();
160         }
161     }
162     if(hc != NULL)
163         settags();
164 }
165
166 static void settags(void)
167 {
168     if(htpollflags(hc) & POLLIN)
169         itag = gdk_input_add(hc->fd, GDK_INPUT_READ, fdcb, NULL);
170     if(htpollflags(hc) & POLLOUT)
171         otag = gdk_input_add(hc->fd, GDK_INPUT_WRITE, fdcb, NULL);
172 }
173
174 void fetchhublist(char *url, regex_t *flt)
175 {
176     int len;
177     char *p;
178     struct hturlinfo *u;
179     
180     aborthublist();
181     filter = flt;
182     u = parseurl(url);
183     hc = htconnect(u);
184     freeurl(u);
185     state = 0;
186     settags();
187
188     len = strlen(url);
189     p = url + len;
190     if((len > 4) && !strncmp(p - 4, ".bz2", 4)) {
191         p -= 4;
192         len -= 4;
193         bzs = memset(smalloc(sizeof(*bzs)), 0, sizeof(*bzs));
194         if(BZ2_bzDecompressInit(bzs, 0, 0) != BZ_OK) {
195             msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Could not initialize decompression library"));
196             free(bzs);
197             bzs = NULL;
198             aborthublist();
199             return;
200         }
201     }
202     if((len > 4) && !strncmp(p - 4, ".xml", 4)) {
203         p -= 4;
204         len -= 4;
205         handler = pubhubxmlhandler;
206     } else {
207         handler = pubhuboldhandler;
208     }
209     handler(PHO_INIT, NULL, 0);
210 }