1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
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
24 #include <sys/types.h>
29 #include <glib/gprintf.h>
38 #include "pwmd_error.h"
41 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
));
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
));
63 static gboolean
parse_xml(struct client_s
*client
)
65 xmlErrorPtr xml_error
;
67 switch (open_xml(client
->xml
, client
->len
, &client
->doc
, &client
->reader
)) {
69 xml_error
= xmlGetLastError();
70 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
71 send_error(client
, EPWMD_LIBXML_ERROR
);
74 xml_error
= xmlGetLastError();
75 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
76 send_error(client
, EPWMD_LIBXML_ERROR
);
85 static gboolean
valid_filename(const gchar
*filename
)
89 if (!filename
|| !*filename
)
92 for (p
= filename
; *p
; p
++) {
93 if (g_ascii_isalnum(*p
) == FALSE
)
100 static gboolean
cache_reset_timeout(const guchar
*md5filename
)
106 for (p
= shm_data
, len
= 0; len
<= cache_size
;) {
107 memcpy(&f
, p
, sizeof(file_cache_t
));
109 if (memcmp((gchar
*)f
.filename
, (gchar
*)md5filename
, sizeof(f
.filename
)) == 0) {
112 memcpy(p
, &f
, sizeof(file_cache_t
));
116 p
+= sizeof(file_cache_t
);
117 len
+= sizeof(file_cache_t
);
119 if (len
+ sizeof(file_cache_t
) > cache_size
)
126 gboolean
cache_set_timeout(const guchar
*md5filename
, glong timeout
)
132 for (p
= shm_data
, len
= 0; len
<= cache_size
;) {
133 memcpy(&f
, p
, sizeof(file_cache_t
));
136 if (memcmp((gchar
*)f
.filename
, (gchar
*)md5filename
, sizeof(f
.filename
)) == 0) {
138 f
.when
= f
.timeout
= timeout
;
139 memcpy(p
, &f
, sizeof(file_cache_t
));
145 f
.when
= f
.timeout
= timeout
;
146 memcpy(p
, &f
, sizeof(file_cache_t
));
149 p
+= sizeof(file_cache_t
);
150 len
+= sizeof(file_cache_t
);
152 if (len
+ sizeof(file_cache_t
) > cache_size
)
156 return (md5filename
) ? FALSE
: TRUE
;
159 static gboolean
cache_update_key(const guchar
*md5filename
, const guchar
*shakey
)
165 for (p
= shm_data
, len
= 0; len
<= cache_size
;) {
166 memcpy(&f
, p
, sizeof(file_cache_t
));
168 if (f
.used
== TRUE
) {
169 if (memcmp((gchar
*)f
.filename
, (gchar
*)md5filename
, sizeof(f
.filename
)) == 0) {
170 memcpy(&f
.key
, shakey
, sizeof(f
.key
));
171 memcpy(p
, &f
, sizeof(file_cache_t
));
176 p
+= sizeof(file_cache_t
);
177 len
+= sizeof(file_cache_t
);
179 if (len
+ sizeof(file_cache_t
) > cache_size
)
183 return cache_add_file(md5filename
, shakey
);
186 static gint
cache_valid_key(const guchar
*key
, gsize len
)
190 for (b
= 0; b
< len
; b
++) {
198 static gboolean
cache_get_key(const guchar
*md5file
, guchar
*shakey
)
204 for (p
= shm_data
, len
= 0; len
<= cache_size
;) {
205 memcpy(&f
, p
, sizeof(file_cache_t
));
208 * The slot may be used but not yet contain a key.
210 if (f
.used
== TRUE
) {
211 if (memcmp(&f
.filename
, md5file
, sizeof(f
.filename
)) == 0) {
212 if (cache_valid_key(f
.key
, sizeof(f
.key
)) == FALSE
)
215 memcpy(shakey
, &f
.key
, sizeof(f
.key
));
220 p
+= sizeof(file_cache_t
);
221 len
+= sizeof(file_cache_t
);
223 if (len
+ sizeof(file_cache_t
) > cache_size
)
230 gint
open_file(const gchar
*filename
, struct stat
*st
)
234 if ((fd
= open(filename
, O_RDONLY
)) == -1)
237 if (stat(filename
, st
) == -1) {
245 gboolean
open_command(struct client_s
*client
, gchar
**req
)
250 const gchar
*filename
= req
[0];
251 guchar shakey
[gcrykeysize
];
252 guchar tkey
[gcrykeysize
];
257 gchar filebuf
[PATH_MAX
], *p
, *p2
;
259 struct file_header_s
{
261 guchar iv
[gcryblocksize
];
264 if (!filename
|| !*filename
) {
265 send_error(client
, EPWMD_COMMAND_SYNTAX
);
269 if (valid_filename(filename
) == FALSE
) {
270 send_error(client
, EPWMD_INVALID_FILENAME
);
274 p
= get_key_file_string("default", "data_directory");
275 p2
= expand_homedir(p
);
277 snprintf(filebuf
, sizeof(filebuf
), "%s/%s", p2
, filename
);
280 if (stat(filebuf
, &st
) == 0) {
281 if (!S_ISREG(st
.st_mode
) && !S_ISLNK(st
.st_mode
)) {
282 log_write("%s: %s", filename
, pwmd_strerror(EPWMD_NOT_A_FILE
));
283 send_to_client(client
, "ERR %03i %s\n", EPWMD_NOT_A_FILE
, pwmd_strerror(EPWMD_NOT_A_FILE
));
287 client
->mtime
= st
.st_mtime
;
290 gcry_md_hash_buffer(GCRY_MD_MD5
, client
->md5file
, filename
, strlen(filename
));
293 * New files don't need a key.
295 if (access(filebuf
, R_OK
|W_OK
) != 0) {
296 if (errno
!= ENOENT
) {
298 log_write("%s: %s", filename
, strerror(errno
));
299 send_to_client(client
, "ERR %03i %s: %s\n", EPWMD_ERROR
, filename
,
304 if ((client
->xml
= new_document()) == NULL
) {
306 log_write("%s", strerror(errno
));
307 send_to_client(client
, "ERR %03i malloc(): %s\n", EPWMD_ERROR
,
312 client
->len
= strlen(client
->xml
);
314 if (cache_add_file(client
->md5file
, NULL
) == FALSE
) {
315 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(EPWMD_MAX_SLOTS
));
316 send_error(client
, EPWMD_MAX_SLOTS
);
320 client
->filename
= g_strdup(filename
);
321 return parse_xml(client
);
324 if ((fd
= open_file(filebuf
, &st
)) == -1) {
326 log_write("%s: %s", filename
, strerror(errno
));
327 send_to_client(client
, "ERR %03i %s: %s\n", EPWMD_ERROR
, filename
, strerror(error
));
334 if (cache_get_key(client
->md5file
, shakey
) == TRUE
)
338 * No key specified and no matching filename found in the cache.
340 if (!req
[1] || !*req
[1]) {
342 send_error(client
, EPWMD_KEY
);
347 insize
= st
.st_size
- sizeof(struct file_header_s
);
348 read(fd
, &file_header
, sizeof(struct file_header_s
));
349 inbuf
= gcry_malloc(insize
);
350 read(fd
, inbuf
, insize
);
355 gcry_md_hash_buffer(GCRY_MD_SHA256
, shakey
, req
[1], strlen(req
[1]));
356 memset(req
[1], 0, strlen(req
[1]));
359 if ((gcryerrno
= gcry_cipher_setiv(client
->gh
, file_header
.iv
,
360 sizeof(file_header
.iv
)))) {
362 memset(shakey
, 0, sizeof(shakey
));
363 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
364 send_to_client(client
, "ERR %03i gcrypt: %s\n", EPWMD_ERROR
, gcry_strerror(gcryerrno
));
368 if ((gcryerrno
= gcry_cipher_setkey(client
->gh
, shakey
, gcrykeysize
))) {
370 memset(shakey
, 0, sizeof(shakey
));
371 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
372 send_to_client(client
, "ERR %03i gcrypt: %s\n", EPWMD_ERROR
, gcry_strerror(gcryerrno
));
376 if (decrypt_xml(client
->gh
, inbuf
, insize
, NULL
, 0) == FALSE
) {
382 memset(shakey
, 0, sizeof(shakey
));
384 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
385 send_to_client(client
, "ERR %03i gcrypt: %s\n", EPWMD_ERROR
, gcry_strerror(gcryerrno
));
389 memcpy(tkey
, shakey
, sizeof(tkey
));
392 if ((gcryerrno
= gcry_cipher_setkey(client
->gh
, tkey
, gcrykeysize
))) {
393 memset(tkey
, 0, sizeof(tkey
));
395 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
396 send_to_client(client
, "ERR %03i gcrypt: %s\n", EPWMD_ERROR
, gcry_strerror(gcryerrno
));
400 iter
= file_header
.iter
;
403 if ((gcryerrno
= gcry_cipher_setiv(client
->gh
, file_header
.iv
,
404 sizeof(file_header
.iv
)))) {
405 memset(tkey
, 0, sizeof(tkey
));
407 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
408 send_to_client(client
, "ERR %03i gcrypt: %s\n", EPWMD_ERROR
, gcry_strerror(gcryerrno
));
412 if (decrypt_xml(client
->gh
, inbuf
, insize
, NULL
, 0) == FALSE
) {
418 memset(tkey
, 0, sizeof(tkey
));
420 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
421 send_to_client(client
, "ERR %03i gcrypt: %s\n", EPWMD_ERROR
, gcry_strerror(gcryerrno
));
426 memset(tkey
, 0, sizeof(tkey
));
428 client
->len
= insize
;
430 if (g_strncasecmp(client
->xml
, "<?xml version=\"1.0\"?>", 21) != 0) {
431 send_error(client
, EPWMD_BADKEY
);
436 if (cache_add_file(client
->md5file
, shakey
) == FALSE
) {
437 memset(shakey
, 0, sizeof(shakey
));
438 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(EPWMD_MAX_SLOTS
));
439 send_error(client
, EPWMD_MAX_SLOTS
);
444 memset(shakey
, 0, sizeof(shakey
));
445 client
->filename
= g_strdup(filename
);
448 timeout
= get_key_file_integer(client
->filename
, "cache_timeout");
449 cache_set_timeout(client
->md5file
, timeout
);
452 return parse_xml(client
);
456 * client->reader should be at the position in the document where the element
457 * search should start. It won't search past the closing account element.
459 static gboolean
find_elements(struct client_s
*client
, xmlTextReaderPtr reader
,
460 gchar
**req
, gint quiet
)
464 if (!req
|| !req
[0]) {
466 send_error(client
, EPWMD_COMMAND_SYNTAX
);
470 for (i
= 0; req
[i
]; i
++) {
471 if (find_element(reader
, req
[i
], req
[i
+1] != NULL
) == FALSE
) {
473 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
482 gboolean
do_xml_encrypt(struct client_s
*client
, gcry_cipher_hd_t gh
,
483 const gchar
*filename
, const xmlChar
*data
, size_t insize
,
484 const guchar
*shakey
, guint iter
)
489 guchar tkey
[gcrykeysize
];
492 struct file_header_s
{
494 guchar iv
[gcryblocksize
];
497 if (insize
/ gcryblocksize
) {
498 len
= (insize
/ gcryblocksize
) * gcryblocksize
;
500 if (insize
% gcryblocksize
)
501 len
+= gcryblocksize
;
504 inbuf
= gcry_calloc(1, len
);
505 memcpy(inbuf
, data
, insize
);
507 gcry_create_nonce(file_header
.iv
, sizeof(file_header
.iv
));
508 memcpy(tkey
, shakey
, sizeof(tkey
));
511 if ((gcryerrno
= gcry_cipher_setkey(gh
, tkey
, gcrykeysize
))) {
513 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
514 send_to_client(client
, "ERR %03i gcrypt: %s\n", EPWMD_ERROR
, gcry_strerror(gcryerrno
));
518 file_header
.iter
= iter
;
521 if ((gcryerrno
= gcry_cipher_setiv(gh
, file_header
.iv
,
522 sizeof(file_header
.iv
)))) {
524 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
525 send_to_client(client
, "ERR %03i gcrypt: %s\n", EPWMD_ERROR
, gcry_strerror(gcryerrno
));
529 if (encrypt_xml(gh
, inbuf
, insize
, NULL
, 0)
532 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
533 send_to_client(client
, "ERR %03i gcrypt: %s\n", EPWMD_ERROR
, gcry_strerror(gcryerrno
));
538 if ((gcryerrno
= gcry_cipher_setiv(gh
, file_header
.iv
,
539 sizeof(file_header
.iv
)))) {
541 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
542 send_to_client(client
, "ERR %03i gcrypt: %s\n", EPWMD_ERROR
, gcry_strerror(gcryerrno
));
546 if ((gcryerrno
= gcry_cipher_setkey(gh
, shakey
, gcrykeysize
))) {
548 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
549 send_to_client(client
, "ERR %03i gcrypt: %s\n", EPWMD_ERROR
, gcry_strerror(gcryerrno
));
553 if (encrypt_xml(gh
, inbuf
, insize
, NULL
, 0)
556 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
557 send_to_client(client
, "ERR %03i gcrypt: %s\n", EPWMD_ERROR
, gcry_strerror(gcryerrno
));
562 if ((fd
= open(filename
, O_WRONLY
|O_CREAT
|O_TRUNC
, 0600)) == -1) {
565 p
= strrchr(filename
, '/');
567 log_write("%s: %s", p
, strerror(errno
));
568 send_to_client(client
, "ERR %03i %s: %s\n", EPWMD_ERROR
, p
, strerror(error
));
574 * xml_import() from command line.
578 write(fd
, &file_header
, sizeof(struct file_header_s
));
579 write(fd
, inbuf
, insize
);
588 gboolean
save_command(struct client_s
*client
, const gchar
*filename
, gchar
*key
)
593 guchar shakey
[gcrykeysize
];
596 gchar filebuf
[PATH_MAX
], *p
, *p2
;
597 gboolean reset_timeout
;
599 p
= get_key_file_string("default", "data_directory");
600 p2
= expand_homedir(p
);
602 snprintf(filebuf
, sizeof(filebuf
), "%s/%s", p2
, filename
);
605 if (stat(filebuf
, &st
) == 0 && client
->mtime
) {
606 if (client
->mtime
!= st
.st_mtime
) {
607 log_write("%s: %s", filename
, pwmd_strerror(EPWMD_FILE_MODIFIED
));
608 send_error(client
, EPWMD_FILE_MODIFIED
);
614 if (cache_get_key(client
->md5file
, shakey
) == FALSE
) {
615 send_error(client
, EPWMD_KEY
);
622 gcry_md_hash_buffer(GCRY_MD_SHA256
, shakey
, key
, strlen(key
));
623 memset(key
, 0, strlen(key
));
626 xmlDocDumpFormatMemory(client
->doc
, &xmlbuf
, &len
, 0);
628 if ((iter
= get_key_file_integer(client
->filename
, "iterations")) == -1)
631 if (do_xml_encrypt(client
, client
->gh
, filebuf
, xmlbuf
, len
, shakey
,
633 memset(shakey
, 0, sizeof(shakey
));
640 client
->mtime
= st
.st_mtime
;
643 memset(shakey
, 0, sizeof(shakey
));
645 if ((reset_timeout
= get_key_file_boolean(client
->filename
,
646 "cache_reset_timeout")) == TRUE
)
647 cache_reset_timeout(client
->md5file
);
652 if (cache_update_key(client
->md5file
, shakey
) == FALSE
) {
653 memset(shakey
, 0, sizeof(shakey
));
654 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(EPWMD_MAX_SLOTS
));
655 send_error(client
, EPWMD_MAX_SLOTS
);
659 memset(shakey
, 0, sizeof(shakey
));
660 cache_reset_timeout(client
->md5file
);
664 static gboolean
contains_whitespace(const gchar
*str
)
666 const gchar
*p
= str
;
669 if (g_ascii_isspace(*p
) == TRUE
) {
678 * the 'reader' should be at the element of the document where the elements
679 * 'req' are to be created.
681 static gboolean
create_elements(struct client_s
*client
, xmlTextReaderPtr reader
,
682 gchar
**req
, gint novalue
)
688 r
= xmlTextReaderCurrentNode(reader
);
690 if (xmlTextReaderDepth(reader
) > 1)
693 for (i
= 0; req
[i
]; i
++) {
697 * Whitespace is allowed in values or attributes but not in element
700 if (req
[i
+1] && valid_xml_element((xmlChar
*)req
[i
]) == FALSE
) {
701 send_error(client
, EPWMD_INVALID_ELEMENT
);
706 * The value of the element tree.
708 if (!req
[i
+1] && !novalue
) {
710 * Prevent creating 'text' elements in the root of the account.
713 send_error(client
, EPWMD_ROOT_TEXT_ELEMENT
);
718 * FIXME ?? overwriting an element tree with a text element:
720 * STORE account element element2 value
721 * STORE account element value
723 * would remove the existing element tree. This may be a bug or
726 xmlNodeSetContent(r
, (xmlChar
*)req
[i
]);
730 if ((n
= find_node(r
, (xmlChar
*)req
[i
])) == NULL
) {
731 n
= xmlNewNode(NULL
, (xmlChar
*)req
[i
]);
732 r
= xmlAddChild(r
, n
);
737 if (!req
[i
+1] && novalue
)
745 * FIXME reuse reader handle
747 static gboolean
reset_reader(xmlDocPtr doc
, xmlTextReaderPtr
*reader
)
750 xmlFreeTextReader(*reader
);
754 if ((*reader
= xmlReaderWalker(doc
)) == NULL
)
760 static void delete_node(xmlNodePtr n
)
766 gboolean
delete_command(struct client_s
*client
, gchar
**req
)
770 xmlErrorPtr xml_error
;
772 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
773 xml_error
= xmlGetLastError();
774 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
775 send_error(client
, EPWMD_LIBXML_ERROR
);
779 if (find_account(client
->reader
, req
[0]) == FALSE
) {
780 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
784 n
= xmlTextReaderCurrentNode(client
->reader
);
787 * No sub-node defined. Remove the entire node (account).
796 * Remove matching sub-nodes starting from the root of the account.
798 while (req
[i
] && find_element(client
->reader
, req
[i
++], req
[i
] != NULL
) == TRUE
)
799 n
= xmlTextReaderCurrentNode(client
->reader
);
801 if (n
&& xmlStrcmp(n
->name
, (xmlChar
*)req
[i
-1]) == 0 &&
802 xmlTextReaderNodeType(client
->reader
) == XML_READER_TYPE_ELEMENT
)
805 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
812 gboolean
store_command(struct client_s
*client
, gchar
**req
)
814 xmlErrorPtr xml_error
;
817 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
818 xml_error
= xmlGetLastError();
819 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
820 send_error(client
, EPWMD_LIBXML_ERROR
);
825 send_error(client
, EPWMD_COMMAND_SYNTAX
);
829 if (find_account(client
->reader
, req
[0]) == FALSE
) {
830 if (contains_whitespace(req
[0]) == TRUE
) {
831 send_error(client
, EPWMD_INVALID_ELEMENT
);
835 if (new_account(client
->doc
, req
[0]) == FALSE
) {
836 send_error(client
, EPWMD_ERROR
);
843 xmlTextReaderNext(client
->reader
);
844 return create_elements(client
, client
->reader
, req
+1, 0);
847 static gboolean
do_get_command(struct client_s
*client
, xmlTextReaderPtr
*reader
,
848 gchar
**req
, xmlChar
**content
, gint quiet
, gint list
)
855 xmlErrorPtr xml_error
;
857 if (reset_reader(client
->doc
, reader
) == FALSE
) {
859 xml_error
= xmlGetLastError();
860 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
861 send_error(client
, EPWMD_LIBXML_ERROR
);
867 if (find_account(*reader
, req
[0]) == FALSE
) {
869 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
874 * May be an account with only a TARGET attribute.
877 if (find_elements(client
, *reader
, req
+ 1, (list
) ? 1 : quiet
) == FALSE
)
881 if ((n
= xmlTextReaderCurrentNode(*reader
)) == NULL
) {
883 xml_error
= xmlGetLastError();
884 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
885 send_error(client
, EPWMD_LIBXML_ERROR
);
892 * If the current element has a TARGET attribute, the value of the
893 * attribute is an element path somewhere else in the document. Use this
894 * value and not any TEXT element value. The value may be another element
895 * with a TARGET attribute and this function will recurse until a non-TARGET
896 * attribute in the element is found.
898 if ((a
= xmlHasProp(n
, (xmlChar
*)"target")) != NULL
) {
899 if ((p
= xmlNodeGetContent(a
->children
)) != NULL
) {
900 if (strchr((gchar
*)p
, '\t') != NULL
) {
901 if ((nreq
= split_input_line((gchar
*)p
, "\t", 0)) == NULL
) {
905 send_error(client
, EPWMD_INVALID_ELEMENT
);
910 if ((nreq
= split_input_line((gchar
*)p
, " ", 0)) == NULL
) {
914 send_error(client
, EPWMD_INVALID_ELEMENT
);
920 ret
= do_get_command(client
, reader
, nreq
, content
, quiet
, list
);
926 switch (xmlTextReaderNext(*reader
)) {
929 xml_error
= xmlGetLastError();
930 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
931 send_error(client
, EPWMD_LIBXML_ERROR
);
937 send_error(client
, EPWMD_EMPTY_ELEMENT
);
943 switch (xmlTextReaderNodeType(*reader
)) {
944 case XML_READER_TYPE_END_ELEMENT
:
946 * May be an empty element after an ATTR DELETE TARGET command.
949 case XML_READER_TYPE_TEXT
:
953 xml_error
= xmlGetLastError();
954 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
955 send_error(client
, EPWMD_LIBXML_ERROR
);
961 if (n
->children
&& !list
)
962 send_error(client
, EPWMD_TRAILING_ELEMENT
);
963 else if (!n
->children
&& !list
)
964 send_error(client
, EPWMD_INVALID_ELEMENT
);
969 if ((*content
= xmlNodeGetContent(n
)) == NULL
) {
971 send_error(client
, EPWMD_EMPTY_ELEMENT
);
979 * Retrieves the value associated with the element tree 'req'.
981 gboolean
get_command(struct client_s
*client
, xmlTextReaderPtr
*reader
,
982 gchar
**req
, gint quiet
)
984 xmlChar
*content
= NULL
;
986 if (do_get_command(client
, reader
, req
, &content
, quiet
, 0) == FALSE
)
991 send_error(client
, EPWMD_EMPTY_ELEMENT
);
996 send_to_client(client
, "BEGIN %li\n%s\nOK \n", xmlStrlen(content
), content
);
1002 static gchar
*element_path_to_req(const gchar
*account
, xmlChar
*path
,
1003 const xmlChar
*content
)
1005 static gchar
*element_path_to_req(const gchar
*account
, xmlChar
*path
)
1015 for (n
= 0; *p
&& n
< 3; p
++) {
1020 if (strstr((gchar
*)p
, "text()") != NULL
)
1021 p
[xmlStrlen(p
) - 7] = 0;
1023 for (n
= 0; p
[n
]; n
++) {
1029 buf
= g_strdup_printf("%s\t%s\t%s", account
, p
, content
);
1031 buf
= g_strdup_printf("%s\t%s", account
, p
);
1036 static gboolean
append_to_array(gchar
***array
, gint
*total
, const gchar
*str
)
1041 if ((a
= g_realloc(*array
, (t
+ 2) * sizeof(gchar
*))) == NULL
)
1044 a
[t
++] = g_strdup(str
);
1051 gboolean
list_command(struct client_s
*client
, gchar
*str
)
1055 gchar
**elements
= NULL
;
1056 gint pwmd_errno
= -1;
1059 xmlChar
*path
= NULL
;
1063 xmlTextReaderPtr r
= NULL
;
1064 gchar
**req
= NULL
, **nreq
;
1068 xmlErrorPtr xml_error
;
1071 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1072 xml_error
= xmlGetLastError();
1073 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1074 send_error(client
, EPWMD_LIBXML_ERROR
);
1078 if (strchr(p
, ' ') == NULL
) {
1080 if (list_accounts(client
->reader
, &dst
, &pwmd_errno
) == FALSE
) {
1081 send_error(client
, pwmd_errno
);
1085 send_to_client(client
, "BEGIN %i\n%s\nOK \n",
1086 g_utf8_strlen(dst
, -1), dst
);
1087 memset(dst
, 0, strlen(dst
));
1096 while (*p
&& isspace(*p
))
1102 if (strchr(p
, '\t') != NULL
) {
1103 if ((req
= split_input_line(p
, "\t", 0)) == NULL
) {
1104 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1108 if (find_account(client
->reader
, req
[0]) == FALSE
) {
1109 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1113 if (find_elements(client
, client
->reader
, req
+ 1, 0) == FALSE
) {
1118 depth
= xmlTextReaderDepth(client
->reader
);
1121 if (find_account(client
->reader
, p
) == FALSE
) {
1122 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1127 if ((n
= xmlTextReaderCurrentNode(client
->reader
)) == NULL
) {
1128 xml_error
= xmlGetLastError();
1129 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1130 send_error(client
, EPWMD_LIBXML_ERROR
);
1134 if ((a
= xmlHasProp(n
, (xmlChar
*)"target")) != NULL
) {
1135 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1136 send_error(client
, EPWMD_LIBXML_ERROR
);
1140 if ((content
= xmlNodeGetContent(a
->children
)) != NULL
) {
1141 if (find_account(client
->reader
, (gchar
*)content
) == FALSE
) {
1143 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1151 account
= (req
) ? g_strdup(req
[0]) : g_strdup(p
);
1156 while (xmlTextReaderNext(client
->reader
) == 1) {
1158 if ((n
= xmlTextReaderCurrentNode(client
->reader
)) == NULL
) {
1159 xml_error
= xmlGetLastError();
1160 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1161 send_error(client
, EPWMD_LIBXML_ERROR
);
1165 if (xmlTextReaderDepth(client
->reader
) == 1 &&
1166 xmlStrcmp(n
->name
, (xmlChar
*)"account") == 0 &&
1167 xmlTextReaderNodeType(client
->reader
) == XML_READER_TYPE_END_ELEMENT
)
1170 if (depth
&& depth
== xmlTextReaderDepth(client
->reader
) &&
1171 xmlTextReaderNodeType(client
->reader
) == XML_READER_TYPE_END_ELEMENT
)
1175 * If the current element has a TARGET attribute, the value of the
1176 * attribute is an element path somewhere else in the document. Use this
1177 * value and not any TEXT element value.
1179 type
= xmlTextReaderNodeType(client
->reader
);
1180 a
= xmlHasProp(n
, (xmlChar
*)"target");
1182 if (type
== XML_READER_TYPE_ELEMENT
&& a
) {
1183 if ((content
= xmlNodeGetContent(a
->children
)) != NULL
) {
1184 path
= xmlGetNodePath(n
);
1186 if ((nreq
= split_input_line((gchar
*)content
, "\t", 0)) == NULL
) {
1188 g_strfreev(elements
);
1192 send_error(client
, EPWMD_INVALID_ELEMENT
);
1199 if ((ret
= do_get_command(client
, &r
, nreq
, &content
, 0, 1)) == TRUE
) {
1200 if (content
&& *content
) {
1202 line
= element_path_to_req(account
, path
, content
);
1204 line
= element_path_to_req(account
, path
);
1208 if (append_to_array(&elements
, &total
, line
) == FALSE
) {
1210 g_strfreev(elements
);
1213 memset(line
, 0, g_utf8_strlen(line
, -1));
1216 xmlFreeTextReader(r
);
1217 send_error(client
, EPWMD_ERROR
);
1221 memset(line
, 0, g_utf8_strlen(line
, -1));
1225 if (xmlTextReaderNext(client
->reader
) == 1) {
1226 if (xmlTextReaderNodeType(client
->reader
) !=
1227 XML_READER_TYPE_TEXT
) {
1229 xmlFreeTextReader(r
);
1237 xmlFreeTextReader(r
);
1243 if (type
== XML_READER_TYPE_TEXT
) {
1244 xmlChar
*np
= xmlGetNodePath(n
);
1247 content
= xmlNodeGetContent(n
);
1248 line
= element_path_to_req(account
, np
, content
);
1251 line
= element_path_to_req(account
, np
);
1254 append_to_array(&elements
, &total
, line
);
1255 memset(line
, 0, g_utf8_strlen(line
, -1));
1261 send_error(client
, EPWMD_EMPTY_ELEMENT
);
1267 line
= g_strjoinv("\n", elements
);
1268 send_to_client(client
, "BEGIN %li\n%s\nOK \n",
1269 g_utf8_strlen(line
, -1), line
);
1270 g_strfreev(elements
);
1276 * The client->reader handle should be at the element in the document where
1277 * the attribute will be created or modified.
1279 static gboolean
add_attribute(struct client_s
*client
, const gchar
*name
, const gchar
*value
)
1283 xmlErrorPtr xml_error
;
1285 if ((n
= xmlTextReaderCurrentNode(client
->reader
)) == NULL
) {
1286 xml_error
= xmlGetLastError();
1287 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1288 send_error(client
, EPWMD_LIBXML_ERROR
);
1292 if ((a
= xmlHasProp(n
, (xmlChar
*)name
)) == NULL
)
1293 a
= xmlNewProp(n
, (xmlChar
*)name
, (xmlChar
*)value
);
1295 xmlNodeSetContent(a
->children
, (xmlChar
*)value
);
1301 * req[0] - element path
1303 static gboolean
attribute_list(struct client_s
*client
, gchar
**req
)
1305 gchar
**attrlist
= NULL
;
1307 gchar
**epath
= NULL
;
1311 xmlErrorPtr xml_error
;
1313 if (!req
|| !req
[0]) {
1314 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1318 if ((epath
= split_input_line(req
[0], "\t", 0)) == NULL
) {
1320 * The first argument may be only an account.
1322 if ((epath
= split_input_line(req
[0], " ", 0)) == NULL
) {
1323 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1328 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1329 xml_error
= xmlGetLastError();
1330 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1331 send_error(client
, EPWMD_LIBXML_ERROR
);
1335 if (find_account(client
->reader
, epath
[0]) == FALSE
) {
1336 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1341 if ((find_elements(client
, client
->reader
, epath
+1, 0)) == FALSE
)
1345 if ((n
= xmlTextReaderCurrentNode(client
->reader
)) == NULL
) {
1346 xml_error
= xmlGetLastError();
1347 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1348 send_error(client
, EPWMD_LIBXML_ERROR
);
1352 for (a
= n
->properties
; a
; a
= a
->next
) {
1353 if ((attrlist
= g_realloc(attrlist
, (i
+ 2) * sizeof(gchar
*))) == NULL
) {
1354 log_write("%s(%i): g_realloc() failed", __FILE__
, __LINE__
);
1355 send_error(client
, EPWMD_ERROR
);
1360 attrlist
[i
++] = g_strdup_printf("%s\t%s", (gchar
*)a
->name
, (gchar
*)an
->content
);
1365 send_error(client
, EPWMD_EMPTY_ELEMENT
);
1369 line
= g_strjoinv("\n", attrlist
);
1370 send_to_client(client
, "BEGIN %li\n%s\n", g_utf8_strlen(line
, -1), line
);
1373 g_strfreev(attrlist
);
1381 * req[0] - attribute
1382 * req[1] - element path
1384 static gboolean
attribute_delete(struct client_s
*client
, gchar
**req
)
1388 gchar
**epath
= NULL
;
1389 xmlErrorPtr xml_error
;
1391 if (!req
|| !req
[0] || !req
[1]) {
1392 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1396 if ((epath
= split_input_line(req
[1], "\t", 0)) == NULL
) {
1398 * The first argument may be only an account.
1400 if ((epath
= split_input_line(req
[1], " ", 0)) == NULL
) {
1401 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1407 * Don't remove the NAME attribute for the account element.
1409 if (!epath
[1] && g_ascii_strcasecmp(req
[0], "NAME") == 0) {
1410 send_error(client
, EPWMD_ATTR_SYNTAX
);
1414 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1415 xml_error
= xmlGetLastError();
1416 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1417 send_error(client
, EPWMD_LIBXML_ERROR
);
1421 if (find_account(client
->reader
, epath
[0]) == FALSE
) {
1422 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1427 if ((find_elements(client
, client
->reader
, epath
+1, 0)) == FALSE
)
1431 if ((n
= xmlTextReaderCurrentNode(client
->reader
)) == NULL
) {
1432 xml_error
= xmlGetLastError();
1433 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1434 send_error(client
, EPWMD_LIBXML_ERROR
);
1438 if ((a
= xmlHasProp(n
, (xmlChar
*)req
[0])) == NULL
) {
1439 send_error(client
, EPWMD_ATTR_NOT_FOUND
);
1443 if (xmlRemoveProp(a
) == -1) {
1444 xml_error
= xmlGetLastError();
1445 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1446 send_error(client
, EPWMD_LIBXML_ERROR
);
1458 * req[0] - source element path
1459 * req[1] - destination element path
1461 static gboolean
target_attribute(struct client_s
*client
, gchar
**req
)
1463 gchar
**src
, **dst
, *line
;
1464 xmlErrorPtr xml_error
;
1466 if (!req
|| !req
[0] || !req
[1]) {
1467 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1471 if ((src
= split_input_line(req
[0], "\t", 0)) == NULL
) {
1473 * The first argument may be only an account.
1475 if ((src
= split_input_line(req
[0], " ", 0)) == NULL
) {
1476 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1481 if ((dst
= split_input_line(req
[1], "\t", 0)) == NULL
) {
1483 * The first argument may be only an account.
1485 if ((dst
= split_input_line(req
[1], " ", 0)) == NULL
) {
1486 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1493 * Prevent an element tree pointing to only and account. Accounts require
1494 * at least one element. Accounts pointing to accounts are allowed.
1496 if ((!src
[1] && dst
[1]) || (!dst
[1] && src
[1])) {
1497 send_error(client
, EPWMD_ATTR_SYNTAX
);
1503 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1504 xml_error
= xmlGetLastError();
1505 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1506 send_error(client
, EPWMD_LIBXML_ERROR
);
1513 * Make sure the destination element path exists.
1515 if (find_account(client
->reader
, dst
[0]) == FALSE
) {
1516 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1523 if (find_elements(client
, client
->reader
, dst
+1, 0) == FALSE
) {
1530 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1531 xml_error
= xmlGetLastError();
1532 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1533 send_error(client
, EPWMD_LIBXML_ERROR
);
1540 * If the source element tree doesn't exist, create it.
1542 if (find_account(client
->reader
, src
[0]) == FALSE
) {
1543 if (new_account(client
->doc
, src
[0]) == FALSE
) {
1544 xml_error
= xmlGetLastError();
1545 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1546 send_error(client
, EPWMD_LIBXML_ERROR
);
1552 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1553 xml_error
= xmlGetLastError();
1554 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1555 send_error(client
, EPWMD_LIBXML_ERROR
);
1561 if (find_account(client
->reader
, src
[0]) == FALSE
) {
1562 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1570 if (find_elements(client
, client
->reader
, src
+1, 1) == FALSE
) {
1571 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1572 xml_error
= xmlGetLastError();
1573 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1574 send_error(client
, EPWMD_LIBXML_ERROR
);
1580 if (find_account(client
->reader
, src
[0]) == FALSE
) {
1581 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1587 xmlTextReaderNext(client
->reader
);
1589 if (create_elements(client
, client
->reader
, src
+1, 1) == FALSE
) {
1595 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1596 xml_error
= xmlGetLastError();
1597 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1598 send_error(client
, EPWMD_LIBXML_ERROR
);
1604 if (find_account(client
->reader
, src
[0]) == FALSE
) {
1605 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1611 if (find_elements(client
, client
->reader
, src
+1, 0) == FALSE
) {
1619 line
= g_strjoinv("\t", dst
);
1621 if (add_attribute(client
, "target", line
) == FALSE
) {
1639 * req[0] - account name
1642 static gboolean
name_attribute(struct client_s
*client
, gchar
**req
)
1644 xmlErrorPtr xml_error
;
1646 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1647 xml_error
= xmlGetLastError();
1648 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1649 send_error(client
, EPWMD_LIBXML_ERROR
);
1653 if (find_account(client
->reader
, req
[0]) == FALSE
) {
1654 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1658 if (strcmp(req
[0], req
[1]) == 0)
1661 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1662 xml_error
= xmlGetLastError();
1663 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1664 send_error(client
, EPWMD_LIBXML_ERROR
);
1669 * Will not overwrite an existing account.
1671 if (find_account(client
->reader
, req
[1]) == TRUE
) {
1672 send_error(client
, EPWMD_ACCOUNT_EXISTS
);
1676 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1677 xml_error
= xmlGetLastError();
1678 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1679 send_error(client
, EPWMD_LIBXML_ERROR
);
1683 if (find_account(client
->reader
, req
[0]) == FALSE
) {
1684 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1689 * Whitespace not allowed in account names.
1691 if (contains_whitespace(req
[1]) == TRUE
) {
1692 send_error(client
, EPWMD_ATTR_SYNTAX
);
1696 return add_attribute(client
, "name", req
[1]);
1700 * req[0] - attribute
1701 * req[1] - element path
1703 * If the element has a "target" attribute it won't be "followed".
1705 static gboolean
attribute_get(struct client_s
*client
, gchar
**req
)
1709 gchar
**nreq
= NULL
;
1710 xmlErrorPtr xml_error
;
1712 if (!req
|| !req
[0] || !req
[1]) {
1713 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1717 if (strchr(req
[1], '\t')) {
1718 if ((nreq
= split_input_line(req
[1], "\t", 0)) == NULL
) {
1719 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1724 if ((nreq
= split_input_line(req
[1], " ", 0)) == NULL
) {
1725 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1730 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1731 xml_error
= xmlGetLastError();
1732 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1734 send_error(client
, EPWMD_LIBXML_ERROR
);
1738 if (find_account(client
->reader
, nreq
[0]) == FALSE
) {
1740 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1745 if (find_elements(client
, client
->reader
, nreq
+ 1, 0) == FALSE
) {
1753 if ((n
= xmlTextReaderCurrentNode(client
->reader
)) == NULL
) {
1754 xml_error
= xmlGetLastError();
1755 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1756 send_error(client
, EPWMD_LIBXML_ERROR
);
1760 if ((a
= xmlGetProp(n
, (xmlChar
*)req
[0])) == NULL
) {
1761 send_error(client
, EPWMD_ATTR_NOT_FOUND
);
1765 send_to_client(client
, "BEGIN %li\n%s\n", xmlStrlen(a
), a
);
1771 * req[0] - attribute
1772 * req[1] - element path
1775 static gboolean
attribute_set(struct client_s
*client
, gchar
**req
)
1777 gchar
**epath
= NULL
;
1778 xmlErrorPtr xml_error
;
1780 if (!req
|| !req
[0] || !req
[1] || !req
[2]) {
1781 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1786 * Reserved attribute names.
1788 if (g_ascii_strcasecmp(req
[0], "NAME") == 0) {
1790 * Only reserved for the account element. Not the rest of the
1793 if (strchr(req
[1], '\t') == NULL
)
1794 return name_attribute(client
, req
+ 1);
1796 else if (g_ascii_strcasecmp(req
[0], "TARGET") == 0)
1797 return target_attribute(client
, req
+ 1);
1799 if ((epath
= split_input_line(req
[1], "\t", 0)) == NULL
) {
1801 * The first argument may be only an account.
1803 if ((epath
= split_input_line(req
[1], " ", 0)) == NULL
) {
1804 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1809 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1810 xml_error
= xmlGetLastError();
1811 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1812 send_error(client
, EPWMD_LIBXML_ERROR
);
1816 if (find_account(client
->reader
, epath
[0]) == FALSE
) {
1817 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1822 if ((find_elements(client
, client
->reader
, epath
+1, 0)) == FALSE
)
1827 return add_attribute(client
, req
[0], req
[2]);
1835 * req[1] - attribute name or element path if command is LIST
1836 * req[2] - element path
1837 * req[2] - element path or value
1839 gboolean
attr_command(struct client_s
*client
, gchar
**req
)
1841 if (!req
|| !req
[0] || !req
[1]) {
1842 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1846 if (g_ascii_strcasecmp(req
[0], "SET") == 0)
1847 return attribute_set(client
, req
+1);
1848 if (g_ascii_strcasecmp(req
[0], "GET") == 0)
1849 return attribute_get(client
, req
+1);
1850 else if (g_ascii_strcasecmp(req
[0], "DELETE") == 0)
1851 return attribute_delete(client
, req
+1);
1852 else if (g_ascii_strcasecmp(req
[0], "LIST") == 0)
1853 return attribute_list(client
, req
+1);
1855 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1860 gboolean
cache_test(const guchar
*md5filename
, gint reset
)
1866 for (p
= shm_data
, len
= 0; len
<= cache_size
;) {
1867 memcpy(&f
, p
, sizeof(file_cache_t
));
1870 memset(&f
, 0, sizeof(file_cache_t
));
1871 memcpy(p
, &f
, sizeof(file_cache_t
));
1872 p
+= sizeof(file_cache_t
);
1873 len
+= sizeof(file_cache_t
);
1875 if (len
+ sizeof(file_cache_t
) > cache_size
)
1880 if (f
.used
== TRUE
) {
1881 if (memcmp((gchar
*)f
.filename
, (gchar
*)md5filename
, sizeof(f
.filename
)) == 0) {
1883 memset(&f
, 0, sizeof(file_cache_t
));
1884 memcpy(p
, &f
, sizeof(file_cache_t
));
1888 return cache_valid_key(f
.key
, sizeof(f
.key
));
1892 p
+= sizeof(file_cache_t
);
1893 len
+= sizeof(file_cache_t
);
1895 if (len
+ sizeof(file_cache_t
) > cache_size
)
1899 return (reset
== 2) ? TRUE
: FALSE
;
1902 static gboolean
file_exists(const gchar
*filename
)
1905 gchar filebuf
[PATH_MAX
], *p
, *p2
;
1907 p
= get_key_file_string("default", "data_directory");
1908 p2
= expand_homedir(p
);
1910 snprintf(filebuf
, sizeof(filebuf
), "%s/%s", p2
, filename
);
1913 if (access(filebuf
, R_OK
) == -1)
1918 if (st
.st_size
== 0)
1924 gboolean
cache_command(struct client_s
*client
, gchar
**req
)
1930 if (g_ascii_strcasecmp(req
[0], "CLEAR") == 0) {
1932 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1936 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[1], strlen(req
[1]));
1938 if (cache_test(md5file
, 1) == FALSE
) {
1939 send_error(client
, EPWMD_CACHE_NOT_FOUND
);
1945 else if (g_ascii_strcasecmp(req
[0], "CLEARALL") == 0) {
1946 cache_test(client
->md5file
, 2);
1949 else if (g_ascii_strcasecmp(req
[0], "ISCACHED") == 0) {
1951 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1955 if (file_exists(req
[1]) == FALSE
) {
1956 send_error(client
, EPWMD_FILE_NOT_FOUND
);
1960 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[1], strlen(req
[1]));
1962 if (cache_test(md5file
, 0) == FALSE
) {
1963 send_error(client
, EPWMD_CACHE_NOT_FOUND
);
1969 else if (g_ascii_strcasecmp(req
[0], "TIMEOUT") == 0) {
1970 if (!req
[1] || !req
[2]) {
1971 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1976 timeout
= strtol(req
[1], &p
, 10);
1978 if (errno
!= 0 || *p
!= 0) {
1979 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1983 if (file_exists(req
[2]) == FALSE
) {
1984 send_error(client
, EPWMD_FILE_NOT_FOUND
);
1988 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[2], strlen(req
[2]));
1990 if (cache_set_timeout(md5file
, timeout
) == FALSE
) {
1991 send_error(client
, EPWMD_CACHE_NOT_FOUND
);
1998 send_error(client
, EPWMD_COMMAND_SYNTAX
);
2003 gboolean
help_command(struct client_s
*client
, const gchar
*what
)
2007 if (!what
|| !*what
)
2009 "NFO Try 'HELP COMMAND' for command help\n"
2010 "NFO OPEN LIST GET STORE DELETE ATTR CACHE SAVE DUMP QUIT\n";
2011 else if (g_ascii_strcasecmp(what
, "GET") == 0)
2013 "NFO syntax: GET account <TAB> element [<TAB> element ...]\n"
2014 "NFO <account> is the account to work on and <element>\n"
2015 "NFO is the element wanted.\n"
2017 "NFO Example: GET isp <TAB> imap <TAB> port\n"
2018 "NFO GET isp <TAB> username\n";
2019 else if (g_ascii_strcasecmp(what
, "QUIT") == 0)
2021 "NFO syntax: QUIT\n"
2022 "NFO close the connection\n";
2023 else if (g_ascii_strcasecmp(what
, "DELETE") == 0)
2025 "NFO syntax: DELETE account <TAB> element [<TAB> element ...]\n";
2026 else if (g_ascii_strcasecmp(what
, "STORE") == 0)
2028 "NFO syntax: STORE account <TAB> element [<TAB> element ...] <TAB> value\n"
2029 "NFO <account> is the account to work on and <element>\n"
2030 "NFO is the element to create or modify\n"
2032 "NFO Example: STORE isp <TAB> imap <TAB> port <TAB> 993\n"
2033 "NFO STORE isp <TAB> username <TAB> someuser\n";
2034 else if (g_ascii_strcasecmp(what
, "OPEN") == 0)
2036 "NFO syntax: OPEN <filename> [<key>]\n"
2037 "NFO opens a (new) file\n";
2038 else if (g_ascii_strcasecmp(what
, "LIST") == 0)
2040 "NFO syntax: LIST [account]\n"
2041 "NFO shows available accounts or account elements\n";
2042 else if (g_ascii_strcasecmp(what
, "ATTR") == 0)
2044 "NFO syntax: ATTR SET|GET|DELETE|LIST [ATTRIBUTE] arg1 [arg2]\n"
2045 "NFO ATTR SET NAME account value\n"
2046 "NFO ATTR SET TARGET account[<TAB>element[...]] account[<TAB>element[...]\n"
2047 "NFO ATTR SET attribute account[<TAB>element[...]] attribute_value\n"
2048 "NFO ATTR DELETE attribute account[<TAB>element[...]]\n"
2049 "NFO ATTR GET attribute account[<TAB>element[...]]\n"
2050 "NFO ATTR LIST account[<TAB>element[...]]\n";
2051 else if (g_ascii_strcasecmp(what
, "SAVE") == 0)
2053 "NFO syntax: SAVE [<key>]\n"
2054 "NFO save any changes to the opened file using <key>\n";
2055 else if (g_ascii_strcasecmp(what
, "CACHE") == 0)
2057 "NFO syntax: CACHE [CLEARALL | [CLEAR | ISCACHED <filename>] |\n"
2058 "NFO TIMEOUT <seconds> <filename>]\n"
2059 "NFO tests or clears the cache entry for <filename>\n";
2060 else if (g_ascii_strcasecmp(what
, "DUMP") == 0)
2062 "NFO syntax: DUMP\n"
2063 "NFO shows the in memory XML document\n";
2065 send_error(client
, EPWMD_COMMAND_SYNTAX
);
2069 send_to_client(client
, "%sOK \n", line
);
2073 gboolean
dump_command(struct client_s
*client
)
2078 xmlDocDumpFormatMemory(client
->doc
, &xml
, &len
, 1);
2079 send_to_client(client
, "BEGIN %li\n%s", len
, xml
);