1 /* logjam - a GTK client for LiveJournal.
2 * Copyright (C) 2000-2003 Evan Martin <evan@livejournal.com>
4 * vim: tabstop=4 shiftwidth=4 noexpandtab :
7 #include <libxml/parser.h>
8 #include <libxml/tree.h>
14 #include <stdlib.h> /* atoi */
19 /* XXX win32 gross hack. why does the normal xmlFree cause segfaults? */
21 #define xmlFree(x) g_free(x)
24 #define xmlGetString jam_xmlGetString
25 #define xmlAddTN(node, name, value) xmlNewTextChild(node, NULL, BAD_CAST name, BAD_CAST value)
28 ljxmlAddTxt(xmlNodePtr node, char *name, char *val) {
30 return xmlNewTextChild(node, NULL, name, val);
35 conf_parsedirlist(const char *base
, void* (*fn
)(const char*, void*), void *arg
) {
42 dir
= g_dir_open(base
, 0, NULL
);
46 dirname
= g_dir_read_name(dir
);
48 path
= g_build_filename(base
, dirname
, NULL
);
51 list
= g_slist_append(list
, data
);
53 dirname
= g_dir_read_name(dir
);
61 conf_parsedirxml(const char *dirname
, void* (*fn
)(xmlDocPtr
, xmlNodePtr
, void*), void *data
) {
67 path
= g_build_filename(dirname
, "conf.xml", NULL
);
69 if (!g_file_test(path
, G_FILE_TEST_EXISTS
)) {
74 doc
= xmlParseFile(path
);
77 fprintf(stderr
, _("error parsing configuration file.\n"));
81 /* we get the root element instead of the doc's first child
82 * because XML allows comments outside of the root element. */
83 node
= xmlDocGetRootElement(doc
);
85 fprintf(stderr
, _("empty document.\n"));
90 ret
= fn(doc
, node
, data
);
97 /* we use a bunch of macro magic to make this simpler.
101 /* this should match the enum in conf.h */
102 static char* geometry_names
[] = {
115 parsegeometry(Geometry
*geom
, xmlDocPtr doc
, xmlNodePtr node
) {
116 for (node
= node
->xmlChildrenNode
; node
!= NULL
; node
= node
->next
) {
117 XML_GET_INT("x", geom
->x
)
118 XML_GET_INT("y", geom
->y
)
119 XML_GET_INT("width", geom
->width
)
120 XML_GET_INT("height", geom
->height
)
121 XML_GET_INT("panedpos", geom
->panedpos
)
122 XML_GET_END("parsegeometry")
127 parsegeometries(Configuration
*c
, xmlDocPtr doc
, xmlNodePtr node
) {
130 for (node
= node
->xmlChildrenNode
; node
!= NULL
; node
= node
->next
) {
131 if (xmlStrcmp(node
->name
, BAD_CAST
"geometry") == 0) {
132 window
= xmlGetProp(node
, BAD_CAST
"window");
133 if (!window
) continue;
135 for (i
= 0; i
< GEOM_COUNT
; i
++) {
136 if (g_ascii_strcasecmp((char*)window
, geometry_names
[i
]) == 0) {
137 parsegeometry(&c
->geometries
[i
], doc
, node
);
147 parsehostdir(const char *dirname
, void *data
) {
148 return conf_parsedirxml(dirname
, (conf_parsedirxml_fn
)jam_host_from_xml
, (void*)dirname
);
151 parsehostsdir(char *base
) {
152 return conf_parsedirlist(base
, parsehostdir
, NULL
);
157 parseshowmeta(Options
*options
, xmlDocPtr doc
, xmlNodePtr node
) {
159 for (node
= node
->xmlChildrenNode
; node
!= NULL
; node
= node
->next
) {
160 if (jam_view_meta_from_name((char*)node
->name
, &meta
))
161 options
->showmeta
[meta
] = TRUE
;
164 #endif /* HAVE_GTK */
167 parseoptions(Configuration
*c
, xmlDocPtr doc
, xmlNodePtr node
) {
168 Options
*options
= &c
->options
;
170 #define READOPTION(x) XML_GET_BOOL(#x, options->x)
171 for (node
= node
->xmlChildrenNode
; node
!= NULL
; node
= node
->next
) {
175 READOPTION(useproxyauth
)
178 READOPTION(usespellcheck
)
180 READOPTION(revertusejournal
)
182 READOPTION(cfautostart
)
183 READOPTION(cfusemask
)
186 READOPTION(cffloatraise
)
187 READOPTION(friends_hidestats
)
188 READOPTION(allowmultipleinstances
)
189 READOPTION(smartquotes
)
190 READOPTION(smartquotes_russian
)
192 XML_GET_IF("showmeta", parseshowmeta(options
, doc
, node
);)
194 /* backward compatibility. */
195 XML_GET_BOOL("cfautofloat", options
->cffloat
)
196 XML_GET_BOOL("cfautofloatraise", options
->cffloatraise
)
197 #endif /* HAVE_GTK */
198 XML_GET_END("parseoptions")
203 parsesecurity(Configuration
*c
, xmlDocPtr doc
, xmlNodePtr node
) {
205 typestr
= xmlGetProp(node
, BAD_CAST
"type");
206 if (!typestr
) return;
207 lj_security_from_strings(&c
->defaultsecurity
, (char*)typestr
, NULL
);
213 parsequietdlgs(xmlDocPtr doc
, xmlNodePtr node
) {
214 GSList
*quiet_dlgs
= NULL
;
215 for (node
= node
->xmlChildrenNode
; node
!= NULL
; node
= node
->next
) {
216 XML_GET_LIST("quiet_dlg", quiet_dlgs
, xmlGetString
)
217 XML_GET_END("parsequietdlgs")
221 #endif /* HAVE_GTK */
225 parseproxyauth(Configuration
*c
, xmlDocPtr doc
, xmlNodePtr node
) {
226 for (node
= node
->xmlChildrenNode
; node
!= NULL
; node
= node
->next
) {
227 XML_GET_STR("username", c
->proxyuser
)
228 XML_GET_STR("password", c
->proxypass
)
229 XML_GET_END("parseproxyauth")
235 parseconf(xmlDocPtr doc
, xmlNodePtr node
, void *data
) {
236 char *hostname
= NULL
;
238 Configuration
*c
= data
;
240 #define XML_GET_CONF(key, func) XML_GET_IF(key, func(c, doc, node);)
241 node
= node
->xmlChildrenNode
;
242 for (; node
!= NULL
; node
= node
->next
) {
243 XML_GET_STR("currentserver", hostname
)
244 XML_GET_CONF("geometries", parsegeometries
)
245 XML_GET_CONF("options", parseoptions
)
246 XML_GET_CONF("defaultsecurity", parsesecurity
)
247 XML_GET_STR("uifont", c
->uifont
)
249 XML_GET_STR("spell_language", c
->spell_language
)
250 #endif /* HAVE_GTKSPELL */
252 XML_GET_STR("proxy", c
->proxy
)
253 XML_GET_CONF("proxyauth", parseproxyauth
)
254 XML_GET_STR("spawncommand", c
->spawn_command
)
255 XML_GET_STR("musiccommand", c
->music_command
)
256 #endif /* G_OS_WIN32 */
257 XML_GET_INT("cfuserinterval", c
->cfuserinterval
)
258 XML_GET_INT("cfthreshold", c
->cfthreshold
)
260 XML_GET_FUNC("quiet_dlgs", app
.quiet_dlgs
, parsequietdlgs
)
262 XML_GET_END("conf_xml_read")
266 if (!c
->spell_language
|| strlen(c
->spell_language
) < 2) {
267 g_free(c
->spell_language
);
268 c
->spell_language
= g_strdup("en");
270 #endif /* HAVE_GTKSPELL */
271 hostspath
= g_build_filename(app
.conf_dir
, "servers", NULL
);
272 c
->hosts
= parsehostsdir(hostspath
);
276 c
->lasthost
= conf_host_by_name(c
, hostname
);
283 conf_read(Configuration
*c
, char *path
) {
284 conf_parsedirxml(path
, parseconf
, c
);
289 writegeometry(Geometry
*geometry
, char *name
, xmlNodePtr node
) {
290 node
= xmlNewChild(node
, NULL
, BAD_CAST
"geometry", NULL
);
291 xmlSetProp(node
, BAD_CAST
"window", BAD_CAST name
);
292 jam_xmlAddInt(node
, "x", geometry
->x
);
293 jam_xmlAddInt(node
, "y", geometry
->y
);
294 jam_xmlAddInt(node
, "width", geometry
->width
);
295 jam_xmlAddInt(node
, "height", geometry
->height
);
296 if (geometry
->panedpos
> 0)
297 jam_xmlAddInt(node
, "panedpos", geometry
->panedpos
);
302 writeshowmeta(Options
*options
, xmlNodePtr node
) {
303 xmlNodePtr showmeta
= xmlNewChild(node
, NULL
, BAD_CAST
"showmeta", NULL
);
305 for (i
= JAM_VIEW_META_FIRST
; i
<= JAM_VIEW_META_LAST
; i
++) {
306 if (options
->showmeta
[i
])
307 xmlNewChild(showmeta
, NULL
, BAD_CAST
jam_view_meta_to_name(i
), NULL
);
310 #endif /* HAVE_GTK */
313 writeoptions(Options
*options
, xmlNodePtr node
) {
314 #define WRITEOPTION(x) if (options->x) xmlNewChild(node, NULL, BAD_CAST #x, NULL);
315 WRITEOPTION(netdump
);
317 WRITEOPTION(useproxy
);
318 WRITEOPTION(useproxyauth
);
321 WRITEOPTION(usespellcheck
);
323 WRITEOPTION(revertusejournal
);
324 WRITEOPTION(autosave
);
325 WRITEOPTION(cfautostart
);
326 WRITEOPTION(cfusemask
);
327 WRITEOPTION(docklet
);
328 WRITEOPTION(cffloatraise
);
329 WRITEOPTION(cffloat
);
330 WRITEOPTION(friends_hidestats
);
331 WRITEOPTION(allowmultipleinstances
);
332 WRITEOPTION(smartquotes
);
333 WRITEOPTION(smartquotes_russian
);
335 writeshowmeta(options
, node
);
336 #endif /* HAVE_GTK */
340 conf_write(Configuration
*c
, char *base
) {
343 xmlNodePtr root
, node
;
348 jam_xmlNewDoc(&doc
, &root
, "configuration");
349 xmlSetProp(root
, BAD_CAST
"version", BAD_CAST
"1");
351 for (l
= c
->hosts
; l
!= NULL
; l
= l
->next
) {
352 if (!jam_host_write(l
->data
, &err
)) {
353 g_printerr("%s\n", err
->message
);
360 xmlAddTN(root
, "currentserver", c
->lasthost
->name
);
362 node
= xmlNewChild(root
, NULL
, BAD_CAST
"geometries", NULL
);
363 for (i
= 0; i
< GEOM_COUNT
; i
++) {
364 if (c
->geometries
[i
].width
> 0) {
365 writegeometry(&c
->geometries
[i
], geometry_names
[i
], node
);
369 node
= xmlNewChild(root
, NULL
, BAD_CAST
"options", NULL
);
370 writeoptions(&c
->options
, node
);
373 xmlAddTN(root
, "uifont", c
->uifont
);
376 if (c
->spell_language
)
377 xmlAddTN(root
, "spell_language", c
->spell_language
);
381 xmlAddTN(root
, "proxy", c
->proxy
);
383 node
= xmlNewChild(root
, NULL
, BAD_CAST
"proxyauth", NULL
);
384 xmlAddTN(node
, "username", c
->proxyuser
);
385 xmlAddTN(node
, "password", c
->proxypass
);
388 if (c
->spawn_command
)
389 xmlAddTN(root
, "spawncommand", c
->spawn_command
);
391 if (c
->music_command
)
392 xmlAddTN(root
, "musiccommand", c
->music_command
);
395 if (c
->cfuserinterval
) {
397 g_snprintf(buf
, 20, "%d", c
->cfuserinterval
);
398 xmlAddTN(root
, "cfuserinterval", buf
);
401 if (c
->cfthreshold
) {
403 g_snprintf(buf
, 20, "%d", c
->cfthreshold
);
404 xmlAddTN(root
, "cfthreshold", buf
);
408 if (app
.quiet_dlgs
) {
409 xmlNodePtr xmlList
= xmlNewChild(root
, NULL
, BAD_CAST
"quiet_dlgs", NULL
);
410 for (l
= app
.quiet_dlgs
; l
!= NULL
; l
= l
->next
) {
411 xmlAddTN(xmlList
, "quiet_dlg", (char*)l
->data
);
414 #endif /* HAVE_GTK */
416 if (c
->defaultsecurity
.type
!= LJ_SECURITY_PUBLIC
) {
418 if (c
->defaultsecurity
.type
== LJ_SECURITY_CUSTOM
)
419 c
->defaultsecurity
.type
= LJ_SECURITY_PRIVATE
;
420 lj_security_to_strings(&c
->defaultsecurity
, &type
, NULL
);
422 node
= xmlNewChild(root
, NULL
, BAD_CAST
"defaultsecurity", NULL
);
423 xmlSetProp(node
, BAD_CAST
"type", BAD_CAST type
);
428 path
= g_build_filename(base
, "conf.xml", NULL
);
429 if (xmlSaveFormatFile(path
, doc
, TRUE
) < 0) {
430 g_printerr("xmlSaveFormatFile error saving to %s.\n", path
);