Write a structure to the data file which specifies the iterations and
[pwmd.git] / src / commands.c
blob0f770755530027a40dad4e0e957bc54d56cc95ca
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2006-2007 Ben Kibbey <bjk@luxsci.net>
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.
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.
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
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <err.h>
23 #include <errno.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <ctype.h>
28 #include <glib.h>
29 #include <glib/gprintf.h>
30 #include <gcrypt.h>
32 #ifdef HAVE_CONFIG_H
33 #include <config.h>
34 #endif
36 #include "xml.h"
37 #include "common.h"
38 #include "pwmd_error.h"
39 #include "commands.h"
41 static gboolean encrypt_xml(gcry_cipher_hd_t gh, void *outbuf, gsize outsize,
42 void *inbuf, gsize insize)
44 if ((gcryerrno = gcry_cipher_encrypt(gh, outbuf, outsize, inbuf, insize))) {
45 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(gcryerrno));
46 return FALSE;
49 return TRUE;
52 gboolean decrypt_xml(gcry_cipher_hd_t gh, void *outbuf, gsize outsize,
53 void *inbuf, gsize insize)
55 if ((gcryerrno = gcry_cipher_decrypt(gh, outbuf, outsize, inbuf, insize))) {
56 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(gcryerrno));
57 return FALSE;
60 return TRUE;
63 static gboolean parse_xml(struct client_s *client)
65 switch (open_xml(client->xml, client->len, &client->doc, &client->reader)) {
66 case 1:
67 send_error(client, EPWMD_LIBXML_ERROR);
68 return FALSE;
69 case 2:
70 send_error(client, EPWMD_LIBXML_ERROR);
71 return FALSE;
72 default:
73 break;
76 return TRUE;
79 static gboolean valid_filename(const gchar *filename)
81 const gchar *p;
83 if (!filename || !*filename)
84 return FALSE;
86 for (p = filename; *p; p++) {
87 if (g_ascii_isalnum(*p) == FALSE)
88 return FALSE;
91 return TRUE;
94 static gboolean cache_update_key(const guchar *md5filename, const guchar *shakey)
96 void *p;
97 file_cache_t f;
98 glong len;
100 for (p = shm_data, len = 0; len <= cache_size;) {
101 memcpy(&f, p, sizeof(file_cache_t));
103 if (f.used == TRUE) {
104 if (memcmp((gchar *)f.filename, (gchar *)md5filename, sizeof(f.filename)) == 0) {
105 memcpy(&f.key, shakey, sizeof(f.key));
106 memcpy(p, &f, sizeof(file_cache_t));
107 return TRUE;
111 p += sizeof(file_cache_t);
112 len += sizeof(file_cache_t);
114 if (len + sizeof(file_cache_t) > cache_size)
115 break;
118 return cache_add_file(md5filename, shakey);
121 static gint cache_valid_key(const guchar *key, gsize len)
123 gint b;
125 for (b = 0; b < len; b++) {
126 if (key[b])
127 return TRUE;
130 return FALSE;
133 // FIXME stat info
134 static gboolean cache_get_key(const guchar *md5file, guchar *shakey)
136 void *p;
137 file_cache_t f;
138 glong len;
140 for (p = shm_data, len = 0; len <= cache_size;) {
141 memcpy(&f, p, sizeof(file_cache_t));
144 * The slot may be used but not yet contain a key.
146 if (f.used == TRUE) {
147 if (memcmp(&f.filename, md5file, sizeof(f.filename)) == 0) {
148 if (cache_valid_key(f.key, sizeof(f.key)) == FALSE)
149 return FALSE;
151 memcpy(shakey, &f.key, sizeof(f.key));
152 return TRUE;
156 p += sizeof(file_cache_t);
157 len += sizeof(file_cache_t);
159 if (len + sizeof(file_cache_t) > cache_size)
160 break;
163 return FALSE;
166 gint open_file(const gchar *filename, struct stat *st)
168 gint fd;
170 if ((fd = open(filename, O_RDONLY)) == -1)
171 return -1;
173 if (stat(filename, st) == -1) {
174 close(fd);
175 return -1;
178 return fd;
181 gboolean open_command(struct client_s *client, gchar **req)
183 gint fd;
184 struct stat st;
185 gchar *inbuf;
186 const gchar *filename = req[0];
187 guchar shakey[gcrykeysize];
188 guchar tkey[gcrykeysize];
189 gint cached = 0;
190 gsize insize = 0;
191 guint iter;
192 struct file_header_s {
193 guint iter;
194 guchar iv[gcryblocksize];
195 } file_header;
197 if (!filename || !*filename) {
198 send_error(client, EPWMD_COMMAND_SYNTAX);
199 return FALSE;
202 if (valid_filename(filename) == FALSE) {
203 send_error(client, EPWMD_INVALID_FILENAME);
204 return FALSE;
207 if (stat(filename, &st) == 0) {
208 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
209 send_to_client(client, "ERR %03i %s\n", EPWMD_NOT_A_FILE, pwmd_strerror(EPWMD_NOT_A_FILE));
210 return FALSE;
214 gcry_md_hash_buffer(GCRY_MD_MD5, client->md5file, filename, strlen(filename));
217 * New files don't need a key.
219 if (access(filename, R_OK|W_OK) != 0) {
220 if (errno != ENOENT) {
221 send_to_client(client, "ERR %03i %s: %s\n", EPWMD_ERROR, filename,
222 strerror(errno));
223 return FALSE;
225 new_doc:
226 if ((client->xml = new_document()) == NULL) {
227 send_to_client(client, "ERR %03i malloc(): %s\n", EPWMD_ERROR,
228 strerror(errno));
229 return FALSE;
232 client->len = strlen(client->xml);
234 if (cache_add_file(client->md5file, NULL) == FALSE) {
235 send_error(client, EPWMD_MAX_SLOTS);
236 return FALSE;
239 client->filename = g_strdup(filename);
240 return parse_xml(client);
243 if ((fd = open_file(filename, &st)) == -1) {
244 send_to_client(client, "ERR %03i %s: %s\n", EPWMD_ERROR, filename, strerror(errno));
245 return FALSE;
248 if (st.st_size == 0)
249 goto new_doc;
251 if (cache_get_key(client->md5file, shakey) == TRUE)
252 cached = 1;
253 else {
255 * No key specified and no matching filename found in the cache.
257 if (!req[1] || !*req[1]) {
258 close(fd);
259 send_error(client, EPWMD_KEY);
260 return FALSE;
264 insize = st.st_size - sizeof(struct file_header_s);
265 read(fd, &file_header, sizeof(struct file_header_s));
266 inbuf = gcry_malloc(insize);
267 read(fd, inbuf, insize);
268 close(fd);
270 again:
271 if (!cached) {
272 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, req[1], strlen(req[1]));
273 memset(req[1], 0, strlen(req[1]));
276 memcpy(tkey, shakey, sizeof(tkey));
277 tkey[0] ^= 1;
279 if ((gcryerrno = gcry_cipher_setiv(client->gh, file_header.iv,
280 sizeof(file_header.iv)))) {
281 gcry_free(inbuf);
282 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(gcryerrno));
283 send_to_client(client, "ERR %03i gcrypt: %s\n", EPWMD_ERROR, gcry_strerror(gcryerrno));
284 return FALSE;
287 if ((gcryerrno = gcry_cipher_setkey(client->gh, shakey, gcrykeysize))) {
288 gcry_free(inbuf);
289 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(gcryerrno));
290 send_to_client(client, "ERR %03i gcrypt: %s\n", EPWMD_ERROR, gcry_strerror(gcryerrno));
291 return FALSE;
294 if (decrypt_xml(client->gh, inbuf, insize, NULL, 0) == FALSE) {
295 if (cached) {
296 cached = 0;
297 goto again;
300 gcry_free(inbuf);
301 send_to_client(client, "ERR %03i gcrypt: %s\n", EPWMD_ERROR, gcry_strerror(gcryerrno));
302 return FALSE;
305 if ((gcryerrno = gcry_cipher_setkey(client->gh, tkey, gcrykeysize))) {
306 gcry_free(inbuf);
307 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(gcryerrno));
308 send_to_client(client, "ERR %03i gcrypt: %s\n", EPWMD_ERROR, gcry_strerror(gcryerrno));
309 return FALSE;
312 iter = file_header.iter;
314 while (iter-- > 0) {
315 if ((gcryerrno = gcry_cipher_setiv(client->gh, file_header.iv,
316 sizeof(file_header.iv)))) {
317 gcry_free(inbuf);
318 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(gcryerrno));
319 send_to_client(client, "ERR %03i gcrypt: %s\n", EPWMD_ERROR, gcry_strerror(gcryerrno));
320 return FALSE;
323 if (decrypt_xml(client->gh, inbuf, insize, NULL, 0) == FALSE) {
324 if (cached) {
325 cached = 0;
326 goto again;
329 gcry_free(inbuf);
330 send_to_client(client, "ERR %03i gcrypt: %s\n", EPWMD_ERROR, gcry_strerror(gcryerrno));
331 return FALSE;
335 client->xml = inbuf;
336 client->len = insize;
338 if (g_strncasecmp(client->xml, "<?xml version=\"1.0\"?>", 21) != 0) {
339 send_error(client, EPWMD_BADKEY);
340 return FALSE;
343 if (!cached) {
344 if (cache_add_file(client->md5file, shakey) == FALSE) {
345 send_error(client, EPWMD_MAX_SLOTS);
346 return FALSE;
350 client->filename = g_strdup(filename);
351 return parse_xml(client);
355 * client->reader should be at the position in the document where the element
356 * search should start. It won't search past the closing account element.
358 static gboolean find_elements(struct client_s *client, xmlTextReaderPtr reader,
359 gchar **req, gint quiet)
361 gint i;
363 if (!req || !req[0]) {
364 if (!quiet)
365 send_error(client, EPWMD_COMMAND_SYNTAX);
366 return FALSE;
369 for (i = 0; req[i]; i++) {
370 if (find_element(reader, req[i], req[i+1] != NULL) == FALSE) {
371 if (!quiet)
372 send_error(client, EPWMD_ELEMENT_NOT_FOUND);
374 return FALSE;
378 return TRUE;
381 gboolean save_command(struct client_s *client, const gchar *filename, gchar *key)
383 xmlChar *xmlbuf;
384 gint insize;
385 void *inbuf;
386 gsize len = 0;
387 gint fd;
388 gint update = 1;
389 guchar shakey[gcrykeysize];
390 guchar tkey[gcrykeysize];
391 gint iter = client->iter;
392 struct file_header_s {
393 guint iter;
394 guchar iv[gcryblocksize];
395 } file_header;
397 if (!key || !key) {
398 if (cache_get_key(client->md5file, shakey) == FALSE) {
399 send_error(client, EPWMD_KEY);
400 return FALSE;
403 update = 0;
405 else {
406 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, key, strlen(key));
407 memset(key, 0, strlen(key));
410 xmlDocDumpFormatMemory(client->doc, &xmlbuf, &insize, 0);
411 len = insize;
413 if (insize / gcryblocksize) {
414 len = (insize / gcryblocksize) * gcryblocksize;
416 if (insize % gcryblocksize)
417 len += gcryblocksize;
420 inbuf = gcry_calloc(1, len);
421 memcpy(inbuf, xmlbuf, insize);
422 xmlFree(xmlbuf);
423 insize = len;
424 gcry_create_nonce(file_header.iv, sizeof(file_header.iv));
425 memcpy(tkey, shakey, sizeof(tkey));
426 tkey[0] ^= 1;
428 if ((gcryerrno = gcry_cipher_setkey(client->gh, tkey, gcrykeysize))) {
429 gcry_free(inbuf);
430 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(gcryerrno));
431 send_to_client(client, "ERR %03i gcrypt: %s\n", EPWMD_ERROR, gcry_strerror(gcryerrno));
432 return FALSE;
435 file_header.iter = iter;
437 while (iter-- > 0) {
438 if ((gcryerrno = gcry_cipher_setiv(client->gh, file_header.iv,
439 sizeof(file_header.iv)))) {
440 gcry_free(inbuf);
441 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(gcryerrno));
442 send_to_client(client, "ERR %03i gcrypt: %s\n", EPWMD_ERROR, gcry_strerror(gcryerrno));
443 return FALSE;
446 if (encrypt_xml(client->gh, inbuf, insize, NULL, 0)
447 == FALSE) {
448 gcry_free(inbuf);
449 send_to_client(client, "ERR %03i gcrypt: %s\n", EPWMD_ERROR, gcry_strerror(gcryerrno));
450 return FALSE;
454 if ((gcryerrno = gcry_cipher_setiv(client->gh, file_header.iv,
455 sizeof(file_header.iv)))) {
456 gcry_free(inbuf);
457 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(gcryerrno));
458 send_to_client(client, "ERR %03i gcrypt: %s\n", EPWMD_ERROR, gcry_strerror(gcryerrno));
459 return FALSE;
462 if ((gcryerrno = gcry_cipher_setkey(client->gh, shakey, gcrykeysize))) {
463 gcry_free(inbuf);
464 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(gcryerrno));
465 send_to_client(client, "ERR %03i gcrypt: %s\n", EPWMD_ERROR, gcry_strerror(gcryerrno));
466 return FALSE;
469 if (encrypt_xml(client->gh, inbuf, insize, NULL, 0)
470 == FALSE) {
471 gcry_free(inbuf);
472 send_to_client(client, "ERR %03i gcrypt: %s\n", EPWMD_ERROR, gcry_strerror(gcryerrno));
473 return FALSE;
476 if ((fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0600)) == -1) {
477 gcry_free(inbuf);
478 send_to_client(client, "ERR %03i %s: %s\n", EPWMD_ERROR, filename, strerror(errno));
479 return FALSE;
482 write(fd, &file_header, sizeof(struct file_header_s));
483 write(fd, inbuf, insize);
484 close(fd);
485 gcry_free(inbuf);
487 if (!update)
488 return TRUE;
490 if (cache_update_key(client->md5file, shakey) == FALSE) {
491 send_error(client, EPWMD_MAX_SLOTS);
492 return FALSE;
495 return TRUE;
498 static gboolean contains_whitespace(const gchar *str)
500 const gchar *p = str;
502 for (; *p; p++) {
503 if (g_ascii_isspace(*p) == TRUE) {
504 return TRUE;
508 return FALSE;
512 * the 'reader' should be at the element of the document where the elements
513 * 'req' are to be created.
515 static gboolean create_elements(struct client_s *client, xmlTextReaderPtr reader,
516 gchar **req, gint novalue)
518 gint i;
519 gboolean ret = TRUE;
520 xmlNodePtr r;
522 r = xmlTextReaderCurrentNode(reader);
524 if (xmlTextReaderDepth(reader) > 1)
525 r = r->parent;
527 for (i = 0; req[i]; i++) {
528 xmlNodePtr n;
531 * Whitespace is allowed in values or attributes but not in element
532 * names.
534 if (req[i+1] && valid_xml_element((xmlChar *)req[i]) == FALSE) {
535 send_error(client, EPWMD_INVALID_ELEMENT);
536 return FALSE;
540 * The value of the element tree.
542 if (!req[i+1] && !novalue) {
544 * Prevent creating 'text' elements in the root of the account.
546 if (i < 1) {
547 send_error(client, EPWMD_ROOT_TEXT_ELEMENT);
548 return FALSE;
552 * FIXME ?? overwriting an element tree with a text element:
554 * STORE account element element2 value
555 * STORE account element value
557 * would remove the existing element tree. This may be a bug or
558 * feature.
560 xmlNodeSetContent(r, (xmlChar *)req[i]);
561 break;
564 if ((n = find_node(r, (xmlChar *)req[i])) == NULL) {
565 n = xmlNewNode(NULL, (xmlChar *)req[i]);
566 r = xmlAddChild(r, n);
568 else
569 r = n;
571 if (!req[i+1] && novalue)
572 return TRUE;
575 return ret;
579 * FIXME reuse reader handle
581 static gboolean reset_reader(xmlDocPtr doc, xmlTextReaderPtr *reader)
583 if (reader) {
584 xmlFreeTextReader(*reader);
585 *reader = NULL;
588 if ((*reader = xmlReaderWalker(doc)) == NULL)
589 return FALSE;
591 return TRUE;
594 static void delete_node(xmlNodePtr n)
596 xmlUnlinkNode(n);
597 xmlFreeNode(n);
600 gboolean delete_command(struct client_s *client, gchar **req)
602 gint i = 1;
603 xmlNodePtr n;
605 if (reset_reader(client->doc, &client->reader) == FALSE) {
606 send_error(client, EPWMD_LIBXML_ERROR);
607 return FALSE;
610 if (find_account(client->reader, req[0]) == FALSE) {
611 send_error(client, EPWMD_ELEMENT_NOT_FOUND);
612 return FALSE;
615 n = xmlTextReaderCurrentNode(client->reader);
618 * No sub-node defined. Remove the entire node (account).
620 if (!req[i]) {
621 if (n)
622 delete_node(n);
623 return TRUE;
627 * Remove matching sub-nodes starting from the root of the account.
629 while (req[i] && find_element(client->reader, req[i++], req[i] != NULL) == TRUE)
630 n = xmlTextReaderCurrentNode(client->reader);
632 if (n && xmlStrcmp(n->name, (xmlChar *)req[i-1]) == 0 &&
633 xmlTextReaderNodeType(client->reader) == XML_READER_TYPE_ELEMENT)
634 delete_node(n);
635 else {
636 send_error(client, EPWMD_ELEMENT_NOT_FOUND);
637 return FALSE;
640 return TRUE;
643 gboolean store_command(struct client_s *client, gchar **req)
645 again:
646 if (reset_reader(client->doc, &client->reader) == FALSE) {
647 send_error(client, EPWMD_LIBXML_ERROR);
648 return FALSE;
651 if (!req[0]) {
652 send_error(client, EPWMD_COMMAND_SYNTAX);
653 return FALSE;
656 if (find_account(client->reader, req[0]) == FALSE) {
657 if (contains_whitespace(req[0]) == TRUE) {
658 send_error(client, EPWMD_INVALID_ELEMENT);
659 return FALSE;
662 if (new_account(client->doc, req[0]) == FALSE) {
663 send_error(client, EPWMD_ERROR);
664 return FALSE;
667 goto again;
670 xmlTextReaderNext(client->reader);
671 return create_elements(client, client->reader, req+1, 0);
674 static gboolean do_get_command(struct client_s *client, xmlTextReaderPtr *reader,
675 gchar **req, xmlChar **content, gint quiet, gint list)
677 xmlNodePtr n;
678 xmlAttrPtr a;
679 gchar **nreq;
680 gboolean ret;
681 xmlChar *p;
683 if (reset_reader(client->doc, reader) == FALSE) {
684 if (!quiet)
685 send_error(client, EPWMD_LIBXML_ERROR);
686 return FALSE;
689 if (find_account(*reader, req[0]) == FALSE) {
690 if (!quiet && !list)
691 send_error(client, EPWMD_ELEMENT_NOT_FOUND);
692 return FALSE;
696 * May be an account with only a TARGET attribute.
698 if (req[1]) {
699 if (find_elements(client, *reader, req + 1, (list) ? 1 : quiet) == FALSE)
700 return FALSE;
703 if ((n = xmlTextReaderCurrentNode(*reader)) == NULL) {
704 if (!quiet)
705 send_error(client, EPWMD_LIBXML_ERROR);
706 return FALSE;
710 * If the current element has a TARGET attribute, the value of the
711 * attribute is an element path somewhere else in the document. Use this
712 * value and not any TEXT element value. The value may be another element
713 * with a TARGET attribute and this function will recurse until a non-TARGET
714 * attribute in the element is found.
716 if ((a = xmlHasProp(n, (xmlChar *)"target")) != NULL) {
717 if ((p = xmlNodeGetContent(a->children)) != NULL) {
718 if (strchr((gchar *)p, '\t') != NULL) {
719 if ((nreq = split_input_line((gchar *)p, "\t", 0)) == NULL) {
720 xmlFree(p);
722 if (!quiet)
723 send_error(client, EPWMD_INVALID_ELEMENT);
724 return FALSE;
727 else {
728 if ((nreq = split_input_line((gchar *)p, " ", 0)) == NULL) {
729 xmlFree(p);
731 if (!quiet)
732 send_error(client, EPWMD_INVALID_ELEMENT);
733 return FALSE;
737 xmlFree(p);
738 ret = do_get_command(client, reader, nreq, content, quiet, list);
739 g_strfreev(nreq);
740 return ret;
744 switch (xmlTextReaderNext(*reader)) {
745 case -1:
746 if (!quiet)
747 send_error(client, EPWMD_LIBXML_ERROR);
748 return FALSE;
749 case 0:
750 if (!quiet)
751 send_error(client, EPWMD_EMPTY_ELEMENT);
752 return FALSE;
753 default:
754 break;
757 switch (xmlTextReaderNodeType(*reader)) {
758 case XML_READER_TYPE_END_ELEMENT:
760 * May be an empty element after an ATTR DELETE TARGET command.
762 return TRUE;
763 case XML_READER_TYPE_TEXT:
764 break;
765 case -1:
766 if (!quiet)
767 send_error(client, EPWMD_LIBXML_ERROR);
769 return FALSE;
770 default:
771 if (!quiet) {
772 if (n->children && !list)
773 send_error(client, EPWMD_TRAILING_ELEMENT);
774 else if (!n->children && !list)
775 send_error(client, EPWMD_INVALID_ELEMENT);
777 return FALSE;
780 if ((*content = xmlNodeGetContent(n)) == NULL) {
781 if (!quiet)
782 send_error(client, EPWMD_EMPTY_ELEMENT);
783 return FALSE;
786 return TRUE;
790 * Retrieves the value associated with the element tree 'req'.
792 gboolean get_command(struct client_s *client, xmlTextReaderPtr *reader,
793 gchar **req, gint quiet)
795 xmlChar *content = NULL;
797 if (do_get_command(client, reader, req, &content, quiet, 0) == FALSE)
798 return FALSE;
800 if (!content) {
801 if (!quiet)
802 send_error(client, EPWMD_EMPTY_ELEMENT);
804 return FALSE;
807 send_to_client(client, "BEGIN %li\n%s\nOK \n", xmlStrlen(content), content);
808 xmlFree(content);
809 return TRUE;
812 #ifdef DEBUG
813 static gchar *element_path_to_req(const gchar *account, xmlChar *path,
814 const xmlChar *content)
815 #else
816 static gchar *element_path_to_req(const gchar *account, xmlChar *path)
817 #endif
819 xmlChar *p = path;
820 gint n;
821 gchar *buf;
823 if (!p)
824 return NULL;
826 for (n = 0; *p && n < 3; p++) {
827 if (*p == '/')
828 n++;
831 if (strstr((gchar *)p, "text()") != NULL)
832 p[xmlStrlen(p) - 7] = 0;
834 for (n = 0; p[n]; n++) {
835 if (p[n] == '/')
836 p[n] = '\t';
839 #ifdef DEBUG
840 buf = g_strdup_printf("%s\t%s\t%s", account, p, content);
841 #else
842 buf = g_strdup_printf("%s\t%s", account, p);
843 #endif
844 return buf;
847 static gboolean append_to_array(gchar ***array, gint *total, const gchar *str)
849 gchar **a;
850 gint t = *total;
852 if ((a = g_realloc(*array, (t + 2) * sizeof(gchar *))) == NULL)
853 return FALSE;
855 a[t++] = g_strdup(str);
856 a[t] = NULL;
857 *total = t;
858 *array = a;
859 return TRUE;
862 gboolean list_command(struct client_s *client, gchar *str)
864 gchar *dst = NULL;
865 gchar *p = str;
866 gchar **elements = NULL;
867 gint pwmd_errno = -1;
868 gchar *account;
869 gint total = 0;
870 xmlChar *path = NULL;
871 xmlAttrPtr a;
872 xmlNodePtr n;
873 xmlChar *content;
874 xmlTextReaderPtr r = NULL;
875 gchar **req = NULL, **nreq;
876 gboolean ret;
877 gint type;
878 gchar *line;
880 if (reset_reader(client->doc, &client->reader) == FALSE) {
881 send_error(client, EPWMD_LIBXML_ERROR);
882 return FALSE;
885 if (strchr(p, ' ') == NULL) {
886 list_only:
887 if (list_accounts(client->reader, &dst, &pwmd_errno) == FALSE) {
888 send_error(client, pwmd_errno);
889 return FALSE;
891 else {
892 send_to_client(client, "BEGIN %i\n%s\nOK \n",
893 g_utf8_strlen(dst, -1), dst);
894 memset(dst, 0, strlen(dst));
895 g_free(dst);
898 return TRUE;
901 p = str + 5;
903 while (*p && isspace(*p))
904 p++;
906 if (!*p)
907 goto list_only;
909 if (strchr(p, '\t') != NULL) {
910 if ((req = split_input_line(p, "\t", 0)) == NULL) {
911 send_error(client, EPWMD_COMMAND_SYNTAX);
912 return FALSE;
915 if (find_account(client->reader, req[0]) == FALSE) {
916 send_error(client, EPWMD_ELEMENT_NOT_FOUND);
917 return FALSE;
920 if (find_elements(client, client->reader, req + 1, 0) == FALSE) {
921 g_strfreev(req);
922 return FALSE;
925 else {
926 if (find_account(client->reader, p) == FALSE) {
927 send_error(client, EPWMD_ELEMENT_NOT_FOUND);
928 return FALSE;
932 if ((n = xmlTextReaderCurrentNode(client->reader)) == NULL) {
933 send_error(client, EPWMD_LIBXML_ERROR);
934 return FALSE;
937 if ((a = xmlHasProp(n, (xmlChar *)"target")) != NULL) {
938 if (reset_reader(client->doc, &client->reader) == FALSE) {
939 send_error(client, EPWMD_LIBXML_ERROR);
940 return FALSE;
943 if ((content = xmlNodeGetContent(a->children)) != NULL) {
944 if (find_account(client->reader, (gchar *)content) == FALSE) {
945 xmlFree(content);
946 send_error(client, EPWMD_ELEMENT_NOT_FOUND);
947 return FALSE;
950 xmlFree(content);
954 account = (req) ? g_strdup(req[0]) : g_strdup(p);
956 if (req)
957 g_strfreev(req);
959 while (xmlTextReaderNext(client->reader) == 1) {
960 again:
961 if ((n = xmlTextReaderCurrentNode(client->reader)) == NULL) {
962 send_error(client, EPWMD_LIBXML_ERROR);
963 return FALSE;
966 if (xmlTextReaderDepth(client->reader) == 1 &&
967 xmlStrcmp(n->name, (xmlChar *)"account") == 0 &&
968 xmlTextReaderNodeType(client->reader) == XML_READER_TYPE_END_ELEMENT)
969 break;
972 * If the current element has a TARGET attribute, the value of the
973 * attribute is an element path somewhere else in the document. Use this
974 * value and not any TEXT element value.
976 type = xmlTextReaderNodeType(client->reader);
977 a = xmlHasProp(n, (xmlChar *)"target");
979 if (type == XML_READER_TYPE_ELEMENT && a) {
980 if ((content = xmlNodeGetContent(a->children)) != NULL) {
981 path = xmlGetNodePath(n);
983 if ((nreq = split_input_line((gchar *)content, "\t", 0)) == NULL) {
984 if (elements)
985 g_strfreev(elements);
987 xmlFree(path);
988 xmlFree(content);
989 send_error(client, EPWMD_INVALID_ELEMENT);
990 return FALSE;
993 xmlFree(content);
994 r = NULL;
996 if ((ret = do_get_command(client, &r, nreq, &content, 0, 1)) == TRUE) {
997 if (content && *content) {
998 #ifdef DEBUG
999 line = element_path_to_req(account, path, content);
1000 #else
1001 line = element_path_to_req(account, path);
1002 #endif
1003 xmlFree(content);
1005 if (append_to_array(&elements, &total, line) == FALSE) {
1006 if (elements)
1007 g_strfreev(elements);
1009 xmlFree(path);
1010 memset(line, 0, g_utf8_strlen(line, -1));
1011 g_free(line);
1012 g_strfreev(nreq);
1013 xmlFreeTextReader(r);
1014 send_error(client, EPWMD_ERROR);
1015 return FALSE;
1018 memset(line, 0, g_utf8_strlen(line, -1));
1019 g_free(line);
1022 if (xmlTextReaderNext(client->reader) == 1) {
1023 if (xmlTextReaderNodeType(client->reader) !=
1024 XML_READER_TYPE_TEXT) {
1025 g_strfreev(nreq);
1026 xmlFreeTextReader(r);
1027 xmlFree(path);
1028 goto again;
1033 g_strfreev(nreq);
1034 xmlFreeTextReader(r);
1035 xmlFree(path);
1036 continue;
1040 if (type == XML_READER_TYPE_TEXT) {
1041 xmlChar *np = xmlGetNodePath(n);
1043 #ifdef DEBUG
1044 content = xmlNodeGetContent(n);
1045 line = element_path_to_req(account, np, content);
1046 xmlFree(content);
1047 #else
1048 line = element_path_to_req(account, np);
1049 #endif
1050 xmlFree(np);
1051 append_to_array(&elements, &total, line);
1052 memset(line, 0, g_utf8_strlen(line, -1));
1053 g_free(line);
1057 if (!elements) {
1058 send_error(client, EPWMD_EMPTY_ELEMENT);
1059 g_free(account);
1060 return FALSE;
1063 g_free(account);
1064 line = g_strjoinv("\n", elements);
1065 send_to_client(client, "BEGIN %li\n%s\nOK \n",
1066 g_utf8_strlen(line, -1), line);
1067 g_strfreev(elements);
1068 g_free(line);
1069 return TRUE;
1073 * The client->reader handle should be at the element in the document where
1074 * the attribute will be created or modified.
1076 static gboolean add_attribute(struct client_s *client, const gchar *name, const gchar *value)
1078 xmlAttrPtr a;
1079 xmlNodePtr n;
1081 if ((n = xmlTextReaderCurrentNode(client->reader)) == NULL) {
1082 send_error(client, EPWMD_LIBXML_ERROR);
1083 return FALSE;
1086 if ((a = xmlHasProp(n, (xmlChar *)name)) == NULL)
1087 a = xmlNewProp(n, (xmlChar *)name, (xmlChar *)value);
1088 else
1089 xmlNodeSetContent(a->children, (xmlChar *)value);
1091 return TRUE;
1095 * req[0] - element path
1097 static gboolean attribute_list(struct client_s *client, gchar **req)
1099 gchar **attrlist = NULL;
1100 gint i = 0;
1101 gchar **epath = NULL;
1102 xmlAttrPtr a;
1103 xmlNodePtr n, an;
1104 gchar *line;
1106 if (!req || !req[0]) {
1107 send_error(client, EPWMD_COMMAND_SYNTAX);
1108 return FALSE;
1111 if ((epath = split_input_line(req[0], "\t", 0)) == NULL) {
1113 * The first argument may be only an account.
1115 if ((epath = split_input_line(req[0], " ", 0)) == NULL) {
1116 send_error(client, EPWMD_COMMAND_SYNTAX);
1117 return FALSE;
1121 if (reset_reader(client->doc, &client->reader) == FALSE) {
1122 send_error(client, EPWMD_LIBXML_ERROR);
1123 goto blah;
1126 if (find_account(client->reader, epath[0]) == FALSE) {
1127 send_error(client, EPWMD_ELEMENT_NOT_FOUND);
1128 goto blah;
1131 if (epath[1]) {
1132 if ((find_elements(client, client->reader, epath+1, 0)) == FALSE)
1133 goto blah;
1136 if ((n = xmlTextReaderCurrentNode(client->reader)) == NULL) {
1137 send_error(client, EPWMD_LIBXML_ERROR);
1138 goto blah;
1141 for (a = n->properties; a; a = a->next) {
1142 if ((attrlist = g_realloc(attrlist, (i + 2) * sizeof(gchar *))) == NULL) {
1143 send_error(client, EPWMD_ERROR);
1144 goto blah;
1147 an = a->children;
1148 attrlist[i++] = g_strdup_printf("%s\t%s", (gchar *)a->name, (gchar *)an->content);
1149 attrlist[i] = NULL;
1152 if (!attrlist) {
1153 send_error(client, EPWMD_EMPTY_ELEMENT);
1154 goto blah;
1157 line = g_strjoinv("\n", attrlist);
1158 send_to_client(client, "BEGIN %li\n%s\n", g_utf8_strlen(line, -1), line);
1159 g_free(line);
1160 g_strfreev(epath);
1161 g_strfreev(attrlist);
1162 return TRUE;
1163 blah:
1164 g_strfreev(epath);
1165 return FALSE;
1169 * req[0] - attribute
1170 * req[1] - element path
1172 static gboolean attribute_delete(struct client_s *client, gchar **req)
1174 xmlAttrPtr a;
1175 xmlNodePtr n;
1176 gchar **epath = NULL;
1178 if (!req || !req[0] || !req[1]) {
1179 send_error(client, EPWMD_COMMAND_SYNTAX);
1180 return FALSE;
1183 if ((epath = split_input_line(req[1], "\t", 0)) == NULL) {
1185 * The first argument may be only an account.
1187 if ((epath = split_input_line(req[1], " ", 0)) == NULL) {
1188 send_error(client, EPWMD_COMMAND_SYNTAX);
1189 return FALSE;
1194 * Don't remove the NAME attribute for the account element.
1196 if (!epath[1] && g_ascii_strcasecmp(req[0], "NAME") == 0) {
1197 send_error(client, EPWMD_ATTR_SYNTAX);
1198 goto blah;
1201 if (reset_reader(client->doc, &client->reader) == FALSE) {
1202 send_error(client, EPWMD_LIBXML_ERROR);
1203 goto blah;
1206 if (find_account(client->reader, epath[0]) == FALSE) {
1207 send_error(client, EPWMD_ELEMENT_NOT_FOUND);
1208 goto blah;
1211 if (epath[1]) {
1212 if ((find_elements(client, client->reader, epath+1, 0)) == FALSE)
1213 goto blah;
1216 if ((n = xmlTextReaderCurrentNode(client->reader)) == NULL) {
1217 send_error(client, EPWMD_LIBXML_ERROR);
1218 goto blah;
1221 if ((a = xmlHasProp(n, (xmlChar *)req[0])) == NULL) {
1222 send_error(client, EPWMD_ATTR_NOT_FOUND);
1223 goto blah;
1226 if (xmlRemoveProp(a) == -1) {
1227 send_error(client, EPWMD_LIBXML_ERROR);
1228 goto blah;
1231 g_strfreev(epath);
1232 return TRUE;
1233 blah:
1234 g_strfreev(epath);
1235 return FALSE;
1239 * req[0] - source element path
1240 * req[1] - destination element path
1242 static gboolean target_attribute(struct client_s *client, gchar **req)
1244 gchar **src, **dst, *line;
1246 if (!req || !req[0] || !req[1]) {
1247 send_error(client, EPWMD_COMMAND_SYNTAX);
1248 return FALSE;
1251 if ((src = split_input_line(req[0], "\t", 0)) == NULL) {
1253 * The first argument may be only an account.
1255 if ((src = split_input_line(req[0], " ", 0)) == NULL) {
1256 send_error(client, EPWMD_COMMAND_SYNTAX);
1257 return FALSE;
1261 if ((dst = split_input_line(req[1], "\t", 0)) == NULL) {
1263 * The first argument may be only an account.
1265 if ((dst = split_input_line(req[1], " ", 0)) == NULL) {
1266 send_error(client, EPWMD_COMMAND_SYNTAX);
1267 g_strfreev(src);
1268 goto blah;
1273 * Prevent an element tree pointing to only and account. Accounts require
1274 * at least one element. Accounts pointing to accounts are allowed.
1276 if ((!src[1] && dst[1]) || (!dst[1] && src[1])) {
1277 send_error(client, EPWMD_ATTR_SYNTAX);
1278 g_strfreev(src);
1279 g_strfreev(dst);
1280 goto blah;
1283 if (reset_reader(client->doc, &client->reader) == FALSE) {
1284 send_error(client, EPWMD_LIBXML_ERROR);
1285 g_strfreev(src);
1286 g_strfreev(dst);
1287 goto blah;
1291 * Make sure the destination element path exists.
1293 if (find_account(client->reader, dst[0]) == FALSE) {
1294 send_error(client, EPWMD_ELEMENT_NOT_FOUND);
1295 g_strfreev(src);
1296 g_strfreev(dst);
1297 goto blah;
1300 if (dst[1]) {
1301 if (find_elements(client, client->reader, dst+1, 0) == FALSE) {
1302 g_strfreev(src);
1303 g_strfreev(dst);
1304 goto blah;
1308 if (reset_reader(client->doc, &client->reader) == FALSE) {
1309 send_error(client, EPWMD_LIBXML_ERROR);
1310 g_strfreev(src);
1311 g_strfreev(dst);
1312 goto blah;
1316 * If the source element tree doesn't exist, create it.
1318 if (find_account(client->reader, src[0]) == FALSE) {
1319 if (new_account(client->doc, src[0]) == FALSE) {
1320 send_error(client, EPWMD_LIBXML_ERROR);
1321 g_strfreev(src);
1322 g_strfreev(dst);
1323 goto blah;
1326 if (reset_reader(client->doc, &client->reader) == FALSE) {
1327 send_error(client, EPWMD_LIBXML_ERROR);
1328 g_strfreev(src);
1329 g_strfreev(dst);
1330 goto blah;
1333 if (find_account(client->reader, src[0]) == FALSE) {
1334 send_error(client, EPWMD_ELEMENT_NOT_FOUND);
1335 g_strfreev(src);
1336 g_strfreev(dst);
1337 goto blah;
1341 if (src[1]) {
1342 if (find_elements(client, client->reader, src+1, 1) == FALSE) {
1343 if (reset_reader(client->doc, &client->reader) == FALSE) {
1344 send_error(client, EPWMD_LIBXML_ERROR);
1345 g_strfreev(src);
1346 g_strfreev(dst);
1347 goto blah;
1350 if (find_account(client->reader, src[0]) == FALSE) {
1351 send_error(client, EPWMD_ELEMENT_NOT_FOUND);
1352 g_strfreev(src);
1353 g_strfreev(dst);
1354 goto blah;
1357 xmlTextReaderNext(client->reader);
1359 if (create_elements(client, client->reader, src+1, 1) == FALSE) {
1360 g_strfreev(src);
1361 g_strfreev(dst);
1362 goto blah;
1365 if (reset_reader(client->doc, &client->reader) == FALSE) {
1366 send_error(client, EPWMD_LIBXML_ERROR);
1367 g_strfreev(src);
1368 g_strfreev(dst);
1369 goto blah;
1372 if (find_account(client->reader, src[0]) == FALSE) {
1373 send_error(client, EPWMD_ELEMENT_NOT_FOUND);
1374 g_strfreev(src);
1375 g_strfreev(dst);
1376 goto blah;
1379 if (find_elements(client, client->reader, src+1, 0) == FALSE) {
1380 g_strfreev(src);
1381 g_strfreev(dst);
1382 goto blah;
1387 line = g_strjoinv("\t", dst);
1389 if (add_attribute(client, "target", line) == FALSE) {
1390 g_free(line);
1391 g_strfreev(src);
1392 g_strfreev(dst);
1393 goto blah;
1396 g_strfreev(src);
1397 g_strfreev(dst);
1398 g_free(line);
1399 return TRUE;
1400 blah:
1401 g_strfreev(src);
1402 g_strfreev(dst);
1403 return FALSE;
1407 * req[0] - account name
1408 * req[1] - new name
1410 static gboolean name_attribute(struct client_s *client, gchar **req)
1412 if (reset_reader(client->doc, &client->reader) == FALSE) {
1413 send_error(client, EPWMD_LIBXML_ERROR);
1414 return FALSE;
1417 if (find_account(client->reader, req[0]) == FALSE) {
1418 send_error(client, EPWMD_ELEMENT_NOT_FOUND);
1419 return FALSE;
1422 if (strcmp(req[0], req[1]) == 0)
1423 return TRUE;
1425 if (reset_reader(client->doc, &client->reader) == FALSE) {
1426 send_error(client, EPWMD_LIBXML_ERROR);
1427 return FALSE;
1431 * Will not overwrite an existing account.
1433 if (find_account(client->reader, req[1]) == TRUE) {
1434 send_error(client, EPWMD_ACCOUNT_EXISTS);
1435 return FALSE;
1438 if (reset_reader(client->doc, &client->reader) == FALSE) {
1439 send_error(client, EPWMD_LIBXML_ERROR);
1440 return FALSE;
1443 if (find_account(client->reader, req[0]) == FALSE) {
1444 send_error(client, EPWMD_ELEMENT_NOT_FOUND);
1445 return FALSE;
1449 * Whitespace not allowed in account names.
1451 if (contains_whitespace(req[1]) == TRUE) {
1452 send_error(client, EPWMD_ATTR_SYNTAX);
1453 return FALSE;
1456 return add_attribute(client, "name", req[1]);
1460 * req[0] - attribute
1461 * req[1] - element path
1463 * If the element has a "target" attribute it won't be "followed".
1465 static gboolean attribute_get(struct client_s *client, gchar **req)
1467 xmlNodePtr n;
1468 xmlChar *a;
1469 gchar **nreq = NULL;
1471 if (!req || !req[0] || !req[1]) {
1472 send_error(client, EPWMD_COMMAND_SYNTAX);
1473 return FALSE;
1476 if (strchr(req[1], '\t')) {
1477 if ((nreq = split_input_line(req[1], "\t", 0)) == NULL) {
1478 send_error(client, EPWMD_COMMAND_SYNTAX);
1479 return FALSE;
1482 else {
1483 if ((nreq = split_input_line(req[1], " ", 0)) == NULL) {
1484 send_error(client, EPWMD_COMMAND_SYNTAX);
1485 return FALSE;
1489 if (reset_reader(client->doc, &client->reader) == FALSE) {
1490 g_strfreev(nreq);
1491 send_error(client, EPWMD_LIBXML_ERROR);
1492 return FALSE;
1495 if (find_account(client->reader, nreq[0]) == FALSE) {
1496 g_strfreev(nreq);
1497 send_error(client, EPWMD_ELEMENT_NOT_FOUND);
1498 return FALSE;
1501 if (nreq[1]) {
1502 if (find_elements(client, client->reader, nreq + 1, 0) == FALSE) {
1503 g_strfreev(nreq);
1504 return FALSE;
1508 g_strfreev(nreq);
1510 if ((n = xmlTextReaderCurrentNode(client->reader)) == NULL) {
1511 send_error(client, EPWMD_LIBXML_ERROR);
1512 return FALSE;
1515 if ((a = xmlGetProp(n, (xmlChar *)req[0])) == NULL) {
1516 send_error(client, EPWMD_ATTR_NOT_FOUND);
1517 return FALSE;
1520 send_to_client(client, "BEGIN %li\n%s\n", xmlStrlen(a), a);
1521 xmlFree(a);
1522 return TRUE;
1526 * req[0] - attribute
1527 * req[1] - element path
1528 * req[2] - value
1530 static gboolean attribute_set(struct client_s *client, gchar **req)
1532 gchar **epath = NULL;
1534 if (!req || !req[0] || !req[1] || !req[2]) {
1535 send_error(client, EPWMD_COMMAND_SYNTAX);
1536 return FALSE;
1540 * Reserved attribute names.
1542 if (g_ascii_strcasecmp(req[0], "NAME") == 0) {
1544 * Only reserved for the account element. Not the rest of the
1545 * document.
1547 if (strchr(req[1], '\t') == NULL)
1548 return name_attribute(client, req + 1);
1550 else if (g_ascii_strcasecmp(req[0], "TARGET") == 0)
1551 return target_attribute(client, req + 1);
1553 if ((epath = split_input_line(req[1], "\t", 0)) == NULL) {
1555 * The first argument may be only an account.
1557 if ((epath = split_input_line(req[1], " ", 0)) == NULL) {
1558 send_error(client, EPWMD_COMMAND_SYNTAX);
1559 return FALSE;
1563 if (reset_reader(client->doc, &client->reader) == FALSE) {
1564 send_error(client, EPWMD_LIBXML_ERROR);
1565 goto blah;
1568 if (find_account(client->reader, epath[0]) == FALSE) {
1569 send_error(client, EPWMD_ELEMENT_NOT_FOUND);
1570 goto blah;
1573 if (epath[1]) {
1574 if ((find_elements(client, client->reader, epath+1, 0)) == FALSE)
1575 goto blah;
1578 g_strfreev(epath);
1579 return add_attribute(client, req[0], req[2]);
1580 blah:
1581 g_strfreev(epath);
1582 return FALSE;
1586 * req[0] - command
1587 * req[1] - attribute name or element path if command is LIST
1588 * req[2] - element path
1589 * req[2] - element path or value
1591 gboolean attr_command(struct client_s *client, gchar **req)
1593 if (!req || !req[0] || !req[1]) {
1594 send_error(client, EPWMD_COMMAND_SYNTAX);
1595 return FALSE;
1598 if (g_ascii_strcasecmp(req[0], "SET") == 0)
1599 return attribute_set(client, req+1);
1600 if (g_ascii_strcasecmp(req[0], "GET") == 0)
1601 return attribute_get(client, req+1);
1602 else if (g_ascii_strcasecmp(req[0], "DELETE") == 0)
1603 return attribute_delete(client, req+1);
1604 else if (g_ascii_strcasecmp(req[0], "LIST") == 0)
1605 return attribute_list(client, req+1);
1606 else
1607 send_error(client, EPWMD_COMMAND_SYNTAX);
1609 return FALSE;
1612 static gboolean cache_test(const guchar *md5filename, gint reset)
1614 void *p;
1615 file_cache_t f;
1616 glong len;
1618 for (p = shm_data, len = 0; len <= cache_size;) {
1619 memcpy(&f, p, sizeof(file_cache_t));
1621 if (reset == 2) {
1622 memset(&f, 0, sizeof(file_cache_t));
1623 memcpy(p, &f, sizeof(file_cache_t));
1624 p += sizeof(file_cache_t);
1625 len += sizeof(file_cache_t);
1627 if (len + sizeof(file_cache_t) > cache_size)
1628 break;
1629 continue;
1632 if (f.used == TRUE) {
1633 if (memcmp((gchar *)f.filename, (gchar *)md5filename, sizeof(f.filename)) == 0) {
1634 if (reset == 1) {
1635 memset(&f, 0, sizeof(file_cache_t));
1636 memcpy(p, &f, sizeof(file_cache_t));
1637 return TRUE;
1640 return (f.key[0]) ? TRUE : FALSE;
1644 p += sizeof(file_cache_t);
1645 len += sizeof(file_cache_t);
1647 if (len + sizeof(file_cache_t) > cache_size)
1648 break;
1651 return (reset == 2) ? TRUE : FALSE;
1654 static gboolean file_exists(const gchar *filename)
1656 struct stat st;
1658 if (access(filename, R_OK) == -1)
1659 return FALSE;
1661 stat(filename, &st);
1663 if (st.st_size == 0)
1664 return FALSE;
1666 return TRUE;
1669 gboolean cache_command(struct client_s *client, gchar **req)
1671 guchar md5file[16];
1673 if (g_ascii_strcasecmp(req[0], "clear") == 0) {
1674 if (!req[1]) {
1675 send_error(client, EPWMD_COMMAND_SYNTAX);
1676 return FALSE;
1679 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[1], strlen(req[1]));
1681 if (cache_test(md5file, 1) == FALSE) {
1682 send_error(client, EPWMD_CACHE_NOT_FOUND);
1683 return FALSE;
1686 return TRUE;
1688 else if (g_ascii_strcasecmp(req[0], "clearall") == 0) {
1689 cache_test(client->md5file, 2);
1690 return TRUE;
1692 else if (g_ascii_strcasecmp(req[0], "iscached") == 0) {
1693 if (!req[1]) {
1694 send_error(client, EPWMD_COMMAND_SYNTAX);
1695 return FALSE;
1698 if (file_exists(req[1]) == FALSE) {
1699 send_error(client, EPWMD_FILE_NOT_FOUND);
1700 return FALSE;
1703 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[1], strlen(req[1]));
1705 if (cache_test(md5file, 0) == FALSE) {
1706 send_error(client, EPWMD_CACHE_NOT_FOUND);
1707 return FALSE;
1710 return TRUE;
1712 else
1713 send_error(client, EPWMD_COMMAND_SYNTAX);
1715 return FALSE;
1718 gboolean help_command(struct client_s *client, const gchar *what)
1720 gchar *line;
1722 if (!what || !*what)
1723 line =
1724 "NFO Try 'HELP COMMAND' for command help\n"
1725 "NFO OPEN LIST GET STORE DELETE ATTR CACHE SAVE DUMP QUIT\n";
1726 else if (g_ascii_strcasecmp(what, "GET") == 0)
1727 line =
1728 "NFO syntax: GET account <TAB> element [<TAB> element ...]\n"
1729 "NFO <account> is the account to work on and <element>\n"
1730 "NFO is the element wanted.\n"
1731 "NFO -\n"
1732 "NFO Example: GET isp <TAB> imap <TAB> port\n"
1733 "NFO GET isp <TAB> username\n";
1734 else if (g_ascii_strcasecmp(what, "QUIT") == 0)
1735 line =
1736 "NFO syntax: QUIT\n"
1737 "NFO close the connection\n";
1738 else if (g_ascii_strcasecmp(what, "DELETE") == 0)
1739 line =
1740 "NFO syntax: DELETE account <TAB> element [<TAB> element ...]\n";
1741 else if (g_ascii_strcasecmp(what, "STORE") == 0)
1742 line =
1743 "NFO syntax: STORE account <TAB> element [<TAB> element ...] <TAB> value\n"
1744 "NFO <account> is the account to work on and <element>\n"
1745 "NFO is the element to create or modify\n"
1746 "NFO -\n"
1747 "NFO Example: STORE isp <TAB> imap <TAB> port <TAB> 993\n"
1748 "NFO STORE isp <TAB> username <TAB> someuser\n";
1749 else if (g_ascii_strcasecmp(what, "OPEN") == 0)
1750 line =
1751 "NFO syntax: OPEN <filename> [<key>]\n"
1752 "NFO opens a (new) file\n";
1753 else if (g_ascii_strcasecmp(what, "LIST") == 0)
1754 line =
1755 "NFO syntax: LIST [account]\n"
1756 "NFO shows available accounts or account elements\n";
1757 else if (g_ascii_strcasecmp(what, "ATTR") == 0)
1758 line =
1759 "NFO syntax: ATTR SET|GET|DELETE|LIST [ATTRIBUTE] arg1 [arg2]\n"
1760 "NFO ATTR SET NAME account value\n"
1761 "NFO ATTR SET TARGET account[<TAB>element[...]] account[<TAB>element[...]\n"
1762 "NFO ATTR SET attribute account[<TAB>element[...]] attribute_value\n"
1763 "NFO ATTR DELETE attribute account[<TAB>element[...]]\n"
1764 "NFO ATTR GET attribute account[<TAB>element[...]]\n"
1765 "NFO ATTR LIST account[<TAB>element[...]]\n";
1766 else if (g_ascii_strcasecmp(what, "SAVE") == 0)
1767 line =
1768 "NFO syntax: SAVE [<key>]\n"
1769 "NFO save any changes to the opened file using <key>\n";
1770 else if (g_ascii_strcasecmp(what, "CACHE") == 0)
1771 line =
1772 "NFO syntax: CACHE [CLEARALL | CLEAR <filename> | ISCACHED <filename>]\n"
1773 "NFO tests or clears the cache entry for <filename>\n";
1774 else if (g_ascii_strcasecmp(what, "DUMP") == 0)
1775 line =
1776 "NFO syntax: DUMP\n"
1777 "NFO shows the in memory XML document\n";
1778 else {
1779 send_error(client, EPWMD_COMMAND_SYNTAX);
1780 return FALSE;
1783 send_to_client(client, "%sOK \n", line);
1784 return TRUE;
1787 gboolean dump_command(struct client_s *client)
1789 xmlChar *xml;
1790 gssize len;
1792 xmlDocDumpFormatMemory(client->doc, &xml, &len, 1);
1793 send_to_client(client, "BEGIN %li\n%s", len, xml);
1794 xmlFree(xml);
1795 return TRUE;