Strip dchub:// prefix from XML hublists.
[doldaconnect.git] / clients / gtk2 / hublist-xml.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 <string.h>
22 #include <doldaconnect/utils.h>
23 #include <gtk/gtk.h>
24
25 /* "Programming with libxml2 is like the thrilling embrace of an
26  * exotic strangler."
27  *    --Me */
28 #include <libxml/parser.h>
29 #include <libxml/tree.h>
30
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif
34 #include "dolcon.h"
35 #include "hublist.h"
36
37 static xmlNodePtr findnode(xmlNodePtr node, char *name)
38 {
39     for(; node != NULL; node = node->next)
40     {
41         if(!strcmp((char *)node->name, name))
42             break;
43     }
44     return(node);
45 }
46
47 static int checkvalid(xmlNodePtr n)
48 {
49     int match;
50     char *name, *descr;
51     
52     name = (char *)xmlGetProp(n, (xmlChar *)"Name");
53     descr = (char *)xmlGetProp(n, (xmlChar *)"Description");
54     match = validhub(name, descr, NULL);
55     xmlFree(name);
56     if(descr != NULL)
57         xmlFree(descr);
58     return(match);
59 }
60
61 int pubhubxmlhandler(int op, char *buf, size_t len)
62 {
63     static xmlParserCtxtPtr ctxt = NULL;
64     int i, o;
65     xmlNodePtr dr, r, cr, c, n;
66     int numcols, *cols, sortcol;
67     GType type, *types;
68     char **names, *name, *stype, *attr;
69     GtkListStore *model;
70     GtkTreeIter iter;
71     
72     numcols = 0;
73     names = NULL;
74     types = NULL;
75     switch(op)
76     {
77     case PHO_INIT:
78         break;
79     case PHO_DATA:
80         if(ctxt == NULL) {
81             ctxt = xmlCreatePushParserCtxt(NULL, NULL, buf, len, NULL);
82             if(ctxt == NULL)
83                 return(-1);
84         } else {
85             xmlParseChunk(ctxt, buf, len, 0);
86         }
87         return(len);
88     case PHO_EOF:
89         if(ctxt == NULL)
90         {
91             msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("A hub list could not be read from the server"));
92             break;
93         }
94         xmlParseChunk(ctxt, NULL, 0, 1);
95         if(!ctxt->wellFormed)
96         {
97             msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("The hub list is not valid"));
98             break;
99         }
100         dr = r = cr = NULL;
101         dr = xmlDocGetRootElement(ctxt->myDoc);
102         if(dr != NULL)
103             r = findnode(dr->children, "Hubs");
104         if(r != NULL)
105             cr = findnode(r->children, "Columns");
106         if(cr == NULL)
107         {
108             msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("The hub list cannot be understood"));
109             break;
110         }
111         for(c = findnode(cr->children, "Column"); c != NULL; c = findnode(c->next, "Column"))
112         {
113             name = (char *)xmlGetProp(c, (xmlChar *)"Name");
114             stype = (char *)xmlGetProp(c, (xmlChar *)"Type");
115             type = G_TYPE_INVALID;
116             if(stype != NULL)
117             {
118                 if(!strcmp(stype, "string"))
119                     type = G_TYPE_STRING;
120                 else if(!strcmp(stype, "int"))
121                     type = G_TYPE_INT;
122                 else if(!strcmp(stype, "percent"))
123                     type = G_TYPE_INT;
124                 else if(!strcmp(stype, "bytes"))
125                     type = G_TYPE_INT64;
126             }
127             if((name != NULL) && (type != G_TYPE_INVALID))
128             {
129                 names = srealloc(names, (numcols + 1) * sizeof(*names));
130                 types = srealloc(types, (numcols + 1) * sizeof(*names));
131                 names[numcols] = sstrdup(name);
132                 types[numcols] = type;
133                 numcols++;
134             }
135             if(name != NULL)
136                 xmlFree(name);
137             if(stype != NULL)
138                 xmlFree(stype);
139         }
140         if(numcols == 0)
141         {
142             msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("The hub list did not contain any columns"));
143             break;
144         }
145         for(i = 0; i < numcols; i++)
146         {
147             if(!strcasecmp(names[i], "Address"))
148             {
149                 for(o = i; o > 0; o--) {
150                     name = names[o];
151                     type = types[o];
152                     names[o] = names[o - 1];
153                     types[o] = types[o - 1];
154                     names[o - 1] = name;
155                     types[o - 1] = type;
156                 }
157                 break;
158             }
159         }
160         if(i == numcols)
161         {
162             msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("The hub list did not contain the address to any hubs"));
163             break;
164         }
165         model = gtk_list_store_newv(numcols, types);
166         for(n = findnode(r->children, "Hub"); n != NULL; n = findnode(n->next, "Hub"))
167         {
168             if(!xmlHasProp(n, (xmlChar *)"Address") || !xmlHasProp(n, (xmlChar *)"Name"))
169                 continue;
170             if(!checkvalid(n))
171                 continue;
172             gtk_list_store_append(model, &iter);
173             for(i = 0; i < numcols; i++)
174             {
175                 attr = (char *)xmlGetProp(n, (xmlChar *)names[i]);
176                 if(attr != NULL)
177                 {
178                     if(!strcmp(names[i], "Address")) {
179                         if(!strncmp(attr, "dchub://", 8))
180                             gtk_list_store_set(model, &iter, i, attr + 8, -1);
181                         else
182                             gtk_list_store_set(model, &iter, i, attr, -1);
183                     } else if(types[i] == G_TYPE_STRING) {
184                         gtk_list_store_set(model, &iter, i, attr, -1);
185                     } else if(types[i] == G_TYPE_INT) {
186                         gtk_list_store_set(model, &iter, i, atoi(attr), -1);
187                     } else if(types[i] == G_TYPE_INT64) {
188                         gtk_list_store_set(model, &iter, i, strtoll(attr, NULL, 0), -1);
189                     }
190                     xmlFree(attr);
191                 }
192             }
193         }
194         cols = smalloc((numcols - 1) * sizeof(*cols));
195         for(i = 1; i < numcols; i++)
196             cols[i - 1] = i;
197         sortcol = 0;
198         for(i = 0; i < numcols; i++)
199         {
200             if(!strcmp(names[i], "Users"))
201                 sortcol = i;
202         }
203         setpubhubmodel(GTK_TREE_MODEL(model), sortcol, numcols - 1, cols, names + 1);
204         free(cols);
205         g_object_unref(model);
206         break;
207     case PHO_FINI:
208         if(ctxt != NULL)
209         {
210             if(ctxt->myDoc != NULL)
211                 xmlFreeDoc(ctxt->myDoc);
212             xmlFreeParserCtxt(ctxt);
213             ctxt = NULL;
214         }
215         break;
216     }
217     if(numcols != 0)
218     {
219         for(i = 0; i < numcols; i++)
220             free(names[i]);
221         free(names);
222         free(types);
223     }
224     return(0);
225 }