dd2c1cbdbf4e9740db7cfa81d227023a6a0da793
[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;
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, "bytes"))
123                     type = G_TYPE_INT64;
124             }
125             if((name != NULL) && (type != G_TYPE_INVALID))
126             {
127                 names = srealloc(names, (numcols + 1) * sizeof(*names));
128                 types = srealloc(types, (numcols + 1) * sizeof(*names));
129                 names[numcols] = sstrdup(name);
130                 types[numcols] = type;
131                 numcols++;
132             }
133             if(name != NULL)
134                 xmlFree(name);
135             if(stype != NULL)
136                 xmlFree(stype);
137         }
138         if(numcols == 0)
139         {
140             msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("The hub list did not contain any columns"));
141             break;
142         }
143         for(i = 0; i < numcols; i++)
144         {
145             if(!strcmp(names[i], "Address"))
146             {
147                 name = names[0];
148                 names[0] = names[i];
149                 names[i] = name;
150                 type = types[0];
151                 types[0] = types[i];
152                 types[i] = type;
153                 break;
154             }
155         }
156         if(i == numcols)
157         {
158             msgbox(GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("The hub list did not contain the address to any hubs"));
159             break;
160         }
161         model = gtk_list_store_newv(numcols, types);
162         for(n = findnode(r->children, "Hub"); n != NULL; n = findnode(n->next, "Hub"))
163         {
164             if(!xmlHasProp(n, (xmlChar *)"Address") || !xmlHasProp(n, (xmlChar *)"Name"))
165                 continue;
166             if(!checkvalid(n))
167                 continue;
168             gtk_list_store_append(model, &iter);
169             for(i = 0; i < numcols; i++)
170             {
171                 attr = (char *)xmlGetProp(n, (xmlChar *)names[i]);
172                 if(attr != NULL)
173                 {
174                     if(types[i] == G_TYPE_STRING)
175                         gtk_list_store_set(model, &iter, i, attr, -1);
176                     else if(types[i] == G_TYPE_INT)
177                         gtk_list_store_set(model, &iter, i, atoi(attr), -1);
178                     else if(types[i] == G_TYPE_INT64)
179                         gtk_list_store_set(model, &iter, i, strtoll(attr, NULL, 0), -1);
180                     xmlFree(attr);
181                 }
182             }
183         }
184         cols = smalloc((numcols - 1) * sizeof(*cols));
185         for(i = 1; i < numcols; i++)
186             cols[i - 1] = i;
187         sortcol = 0;
188         for(i = 0; i < numcols; i++)
189         {
190             if(!strcmp(names[i], "Users"))
191                 sortcol = i;
192         }
193         setpubhubmodel(GTK_TREE_MODEL(model), sortcol, numcols - 1, cols, names + 1);
194         free(cols);
195         g_object_unref(model);
196         break;
197     case PHO_FINI:
198         if(ctxt != NULL)
199         {
200             if(ctxt->myDoc != NULL)
201                 xmlFreeDoc(ctxt->myDoc);
202             xmlFreeParserCtxt(ctxt);
203             ctxt = NULL;
204         }
205         break;
206     }
207     if(numcols != 0)
208     {
209         for(i = 0; i < numcols; i++)
210             free(names[i]);
211         free(names);
212         free(types);
213     }
214     return(0);
215 }