Added EPWMD_FILE_MODIFIED. When the SAVE command tries to save to the
[pwmd.git] / src / commands.c
blobbad3c9357e9eb529f77e16fa94dfb976e2bb1444
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;
213 client->mtime = st.st_mtime;
216 gcry_md_hash_buffer(GCRY_MD_MD5, client->md5file, filename, strlen(filename));
219 * New files don't need a key.
221 if (access(filename, R_OK|W_OK) != 0) {
222 if (errno != ENOENT) {
223 send_to_client(client, "ERR %03i %s: %s\n", EPWMD_ERROR, filename,
224 strerror(errno));
225 return FALSE;
227 new_doc:
228 if ((client->xml = new_document()) == NULL) {
229 send_to_client(client, "ERR %03i malloc(): %s\n", EPWMD_ERROR,
230 strerror(errno));
231 return FALSE;
234 client->len = strlen(client->xml);
236 if (cache_add_file(client->md5file, NULL) == FALSE) {
237 send_error(client, EPWMD_MAX_SLOTS);
238 return FALSE;
241 client->filename = g_strdup(filename);
242 return parse_xml(client);
245 if ((fd = open_file(filename, &st)) == -1) {
246 send_to_client(client, "ERR %03i %s: %s\n", EPWMD_ERROR, filename, strerror(errno));
247 return FALSE;
250 if (st.st_size == 0)
251 goto new_doc;
253 if (cache_get_key(client->md5file, shakey) == TRUE)
254 cached = 1;
255 else {
257 * No key specified and no matching filename found in the cache.
259 if (!req[1] || !*req[1]) {
260 close(fd);
261 send_error(client, EPWMD_KEY);
262 return FALSE;
266 insize = st.st_size - sizeof(struct file_header_s);
267 read(fd, &file_header, sizeof(struct file_header_s));
268 inbuf = gcry_malloc(insize);
269 read(fd, inbuf, insize);
270 close(fd);
272 again:
273 if (!cached) {
274 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, req[1], strlen(req[1]));
275 memset(req[1], 0, strlen(req[1]));
278 memcpy(tkey, shakey, sizeof(tkey));
279 tkey[0] ^= 1;
281 if ((gcryerrno = gcry_cipher_setiv(client->gh, file_header.iv,
282 sizeof(file_header.iv)))) {
283 gcry_free(inbuf);
284 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(gcryerrno));
285 send_to_client(client, "ERR %03i gcrypt: %s\n", EPWMD_ERROR, gcry_strerror(gcryerrno));
286 return FALSE;
289 if ((gcryerrno = gcry_cipher_setkey(client->gh, shakey, gcrykeysize))) {
290 gcry_free(inbuf);
291 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(gcryerrno));
292 send_to_client(client, "ERR %03i gcrypt: %s\n", EPWMD_ERROR, gcry_strerror(gcryerrno));
293 return FALSE;
296 if (decrypt_xml(client->gh, inbuf, insize, NULL, 0) == FALSE) {
297 if (cached) {
298 cached = 0;
299 goto again;
302 gcry_free(inbuf);
303 send_to_client(client, "ERR %03i gcrypt: %s\n", EPWMD_ERROR, gcry_strerror(gcryerrno));
304 return FALSE;
307 if ((gcryerrno = gcry_cipher_setkey(client->gh, tkey, gcrykeysize))) {
308 gcry_free(inbuf);
309 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(gcryerrno));
310 send_to_client(client, "ERR %03i gcrypt: %s\n", EPWMD_ERROR, gcry_strerror(gcryerrno));
311 return FALSE;
314 iter = file_header.iter;
316 while (iter-- > 0) {
317 if ((gcryerrno = gcry_cipher_setiv(client->gh, file_header.iv,
318 sizeof(file_header.iv)))) {
319 gcry_free(inbuf);
320 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(gcryerrno));
321 send_to_client(client, "ERR %03i gcrypt: %s\n", EPWMD_ERROR, gcry_strerror(gcryerrno));
322 return FALSE;
325 if (decrypt_xml(client->gh, inbuf, insize, NULL, 0) == FALSE) {
326 if (cached) {
327 cached = 0;
328 goto again;
331 gcry_free(inbuf);
332 send_to_client(client, "ERR %03i gcrypt: %s\n", EPWMD_ERROR, gcry_strerror(gcryerrno));
333 return FALSE;
337 client->xml = inbuf;
338 client->len = insize;
340 if (g_strncasecmp(client->xml, "<?xml version=\"1.0\"?>", 21) != 0) {
341 send_error(client, EPWMD_BADKEY);
342 return FALSE;
345 if (!cached) {
346 if (cache_add_file(client->md5file, shakey) == FALSE) {
347 send_error(client, EPWMD_MAX_SLOTS);
348 return FALSE;
352 client->filename = g_strdup(filename);
353 return parse_xml(client);
357 * client->reader should be at the position in the document where the element
358 * search should start. It won't search past the closing account element.
360 static gboolean find_elements(struct client_s *client, xmlTextReaderPtr reader,
361 gchar **req, gint quiet)
363 gint i;
365 if (!req || !req[0]) {
366 if (!quiet)
367 send_error(client, EPWMD_COMMAND_SYNTAX);
368 return FALSE;
371 for (i = 0; req[i]; i++) {
372 if (find_element(reader, req[i], req[i+1] != NULL) == FALSE) {
373 if (!quiet)
374 send_error(client, EPWMD_ELEMENT_NOT_FOUND);
376 return FALSE;
380 return TRUE;
383 gboolean save_command(struct client_s *client, const gchar *filename, gchar *key)
385 xmlChar *xmlbuf;
386 gint insize;
387 void *inbuf;
388 gsize len = 0;
389 gint fd;
390 gint update = 1;
391 guchar shakey[gcrykeysize];
392 guchar tkey[gcrykeysize];
393 gint iter = client->iter;
394 struct stat st;
395 struct file_header_s {
396 guint iter;
397 guchar iv[gcryblocksize];
398 } file_header;
400 if (stat(filename, &st) == 0 && client->mtime) {
401 if (client->mtime != st.st_mtime) {
402 send_error(client, EPWMD_FILE_MODIFIED);
403 return FALSE;
407 if (!key || !key) {
408 if (cache_get_key(client->md5file, shakey) == FALSE) {
409 send_error(client, EPWMD_KEY);
410 return FALSE;
413 update = 0;
415 else {
416 gcry_md_hash_buffer(GCRY_MD_SHA256, shakey, key, strlen(key));
417 memset(key, 0, strlen(key));
420 xmlDocDumpFormatMemory(client->doc, &xmlbuf, &insize, 0);
421 len = insize;
423 if (insize / gcryblocksize) {
424 len = (insize / gcryblocksize) * gcryblocksize;
426 if (insize % gcryblocksize)
427 len += gcryblocksize;
430 inbuf = gcry_calloc(1, len);
431 memcpy(inbuf, xmlbuf, insize);
432 xmlFree(xmlbuf);
433 insize = len;
434 gcry_create_nonce(file_header.iv, sizeof(file_header.iv));
435 memcpy(tkey, shakey, sizeof(tkey));
436 tkey[0] ^= 1;
438 if ((gcryerrno = gcry_cipher_setkey(client->gh, tkey, gcrykeysize))) {
439 gcry_free(inbuf);
440 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(gcryerrno));
441 send_to_client(client, "ERR %03i gcrypt: %s\n", EPWMD_ERROR, gcry_strerror(gcryerrno));
442 return FALSE;
445 file_header.iter = iter;
447 while (iter-- > 0) {
448 if ((gcryerrno = gcry_cipher_setiv(client->gh, file_header.iv,
449 sizeof(file_header.iv)))) {
450 gcry_free(inbuf);
451 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(gcryerrno));
452 send_to_client(client, "ERR %03i gcrypt: %s\n", EPWMD_ERROR, gcry_strerror(gcryerrno));
453 return FALSE;
456 if (encrypt_xml(client->gh, inbuf, insize, NULL, 0)
457 == FALSE) {
458 gcry_free(inbuf);
459 send_to_client(client, "ERR %03i gcrypt: %s\n", EPWMD_ERROR, gcry_strerror(gcryerrno));
460 return FALSE;
464 if ((gcryerrno = gcry_cipher_setiv(client->gh, file_header.iv,
465 sizeof(file_header.iv)))) {
466 gcry_free(inbuf);
467 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(gcryerrno));
468 send_to_client(client, "ERR %03i gcrypt: %s\n", EPWMD_ERROR, gcry_strerror(gcryerrno));
469 return FALSE;
472 if ((gcryerrno = gcry_cipher_setkey(client->gh, shakey, gcrykeysize))) {
473 gcry_free(inbuf);
474 log_write("%s(%i): %s", __FUNCTION__, __LINE__, gcry_strerror(gcryerrno));
475 send_to_client(client, "ERR %03i gcrypt: %s\n", EPWMD_ERROR, gcry_strerror(gcryerrno));
476 return FALSE;
479 if (encrypt_xml(client->gh, inbuf, insize, NULL, 0)
480 == FALSE) {
481 gcry_free(inbuf);
482 send_to_client(client, "ERR %03i gcrypt: %s\n", EPWMD_ERROR, gcry_strerror(gcryerrno));
483 return FALSE;
486 if ((fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0600)) == -1) {
487 gcry_free(inbuf);
488 send_to_client(client, "ERR %03i %s: %s\n", EPWMD_ERROR, filename, strerror(errno));
489 return FALSE;
492 write(fd, &file_header, sizeof(struct file_header_s));
493 write(fd, inbuf, insize);
494 close(fd);
495 gcry_free(inbuf);
497 stat(filename, &st);
498 client->mtime = st.st_mtime;
500 if (!update)
501 return TRUE;
503 if (cache_update_key(client->md5file, shakey) == FALSE) {
504 send_error(client, EPWMD_MAX_SLOTS);
505 return FALSE;
508 return TRUE;
511 static gboolean contains_whitespace(const gchar *str)
513 const gchar *p = str;
515 for (; *p; p++) {
516 if (g_ascii_isspace(*p) == TRUE) {
517 return TRUE;
521 return FALSE;
525 * the 'reader' should be at the element of the document where the elements
526 * 'req' are to be created.
528 static gboolean create_elements(struct client_s *client, xmlTextReaderPtr reader,
529 gchar **req, gint novalue)
531 gint i;
532 gboolean ret = TRUE;
533 xmlNodePtr r;
535 r = xmlTextReaderCurrentNode(reader);
537 if (xmlTextReaderDepth(reader) > 1)
538 r = r->parent;
540 for (i = 0; req[i]; i++) {
541 xmlNodePtr n;
544 * Whitespace is allowed in values or attributes but not in element
545 * names.
547 if (req[i+1] && valid_xml_element((xmlChar *)req[i]) == FALSE) {
548 send_error(client, EPWMD_INVALID_ELEMENT);
549 return FALSE;
553 * The value of the element tree.
555 if (!req[i+1] && !novalue) {
557 * Prevent creating 'text' elements in the root of the account.
559 if (i < 1) {
560 send_error(client, EPWMD_ROOT_TEXT_ELEMENT);
561 return FALSE;
565 * FIXME ?? overwriting an element tree with a text element:
567 * STORE account element element2 value
568 * STORE account element value
570 * would remove the existing element tree. This may be a bug or
571 * feature.
573 xmlNodeSetContent(r, (xmlChar *)req[i]);
574 break;
577 if ((n = find_node(r, (xmlChar *)req[i])) == NULL) {
578 n = xmlNewNode(NULL, (xmlChar *)req[i]);
579 r = xmlAddChild(r, n);
581 else
582 r = n;
584 if (!req[i+1] && novalue)
585 return TRUE;
588 return ret;
592 * FIXME reuse reader handle
594 static gboolean reset_reader(xmlDocPtr doc, xmlTextReaderPtr *reader)
596 if (reader) {
597 xmlFreeTextReader(*reader);
598 *reader = NULL;
601 if ((*reader = xmlReaderWalker(doc)) == NULL)
602 return FALSE;
604 return TRUE;
607 static void delete_node(xmlNodePtr n)
609 xmlUnlinkNode(n);
610 xmlFreeNode(n);
613 gboolean delete_command(struct client_s *client, gchar **req)
615 gint i = 1;
616 xmlNodePtr n;
618 if (reset_reader(client->doc, &client->reader) == FALSE) {
619 send_error(client, EPWMD_LIBXML_ERROR);
620 return FALSE;
623 if (find_account(client->reader, req[0]) == FALSE) {
624 send_error(client, EPWMD_ELEMENT_NOT_FOUND);
625 return FALSE;
628 n = xmlTextReaderCurrentNode(client->reader);
631 * No sub-node defined. Remove the entire node (account).
633 if (!req[i]) {
634 if (n)
635 delete_node(n);
636 return TRUE;
640 * Remove matching sub-nodes starting from the root of the account.
642 while (req[i] && find_element(client->reader, req[i++], req[i] != NULL) == TRUE)
643 n = xmlTextReaderCurrentNode(client->reader);
645 if (n && xmlStrcmp(n->name, (xmlChar *)req[i-1]) == 0 &&
646 xmlTextReaderNodeType(client->reader) == XML_READER_TYPE_ELEMENT)
647 delete_node(n);
648 else {
649 send_error(client, EPWMD_ELEMENT_NOT_FOUND);
650 return FALSE;
653 return TRUE;
656 gboolean store_command(struct client_s *client, gchar **req)
658 again:
659 if (reset_reader(client->doc, &client->reader) == FALSE) {
660 send_error(client, EPWMD_LIBXML_ERROR);
661 return FALSE;
664 if (!req[0]) {
665 send_error(client, EPWMD_COMMAND_SYNTAX);
666 return FALSE;
669 if (find_account(client->reader, req[0]) == FALSE) {
670 if (contains_whitespace(req[0]) == TRUE) {
671 send_error(client, EPWMD_INVALID_ELEMENT);
672 return FALSE;
675 if (new_account(client->doc, req[0]) == FALSE) {
676 send_error(client, EPWMD_ERROR);
677 return FALSE;
680 goto again;
683 xmlTextReaderNext(client->reader);
684 return create_elements(client, client->reader, req+1, 0);
687 static gboolean do_get_command(struct client_s *client, xmlTextReaderPtr *reader,
688 gchar **req, xmlChar **content, gint quiet, gint list)
690 xmlNodePtr n;
691 xmlAttrPtr a;
692 gchar **nreq;
693 gboolean ret;
694 xmlChar *p;
696 if (reset_reader(client->doc, reader) == FALSE) {
697 if (!quiet)
698 send_error(client, EPWMD_LIBXML_ERROR);
699 return FALSE;
702 if (find_account(*reader, req[0]) == FALSE) {
703 if (!quiet && !list)
704 send_error(client, EPWMD_ELEMENT_NOT_FOUND);
705 return FALSE;
709 * May be an account with only a TARGET attribute.
711 if (req[1]) {
712 if (find_elements(client, *reader, req + 1, (list) ? 1 : quiet) == FALSE)
713 return FALSE;
716 if ((n = xmlTextReaderCurrentNode(*reader)) == NULL) {
717 if (!quiet)
718 send_error(client, EPWMD_LIBXML_ERROR);
719 return FALSE;
723 * If the current element has a TARGET attribute, the value of the
724 * attribute is an element path somewhere else in the document. Use this
725 * value and not any TEXT element value. The value may be another element
726 * with a TARGET attribute and this function will recurse until a non-TARGET
727 * attribute in the element is found.
729 if ((a = xmlHasProp(n, (xmlChar *)"target")) != NULL) {
730 if ((p = xmlNodeGetContent(a->children)) != NULL) {
731 if (strchr((gchar *)p, '\t') != NULL) {
732 if ((nreq = split_input_line((gchar *)p, "\t", 0)) == NULL) {
733 xmlFree(p);
735 if (!quiet)
736 send_error(client, EPWMD_INVALID_ELEMENT);
737 return FALSE;
740 else {
741 if ((nreq = split_input_line((gchar *)p, " ", 0)) == NULL) {
742 xmlFree(p);
744 if (!quiet)
745 send_error(client, EPWMD_INVALID_ELEMENT);
746 return FALSE;
750 xmlFree(p);
751 ret = do_get_command(client, reader, nreq, content, quiet, list);
752 g_strfreev(nreq);
753 return ret;
757 switch (xmlTextReaderNext(*reader)) {
758 case -1:
759 if (!quiet)
760 send_error(client, EPWMD_LIBXML_ERROR);
761 return FALSE;
762 case 0:
763 if (!quiet)
764 send_error(client, EPWMD_EMPTY_ELEMENT);
765 return FALSE;
766 default:
767 break;
770 switch (xmlTextReaderNodeType(*reader)) {
771 case XML_READER_TYPE_END_ELEMENT:
773 * May be an empty element after an ATTR DELETE TARGET command.
775 return TRUE;
776 case XML_READER_TYPE_TEXT:
777 break;
778 case -1:
779 if (!quiet)
780 send_error(client, EPWMD_LIBXML_ERROR);
782 return FALSE;
783 default:
784 if (!quiet) {
785 if (n->children && !list)
786 send_error(client, EPWMD_TRAILING_ELEMENT);
787 else if (!n->children && !list)
788 send_error(client, EPWMD_INVALID_ELEMENT);
790 return FALSE;
793 if ((*content = xmlNodeGetContent(n)) == NULL) {
794 if (!quiet)
795 send_error(client, EPWMD_EMPTY_ELEMENT);
796 return FALSE;
799 return TRUE;
803 * Retrieves the value associated with the element tree 'req'.
805 gboolean get_command(struct client_s *client, xmlTextReaderPtr *reader,
806 gchar **req, gint quiet)
808 xmlChar *content = NULL;
810 if (do_get_command(client, reader, req, &content, quiet, 0) == FALSE)
811 return FALSE;
813 if (!content) {
814 if (!quiet)
815 send_error(client, EPWMD_EMPTY_ELEMENT);
817 return FALSE;
820 send_to_client(client, "BEGIN %li\n%s\nOK \n", xmlStrlen(content), content);
821 xmlFree(content);
822 return TRUE;
825 #ifdef DEBUG
826 static gchar *element_path_to_req(const gchar *account, xmlChar *path,
827 const xmlChar *content)
828 #else
829 static gchar *element_path_to_req(const gchar *account, xmlChar *path)
830 #endif
832 xmlChar *p = path;
833 gint n;
834 gchar *buf;
836 if (!p)
837 return NULL;
839 for (n = 0; *p && n < 3; p++) {
840 if (*p == '/')
841 n++;
844 if (strstr((gchar *)p, "text()") != NULL)
845 p[xmlStrlen(p) - 7] = 0;
847 for (n = 0; p[n]; n++) {
848 if (p[n] == '/')
849 p[n] = '\t';
852 #ifdef DEBUG
853 buf = g_strdup_printf("%s\t%s\t%s", account, p, content);
854 #else
855 buf = g_strdup_printf("%s\t%s", account, p);
856 #endif
857 return buf;
860 static gboolean append_to_array(gchar ***array, gint *total, const gchar *str)
862 gchar **a;
863 gint t = *total;
865 if ((a = g_realloc(*array, (t + 2) * sizeof(gchar *))) == NULL)
866 return FALSE;
868 a[t++] = g_strdup(str);
869 a[t] = NULL;
870 *total = t;
871 *array = a;
872 return TRUE;
875 gboolean list_command(struct client_s *client, gchar *str)
877 gchar *dst = NULL;
878 gchar *p = str;
879 gchar **elements = NULL;
880 gint pwmd_errno = -1;
881 gchar *account;
882 gint total = 0;
883 xmlChar *path = NULL;
884 xmlAttrPtr a;
885 xmlNodePtr n;
886 xmlChar *content;
887 xmlTextReaderPtr r = NULL;
888 gchar **req = NULL, **nreq;
889 gboolean ret;
890 gint type;
891 gchar *line;
893 if (reset_reader(client->doc, &client->reader) == FALSE) {
894 send_error(client, EPWMD_LIBXML_ERROR);
895 return FALSE;
898 if (strchr(p, ' ') == NULL) {
899 list_only:
900 if (list_accounts(client->reader, &dst, &pwmd_errno) == FALSE) {
901 send_error(client, pwmd_errno);
902 return FALSE;
904 else {
905 send_to_client(client, "BEGIN %i\n%s\nOK \n",
906 g_utf8_strlen(dst, -1), dst);
907 memset(dst, 0, strlen(dst));
908 g_free(dst);
911 return TRUE;
914 p = str + 5;
916 while (*p && isspace(*p))
917 p++;
919 if (!*p)
920 goto list_only;
922 if (strchr(p, '\t') != NULL) {
923 if ((req = split_input_line(p, "\t", 0)) == NULL) {
924 send_error(client, EPWMD_COMMAND_SYNTAX);
925 return FALSE;
928 if (find_account(client->reader, req[0]) == FALSE) {
929 send_error(client, EPWMD_ELEMENT_NOT_FOUND);
930 return FALSE;
933 if (find_elements(client, client->reader, req + 1, 0) == FALSE) {
934 g_strfreev(req);
935 return FALSE;
938 else {
939 if (find_account(client->reader, p) == FALSE) {
940 send_error(client, EPWMD_ELEMENT_NOT_FOUND);
941 return FALSE;
945 if ((n = xmlTextReaderCurrentNode(client->reader)) == NULL) {
946 send_error(client, EPWMD_LIBXML_ERROR);
947 return FALSE;
950 if ((a = xmlHasProp(n, (xmlChar *)"target")) != NULL) {
951 if (reset_reader(client->doc, &client->reader) == FALSE) {
952 send_error(client, EPWMD_LIBXML_ERROR);
953 return FALSE;
956 if ((content = xmlNodeGetContent(a->children)) != NULL) {
957 if (find_account(client->reader, (gchar *)content) == FALSE) {
958 xmlFree(content);
959 send_error(client, EPWMD_ELEMENT_NOT_FOUND);
960 return FALSE;
963 xmlFree(content);
967 account = (req) ? g_strdup(req[0]) : g_strdup(p);
969 if (req)
970 g_strfreev(req);
972 while (xmlTextReaderNext(client->reader) == 1) {
973 again:
974 if ((n = xmlTextReaderCurrentNode(client->reader)) == NULL) {
975 send_error(client, EPWMD_LIBXML_ERROR);
976 return FALSE;
979 if (xmlTextReaderDepth(client->reader) == 1 &&
980 xmlStrcmp(n->name, (xmlChar *)"account") == 0 &&
981 xmlTextReaderNodeType(client->reader) == XML_READER_TYPE_END_ELEMENT)
982 break;
985 * If the current element has a TARGET attribute, the value of the
986 * attribute is an element path somewhere else in the document. Use this
987 * value and not any TEXT element value.
989 type = xmlTextReaderNodeType(client->reader);
990 a = xmlHasProp(n, (xmlChar *)"target");
992 if (type == XML_READER_TYPE_ELEMENT && a) {
993 if ((content = xmlNodeGetContent(a->children)) != NULL) {
994 path = xmlGetNodePath(n);
996 if ((nreq = split_input_line((gchar *)content, "\t", 0)) == NULL) {
997 if (elements)
998 g_strfreev(elements);
1000 xmlFree(path);
1001 xmlFree(content);
1002 send_error(client, EPWMD_INVALID_ELEMENT);
1003 return FALSE;
1006 xmlFree(content);
1007 r = NULL;
1009 if ((ret = do_get_command(client, &r, nreq, &content, 0, 1)) == TRUE) {
1010 if (content && *content) {
1011 #ifdef DEBUG
1012 line = element_path_to_req(account, path, content);
1013 #else
1014 line = element_path_to_req(account, path);
1015 #endif
1016 xmlFree(content);
1018 if (append_to_array(&elements, &total, line) == FALSE) {
1019 if (elements)
1020 g_strfreev(elements);
1022 xmlFree(path);
1023 memset(line, 0, g_utf8_strlen(line, -1));
1024 g_free(line);
1025 g_strfreev(nreq);
1026 xmlFreeTextReader(r);
1027 send_error(client, EPWMD_ERROR);
1028 return FALSE;
1031 memset(line, 0, g_utf8_strlen(line, -1));
1032 g_free(line);
1035 if (xmlTextReaderNext(client->reader) == 1) {
1036 if (xmlTextReaderNodeType(client->reader) !=
1037 XML_READER_TYPE_TEXT) {
1038 g_strfreev(nreq);
1039 xmlFreeTextReader(r);
1040 xmlFree(path);
1041 goto again;
1046 g_strfreev(nreq);
1047 xmlFreeTextReader(r);
1048 xmlFree(path);
1049 continue;
1053 if (type == XML_READER_TYPE_TEXT) {
1054 xmlChar *np = xmlGetNodePath(n);
1056 #ifdef DEBUG
1057 content = xmlNodeGetContent(n);
1058 line = element_path_to_req(account, np, content);
1059 xmlFree(content);
1060 #else
1061 line = element_path_to_req(account, np);
1062 #endif
1063 xmlFree(np);
1064 append_to_array(&elements, &total, line);
1065 memset(line, 0, g_utf8_strlen(line, -1));
1066 g_free(line);
1070 if (!elements) {
1071 send_error(client, EPWMD_EMPTY_ELEMENT);
1072 g_free(account);
1073 return FALSE;
1076 g_free(account);
1077 line = g_strjoinv("\n", elements);
1078 send_to_client(client, "BEGIN %li\n%s\nOK \n",
1079 g_utf8_strlen(line, -1), line);
1080 g_strfreev(elements);
1081 g_free(line);
1082 return TRUE;
1086 * The client->reader handle should be at the element in the document where
1087 * the attribute will be created or modified.
1089 static gboolean add_attribute(struct client_s *client, const gchar *name, const gchar *value)
1091 xmlAttrPtr a;
1092 xmlNodePtr n;
1094 if ((n = xmlTextReaderCurrentNode(client->reader)) == NULL) {
1095 send_error(client, EPWMD_LIBXML_ERROR);
1096 return FALSE;
1099 if ((a = xmlHasProp(n, (xmlChar *)name)) == NULL)
1100 a = xmlNewProp(n, (xmlChar *)name, (xmlChar *)value);
1101 else
1102 xmlNodeSetContent(a->children, (xmlChar *)value);
1104 return TRUE;
1108 * req[0] - element path
1110 static gboolean attribute_list(struct client_s *client, gchar **req)
1112 gchar **attrlist = NULL;
1113 gint i = 0;
1114 gchar **epath = NULL;
1115 xmlAttrPtr a;
1116 xmlNodePtr n, an;
1117 gchar *line;
1119 if (!req || !req[0]) {
1120 send_error(client, EPWMD_COMMAND_SYNTAX);
1121 return FALSE;
1124 if ((epath = split_input_line(req[0], "\t", 0)) == NULL) {
1126 * The first argument may be only an account.
1128 if ((epath = split_input_line(req[0], " ", 0)) == NULL) {
1129 send_error(client, EPWMD_COMMAND_SYNTAX);
1130 return FALSE;
1134 if (reset_reader(client->doc, &client->reader) == FALSE) {
1135 send_error(client, EPWMD_LIBXML_ERROR);
1136 goto blah;
1139 if (find_account(client->reader, epath[0]) == FALSE) {
1140 send_error(client, EPWMD_ELEMENT_NOT_FOUND);
1141 goto blah;
1144 if (epath[1]) {
1145 if ((find_elements(client, client->reader, epath+1, 0)) == FALSE)
1146 goto blah;
1149 if ((n = xmlTextReaderCurrentNode(client->reader)) == NULL) {
1150 send_error(client, EPWMD_LIBXML_ERROR);
1151 goto blah;
1154 for (a = n->properties; a; a = a->next) {
1155 if ((attrlist = g_realloc(attrlist, (i + 2) * sizeof(gchar *))) == NULL) {
1156 send_error(client, EPWMD_ERROR);
1157 goto blah;
1160 an = a->children;
1161 attrlist[i++] = g_strdup_printf("%s\t%s", (gchar *)a->name, (gchar *)an->content);
1162 attrlist[i] = NULL;
1165 if (!attrlist) {
1166 send_error(client, EPWMD_EMPTY_ELEMENT);
1167 goto blah;
1170 line = g_strjoinv("\n", attrlist);
1171 send_to_client(client, "BEGIN %li\n%s\n", g_utf8_strlen(line, -1), line);
1172 g_free(line);
1173 g_strfreev(epath);
1174 g_strfreev(attrlist);
1175 return TRUE;
1176 blah:
1177 g_strfreev(epath);
1178 return FALSE;
1182 * req[0] - attribute
1183 * req[1] - element path
1185 static gboolean attribute_delete(struct client_s *client, gchar **req)
1187 xmlAttrPtr a;
1188 xmlNodePtr n;
1189 gchar **epath = NULL;
1191 if (!req || !req[0] || !req[1]) {
1192 send_error(client, EPWMD_COMMAND_SYNTAX);
1193 return FALSE;
1196 if ((epath = split_input_line(req[1], "\t", 0)) == NULL) {
1198 * The first argument may be only an account.
1200 if ((epath = split_input_line(req[1], " ", 0)) == NULL) {
1201 send_error(client, EPWMD_COMMAND_SYNTAX);
1202 return FALSE;
1207 * Don't remove the NAME attribute for the account element.
1209 if (!epath[1] && g_ascii_strcasecmp(req[0], "NAME") == 0) {
1210 send_error(client, EPWMD_ATTR_SYNTAX);
1211 goto blah;
1214 if (reset_reader(client->doc, &client->reader) == FALSE) {
1215 send_error(client, EPWMD_LIBXML_ERROR);
1216 goto blah;
1219 if (find_account(client->reader, epath[0]) == FALSE) {
1220 send_error(client, EPWMD_ELEMENT_NOT_FOUND);
1221 goto blah;
1224 if (epath[1]) {
1225 if ((find_elements(client, client->reader, epath+1, 0)) == FALSE)
1226 goto blah;
1229 if ((n = xmlTextReaderCurrentNode(client->reader)) == NULL) {
1230 send_error(client, EPWMD_LIBXML_ERROR);
1231 goto blah;
1234 if ((a = xmlHasProp(n, (xmlChar *)req[0])) == NULL) {
1235 send_error(client, EPWMD_ATTR_NOT_FOUND);
1236 goto blah;
1239 if (xmlRemoveProp(a) == -1) {
1240 send_error(client, EPWMD_LIBXML_ERROR);
1241 goto blah;
1244 g_strfreev(epath);
1245 return TRUE;
1246 blah:
1247 g_strfreev(epath);
1248 return FALSE;
1252 * req[0] - source element path
1253 * req[1] - destination element path
1255 static gboolean target_attribute(struct client_s *client, gchar **req)
1257 gchar **src, **dst, *line;
1259 if (!req || !req[0] || !req[1]) {
1260 send_error(client, EPWMD_COMMAND_SYNTAX);
1261 return FALSE;
1264 if ((src = split_input_line(req[0], "\t", 0)) == NULL) {
1266 * The first argument may be only an account.
1268 if ((src = split_input_line(req[0], " ", 0)) == NULL) {
1269 send_error(client, EPWMD_COMMAND_SYNTAX);
1270 return FALSE;
1274 if ((dst = split_input_line(req[1], "\t", 0)) == NULL) {
1276 * The first argument may be only an account.
1278 if ((dst = split_input_line(req[1], " ", 0)) == NULL) {
1279 send_error(client, EPWMD_COMMAND_SYNTAX);
1280 g_strfreev(src);
1281 goto blah;
1286 * Prevent an element tree pointing to only and account. Accounts require
1287 * at least one element. Accounts pointing to accounts are allowed.
1289 if ((!src[1] && dst[1]) || (!dst[1] && src[1])) {
1290 send_error(client, EPWMD_ATTR_SYNTAX);
1291 g_strfreev(src);
1292 g_strfreev(dst);
1293 goto blah;
1296 if (reset_reader(client->doc, &client->reader) == FALSE) {
1297 send_error(client, EPWMD_LIBXML_ERROR);
1298 g_strfreev(src);
1299 g_strfreev(dst);
1300 goto blah;
1304 * Make sure the destination element path exists.
1306 if (find_account(client->reader, dst[0]) == FALSE) {
1307 send_error(client, EPWMD_ELEMENT_NOT_FOUND);
1308 g_strfreev(src);
1309 g_strfreev(dst);
1310 goto blah;
1313 if (dst[1]) {
1314 if (find_elements(client, client->reader, dst+1, 0) == FALSE) {
1315 g_strfreev(src);
1316 g_strfreev(dst);
1317 goto blah;
1321 if (reset_reader(client->doc, &client->reader) == FALSE) {
1322 send_error(client, EPWMD_LIBXML_ERROR);
1323 g_strfreev(src);
1324 g_strfreev(dst);
1325 goto blah;
1329 * If the source element tree doesn't exist, create it.
1331 if (find_account(client->reader, src[0]) == FALSE) {
1332 if (new_account(client->doc, src[0]) == FALSE) {
1333 send_error(client, EPWMD_LIBXML_ERROR);
1334 g_strfreev(src);
1335 g_strfreev(dst);
1336 goto blah;
1339 if (reset_reader(client->doc, &client->reader) == FALSE) {
1340 send_error(client, EPWMD_LIBXML_ERROR);
1341 g_strfreev(src);
1342 g_strfreev(dst);
1343 goto blah;
1346 if (find_account(client->reader, src[0]) == FALSE) {
1347 send_error(client, EPWMD_ELEMENT_NOT_FOUND);
1348 g_strfreev(src);
1349 g_strfreev(dst);
1350 goto blah;
1354 if (src[1]) {
1355 if (find_elements(client, client->reader, src+1, 1) == FALSE) {
1356 if (reset_reader(client->doc, &client->reader) == FALSE) {
1357 send_error(client, EPWMD_LIBXML_ERROR);
1358 g_strfreev(src);
1359 g_strfreev(dst);
1360 goto blah;
1363 if (find_account(client->reader, src[0]) == FALSE) {
1364 send_error(client, EPWMD_ELEMENT_NOT_FOUND);
1365 g_strfreev(src);
1366 g_strfreev(dst);
1367 goto blah;
1370 xmlTextReaderNext(client->reader);
1372 if (create_elements(client, client->reader, src+1, 1) == FALSE) {
1373 g_strfreev(src);
1374 g_strfreev(dst);
1375 goto blah;
1378 if (reset_reader(client->doc, &client->reader) == FALSE) {
1379 send_error(client, EPWMD_LIBXML_ERROR);
1380 g_strfreev(src);
1381 g_strfreev(dst);
1382 goto blah;
1385 if (find_account(client->reader, src[0]) == FALSE) {
1386 send_error(client, EPWMD_ELEMENT_NOT_FOUND);
1387 g_strfreev(src);
1388 g_strfreev(dst);
1389 goto blah;
1392 if (find_elements(client, client->reader, src+1, 0) == FALSE) {
1393 g_strfreev(src);
1394 g_strfreev(dst);
1395 goto blah;
1400 line = g_strjoinv("\t", dst);
1402 if (add_attribute(client, "target", line) == FALSE) {
1403 g_free(line);
1404 g_strfreev(src);
1405 g_strfreev(dst);
1406 goto blah;
1409 g_strfreev(src);
1410 g_strfreev(dst);
1411 g_free(line);
1412 return TRUE;
1413 blah:
1414 g_strfreev(src);
1415 g_strfreev(dst);
1416 return FALSE;
1420 * req[0] - account name
1421 * req[1] - new name
1423 static gboolean name_attribute(struct client_s *client, gchar **req)
1425 if (reset_reader(client->doc, &client->reader) == FALSE) {
1426 send_error(client, EPWMD_LIBXML_ERROR);
1427 return FALSE;
1430 if (find_account(client->reader, req[0]) == FALSE) {
1431 send_error(client, EPWMD_ELEMENT_NOT_FOUND);
1432 return FALSE;
1435 if (strcmp(req[0], req[1]) == 0)
1436 return TRUE;
1438 if (reset_reader(client->doc, &client->reader) == FALSE) {
1439 send_error(client, EPWMD_LIBXML_ERROR);
1440 return FALSE;
1444 * Will not overwrite an existing account.
1446 if (find_account(client->reader, req[1]) == TRUE) {
1447 send_error(client, EPWMD_ACCOUNT_EXISTS);
1448 return FALSE;
1451 if (reset_reader(client->doc, &client->reader) == FALSE) {
1452 send_error(client, EPWMD_LIBXML_ERROR);
1453 return FALSE;
1456 if (find_account(client->reader, req[0]) == FALSE) {
1457 send_error(client, EPWMD_ELEMENT_NOT_FOUND);
1458 return FALSE;
1462 * Whitespace not allowed in account names.
1464 if (contains_whitespace(req[1]) == TRUE) {
1465 send_error(client, EPWMD_ATTR_SYNTAX);
1466 return FALSE;
1469 return add_attribute(client, "name", req[1]);
1473 * req[0] - attribute
1474 * req[1] - element path
1476 * If the element has a "target" attribute it won't be "followed".
1478 static gboolean attribute_get(struct client_s *client, gchar **req)
1480 xmlNodePtr n;
1481 xmlChar *a;
1482 gchar **nreq = NULL;
1484 if (!req || !req[0] || !req[1]) {
1485 send_error(client, EPWMD_COMMAND_SYNTAX);
1486 return FALSE;
1489 if (strchr(req[1], '\t')) {
1490 if ((nreq = split_input_line(req[1], "\t", 0)) == NULL) {
1491 send_error(client, EPWMD_COMMAND_SYNTAX);
1492 return FALSE;
1495 else {
1496 if ((nreq = split_input_line(req[1], " ", 0)) == NULL) {
1497 send_error(client, EPWMD_COMMAND_SYNTAX);
1498 return FALSE;
1502 if (reset_reader(client->doc, &client->reader) == FALSE) {
1503 g_strfreev(nreq);
1504 send_error(client, EPWMD_LIBXML_ERROR);
1505 return FALSE;
1508 if (find_account(client->reader, nreq[0]) == FALSE) {
1509 g_strfreev(nreq);
1510 send_error(client, EPWMD_ELEMENT_NOT_FOUND);
1511 return FALSE;
1514 if (nreq[1]) {
1515 if (find_elements(client, client->reader, nreq + 1, 0) == FALSE) {
1516 g_strfreev(nreq);
1517 return FALSE;
1521 g_strfreev(nreq);
1523 if ((n = xmlTextReaderCurrentNode(client->reader)) == NULL) {
1524 send_error(client, EPWMD_LIBXML_ERROR);
1525 return FALSE;
1528 if ((a = xmlGetProp(n, (xmlChar *)req[0])) == NULL) {
1529 send_error(client, EPWMD_ATTR_NOT_FOUND);
1530 return FALSE;
1533 send_to_client(client, "BEGIN %li\n%s\n", xmlStrlen(a), a);
1534 xmlFree(a);
1535 return TRUE;
1539 * req[0] - attribute
1540 * req[1] - element path
1541 * req[2] - value
1543 static gboolean attribute_set(struct client_s *client, gchar **req)
1545 gchar **epath = NULL;
1547 if (!req || !req[0] || !req[1] || !req[2]) {
1548 send_error(client, EPWMD_COMMAND_SYNTAX);
1549 return FALSE;
1553 * Reserved attribute names.
1555 if (g_ascii_strcasecmp(req[0], "NAME") == 0) {
1557 * Only reserved for the account element. Not the rest of the
1558 * document.
1560 if (strchr(req[1], '\t') == NULL)
1561 return name_attribute(client, req + 1);
1563 else if (g_ascii_strcasecmp(req[0], "TARGET") == 0)
1564 return target_attribute(client, req + 1);
1566 if ((epath = split_input_line(req[1], "\t", 0)) == NULL) {
1568 * The first argument may be only an account.
1570 if ((epath = split_input_line(req[1], " ", 0)) == NULL) {
1571 send_error(client, EPWMD_COMMAND_SYNTAX);
1572 return FALSE;
1576 if (reset_reader(client->doc, &client->reader) == FALSE) {
1577 send_error(client, EPWMD_LIBXML_ERROR);
1578 goto blah;
1581 if (find_account(client->reader, epath[0]) == FALSE) {
1582 send_error(client, EPWMD_ELEMENT_NOT_FOUND);
1583 goto blah;
1586 if (epath[1]) {
1587 if ((find_elements(client, client->reader, epath+1, 0)) == FALSE)
1588 goto blah;
1591 g_strfreev(epath);
1592 return add_attribute(client, req[0], req[2]);
1593 blah:
1594 g_strfreev(epath);
1595 return FALSE;
1599 * req[0] - command
1600 * req[1] - attribute name or element path if command is LIST
1601 * req[2] - element path
1602 * req[2] - element path or value
1604 gboolean attr_command(struct client_s *client, gchar **req)
1606 if (!req || !req[0] || !req[1]) {
1607 send_error(client, EPWMD_COMMAND_SYNTAX);
1608 return FALSE;
1611 if (g_ascii_strcasecmp(req[0], "SET") == 0)
1612 return attribute_set(client, req+1);
1613 if (g_ascii_strcasecmp(req[0], "GET") == 0)
1614 return attribute_get(client, req+1);
1615 else if (g_ascii_strcasecmp(req[0], "DELETE") == 0)
1616 return attribute_delete(client, req+1);
1617 else if (g_ascii_strcasecmp(req[0], "LIST") == 0)
1618 return attribute_list(client, req+1);
1619 else
1620 send_error(client, EPWMD_COMMAND_SYNTAX);
1622 return FALSE;
1625 static gboolean cache_test(const guchar *md5filename, gint reset)
1627 void *p;
1628 file_cache_t f;
1629 glong len;
1631 for (p = shm_data, len = 0; len <= cache_size;) {
1632 memcpy(&f, p, sizeof(file_cache_t));
1634 if (reset == 2) {
1635 memset(&f, 0, sizeof(file_cache_t));
1636 memcpy(p, &f, sizeof(file_cache_t));
1637 p += sizeof(file_cache_t);
1638 len += sizeof(file_cache_t);
1640 if (len + sizeof(file_cache_t) > cache_size)
1641 break;
1642 continue;
1645 if (f.used == TRUE) {
1646 if (memcmp((gchar *)f.filename, (gchar *)md5filename, sizeof(f.filename)) == 0) {
1647 if (reset == 1) {
1648 memset(&f, 0, sizeof(file_cache_t));
1649 memcpy(p, &f, sizeof(file_cache_t));
1650 return TRUE;
1653 return (f.key[0]) ? TRUE : FALSE;
1657 p += sizeof(file_cache_t);
1658 len += sizeof(file_cache_t);
1660 if (len + sizeof(file_cache_t) > cache_size)
1661 break;
1664 return (reset == 2) ? TRUE : FALSE;
1667 static gboolean file_exists(const gchar *filename)
1669 struct stat st;
1671 if (access(filename, R_OK) == -1)
1672 return FALSE;
1674 stat(filename, &st);
1676 if (st.st_size == 0)
1677 return FALSE;
1679 return TRUE;
1682 gboolean cache_command(struct client_s *client, gchar **req)
1684 guchar md5file[16];
1686 if (g_ascii_strcasecmp(req[0], "clear") == 0) {
1687 if (!req[1]) {
1688 send_error(client, EPWMD_COMMAND_SYNTAX);
1689 return FALSE;
1692 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[1], strlen(req[1]));
1694 if (cache_test(md5file, 1) == FALSE) {
1695 send_error(client, EPWMD_CACHE_NOT_FOUND);
1696 return FALSE;
1699 return TRUE;
1701 else if (g_ascii_strcasecmp(req[0], "clearall") == 0) {
1702 cache_test(client->md5file, 2);
1703 return TRUE;
1705 else if (g_ascii_strcasecmp(req[0], "iscached") == 0) {
1706 if (!req[1]) {
1707 send_error(client, EPWMD_COMMAND_SYNTAX);
1708 return FALSE;
1711 if (file_exists(req[1]) == FALSE) {
1712 send_error(client, EPWMD_FILE_NOT_FOUND);
1713 return FALSE;
1716 gcry_md_hash_buffer(GCRY_MD_MD5, md5file, req[1], strlen(req[1]));
1718 if (cache_test(md5file, 0) == FALSE) {
1719 send_error(client, EPWMD_CACHE_NOT_FOUND);
1720 return FALSE;
1723 return TRUE;
1725 else
1726 send_error(client, EPWMD_COMMAND_SYNTAX);
1728 return FALSE;
1731 gboolean help_command(struct client_s *client, const gchar *what)
1733 gchar *line;
1735 if (!what || !*what)
1736 line =
1737 "NFO Try 'HELP COMMAND' for command help\n"
1738 "NFO OPEN LIST GET STORE DELETE ATTR CACHE SAVE DUMP QUIT\n";
1739 else if (g_ascii_strcasecmp(what, "GET") == 0)
1740 line =
1741 "NFO syntax: GET account <TAB> element [<TAB> element ...]\n"
1742 "NFO <account> is the account to work on and <element>\n"
1743 "NFO is the element wanted.\n"
1744 "NFO -\n"
1745 "NFO Example: GET isp <TAB> imap <TAB> port\n"
1746 "NFO GET isp <TAB> username\n";
1747 else if (g_ascii_strcasecmp(what, "QUIT") == 0)
1748 line =
1749 "NFO syntax: QUIT\n"
1750 "NFO close the connection\n";
1751 else if (g_ascii_strcasecmp(what, "DELETE") == 0)
1752 line =
1753 "NFO syntax: DELETE account <TAB> element [<TAB> element ...]\n";
1754 else if (g_ascii_strcasecmp(what, "STORE") == 0)
1755 line =
1756 "NFO syntax: STORE account <TAB> element [<TAB> element ...] <TAB> value\n"
1757 "NFO <account> is the account to work on and <element>\n"
1758 "NFO is the element to create or modify\n"
1759 "NFO -\n"
1760 "NFO Example: STORE isp <TAB> imap <TAB> port <TAB> 993\n"
1761 "NFO STORE isp <TAB> username <TAB> someuser\n";
1762 else if (g_ascii_strcasecmp(what, "OPEN") == 0)
1763 line =
1764 "NFO syntax: OPEN <filename> [<key>]\n"
1765 "NFO opens a (new) file\n";
1766 else if (g_ascii_strcasecmp(what, "LIST") == 0)
1767 line =
1768 "NFO syntax: LIST [account]\n"
1769 "NFO shows available accounts or account elements\n";
1770 else if (g_ascii_strcasecmp(what, "ATTR") == 0)
1771 line =
1772 "NFO syntax: ATTR SET|GET|DELETE|LIST [ATTRIBUTE] arg1 [arg2]\n"
1773 "NFO ATTR SET NAME account value\n"
1774 "NFO ATTR SET TARGET account[<TAB>element[...]] account[<TAB>element[...]\n"
1775 "NFO ATTR SET attribute account[<TAB>element[...]] attribute_value\n"
1776 "NFO ATTR DELETE attribute account[<TAB>element[...]]\n"
1777 "NFO ATTR GET attribute account[<TAB>element[...]]\n"
1778 "NFO ATTR LIST account[<TAB>element[...]]\n";
1779 else if (g_ascii_strcasecmp(what, "SAVE") == 0)
1780 line =
1781 "NFO syntax: SAVE [<key>]\n"
1782 "NFO save any changes to the opened file using <key>\n";
1783 else if (g_ascii_strcasecmp(what, "CACHE") == 0)
1784 line =
1785 "NFO syntax: CACHE [CLEARALL | CLEAR <filename> | ISCACHED <filename>]\n"
1786 "NFO tests or clears the cache entry for <filename>\n";
1787 else if (g_ascii_strcasecmp(what, "DUMP") == 0)
1788 line =
1789 "NFO syntax: DUMP\n"
1790 "NFO shows the in memory XML document\n";
1791 else {
1792 send_error(client, EPWMD_COMMAND_SYNTAX);
1793 return FALSE;
1796 send_to_client(client, "%sOK \n", line);
1797 return TRUE;
1800 gboolean dump_command(struct client_s *client)
1802 xmlChar *xml;
1803 gssize len;
1805 xmlDocDumpFormatMemory(client->doc, &xml, &len, 1);
1806 send_to_client(client, "BEGIN %li\n%s", len, xml);
1807 xmlFree(xml);
1808 return TRUE;