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
);
649 log_write("%s\n", reset_timeout
== FALSE
?"ack":"ackack");
653 if (cache_update_key(client
->md5file
, shakey
) == FALSE
) {
654 memset(shakey
, 0, sizeof(shakey
));
655 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(EPWMD_MAX_SLOTS
));
656 send_error(client
, EPWMD_MAX_SLOTS
);
660 memset(shakey
, 0, sizeof(shakey
));
661 cache_reset_timeout(client
->md5file
);
665 static gboolean
contains_whitespace(const gchar
*str
)
667 const gchar
*p
= str
;
670 if (g_ascii_isspace(*p
) == TRUE
) {
679 * the 'reader' should be at the element of the document where the elements
680 * 'req' are to be created.
682 static gboolean
create_elements(struct client_s
*client
, xmlTextReaderPtr reader
,
683 gchar
**req
, gint novalue
)
689 r
= xmlTextReaderCurrentNode(reader
);
691 if (xmlTextReaderDepth(reader
) > 1)
694 for (i
= 0; req
[i
]; i
++) {
698 * Whitespace is allowed in values or attributes but not in element
701 if (req
[i
+1] && valid_xml_element((xmlChar
*)req
[i
]) == FALSE
) {
702 send_error(client
, EPWMD_INVALID_ELEMENT
);
707 * The value of the element tree.
709 if (!req
[i
+1] && !novalue
) {
711 * Prevent creating 'text' elements in the root of the account.
714 send_error(client
, EPWMD_ROOT_TEXT_ELEMENT
);
719 * FIXME ?? overwriting an element tree with a text element:
721 * STORE account element element2 value
722 * STORE account element value
724 * would remove the existing element tree. This may be a bug or
727 xmlNodeSetContent(r
, (xmlChar
*)req
[i
]);
731 if ((n
= find_node(r
, (xmlChar
*)req
[i
])) == NULL
) {
732 n
= xmlNewNode(NULL
, (xmlChar
*)req
[i
]);
733 r
= xmlAddChild(r
, n
);
738 if (!req
[i
+1] && novalue
)
746 * FIXME reuse reader handle
748 static gboolean
reset_reader(xmlDocPtr doc
, xmlTextReaderPtr
*reader
)
751 xmlFreeTextReader(*reader
);
755 if ((*reader
= xmlReaderWalker(doc
)) == NULL
)
761 static void delete_node(xmlNodePtr n
)
767 gboolean
delete_command(struct client_s
*client
, gchar
**req
)
771 xmlErrorPtr xml_error
;
773 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
774 xml_error
= xmlGetLastError();
775 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
776 send_error(client
, EPWMD_LIBXML_ERROR
);
780 if (find_account(client
->reader
, req
[0]) == FALSE
) {
781 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
785 n
= xmlTextReaderCurrentNode(client
->reader
);
788 * No sub-node defined. Remove the entire node (account).
797 * Remove matching sub-nodes starting from the root of the account.
799 while (req
[i
] && find_element(client
->reader
, req
[i
++], req
[i
] != NULL
) == TRUE
)
800 n
= xmlTextReaderCurrentNode(client
->reader
);
802 if (n
&& xmlStrcmp(n
->name
, (xmlChar
*)req
[i
-1]) == 0 &&
803 xmlTextReaderNodeType(client
->reader
) == XML_READER_TYPE_ELEMENT
)
806 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
813 gboolean
store_command(struct client_s
*client
, gchar
**req
)
815 xmlErrorPtr xml_error
;
818 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
819 xml_error
= xmlGetLastError();
820 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
821 send_error(client
, EPWMD_LIBXML_ERROR
);
826 send_error(client
, EPWMD_COMMAND_SYNTAX
);
830 if (find_account(client
->reader
, req
[0]) == FALSE
) {
831 if (contains_whitespace(req
[0]) == TRUE
) {
832 send_error(client
, EPWMD_INVALID_ELEMENT
);
836 if (new_account(client
->doc
, req
[0]) == FALSE
) {
837 send_error(client
, EPWMD_ERROR
);
844 xmlTextReaderNext(client
->reader
);
845 return create_elements(client
, client
->reader
, req
+1, 0);
848 static gboolean
do_get_command(struct client_s
*client
, xmlTextReaderPtr
*reader
,
849 gchar
**req
, xmlChar
**content
, gint quiet
, gint list
)
856 xmlErrorPtr xml_error
;
858 if (reset_reader(client
->doc
, reader
) == FALSE
) {
860 xml_error
= xmlGetLastError();
861 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
862 send_error(client
, EPWMD_LIBXML_ERROR
);
868 if (find_account(*reader
, req
[0]) == FALSE
) {
870 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
875 * May be an account with only a TARGET attribute.
878 if (find_elements(client
, *reader
, req
+ 1, (list
) ? 1 : quiet
) == FALSE
)
882 if ((n
= xmlTextReaderCurrentNode(*reader
)) == NULL
) {
884 xml_error
= xmlGetLastError();
885 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
886 send_error(client
, EPWMD_LIBXML_ERROR
);
893 * If the current element has a TARGET attribute, the value of the
894 * attribute is an element path somewhere else in the document. Use this
895 * value and not any TEXT element value. The value may be another element
896 * with a TARGET attribute and this function will recurse until a non-TARGET
897 * attribute in the element is found.
899 if ((a
= xmlHasProp(n
, (xmlChar
*)"target")) != NULL
) {
900 if ((p
= xmlNodeGetContent(a
->children
)) != NULL
) {
901 if (strchr((gchar
*)p
, '\t') != NULL
) {
902 if ((nreq
= split_input_line((gchar
*)p
, "\t", 0)) == NULL
) {
906 send_error(client
, EPWMD_INVALID_ELEMENT
);
911 if ((nreq
= split_input_line((gchar
*)p
, " ", 0)) == NULL
) {
915 send_error(client
, EPWMD_INVALID_ELEMENT
);
921 ret
= do_get_command(client
, reader
, nreq
, content
, quiet
, list
);
927 switch (xmlTextReaderNext(*reader
)) {
930 xml_error
= xmlGetLastError();
931 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
932 send_error(client
, EPWMD_LIBXML_ERROR
);
938 send_error(client
, EPWMD_EMPTY_ELEMENT
);
944 switch (xmlTextReaderNodeType(*reader
)) {
945 case XML_READER_TYPE_END_ELEMENT
:
947 * May be an empty element after an ATTR DELETE TARGET command.
950 case XML_READER_TYPE_TEXT
:
954 xml_error
= xmlGetLastError();
955 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
956 send_error(client
, EPWMD_LIBXML_ERROR
);
962 if (n
->children
&& !list
)
963 send_error(client
, EPWMD_TRAILING_ELEMENT
);
964 else if (!n
->children
&& !list
)
965 send_error(client
, EPWMD_INVALID_ELEMENT
);
970 if ((*content
= xmlNodeGetContent(n
)) == NULL
) {
972 send_error(client
, EPWMD_EMPTY_ELEMENT
);
980 * Retrieves the value associated with the element tree 'req'.
982 gboolean
get_command(struct client_s
*client
, xmlTextReaderPtr
*reader
,
983 gchar
**req
, gint quiet
)
985 xmlChar
*content
= NULL
;
987 if (do_get_command(client
, reader
, req
, &content
, quiet
, 0) == FALSE
)
992 send_error(client
, EPWMD_EMPTY_ELEMENT
);
997 send_to_client(client
, "BEGIN %li\n%s\nOK \n", xmlStrlen(content
), content
);
1003 static gchar
*element_path_to_req(const gchar
*account
, xmlChar
*path
,
1004 const xmlChar
*content
)
1006 static gchar
*element_path_to_req(const gchar
*account
, xmlChar
*path
)
1016 for (n
= 0; *p
&& n
< 3; p
++) {
1021 if (strstr((gchar
*)p
, "text()") != NULL
)
1022 p
[xmlStrlen(p
) - 7] = 0;
1024 for (n
= 0; p
[n
]; n
++) {
1030 buf
= g_strdup_printf("%s\t%s\t%s", account
, p
, content
);
1032 buf
= g_strdup_printf("%s\t%s", account
, p
);
1037 static gboolean
append_to_array(gchar
***array
, gint
*total
, const gchar
*str
)
1042 if ((a
= g_realloc(*array
, (t
+ 2) * sizeof(gchar
*))) == NULL
)
1045 a
[t
++] = g_strdup(str
);
1052 gboolean
list_command(struct client_s
*client
, gchar
*str
)
1056 gchar
**elements
= NULL
;
1057 gint pwmd_errno
= -1;
1060 xmlChar
*path
= NULL
;
1064 xmlTextReaderPtr r
= NULL
;
1065 gchar
**req
= NULL
, **nreq
;
1069 xmlErrorPtr xml_error
;
1072 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1073 xml_error
= xmlGetLastError();
1074 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1075 send_error(client
, EPWMD_LIBXML_ERROR
);
1079 if (strchr(p
, ' ') == NULL
) {
1081 if (list_accounts(client
->reader
, &dst
, &pwmd_errno
) == FALSE
) {
1082 send_error(client
, pwmd_errno
);
1086 send_to_client(client
, "BEGIN %i\n%s\nOK \n",
1087 g_utf8_strlen(dst
, -1), dst
);
1088 memset(dst
, 0, strlen(dst
));
1097 while (*p
&& isspace(*p
))
1103 if (strchr(p
, '\t') != NULL
) {
1104 if ((req
= split_input_line(p
, "\t", 0)) == NULL
) {
1105 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1109 if (find_account(client
->reader
, req
[0]) == FALSE
) {
1110 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1114 if (find_elements(client
, client
->reader
, req
+ 1, 0) == FALSE
) {
1119 depth
= xmlTextReaderDepth(client
->reader
);
1122 if (find_account(client
->reader
, p
) == FALSE
) {
1123 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1128 if ((n
= xmlTextReaderCurrentNode(client
->reader
)) == NULL
) {
1129 xml_error
= xmlGetLastError();
1130 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1131 send_error(client
, EPWMD_LIBXML_ERROR
);
1135 if ((a
= xmlHasProp(n
, (xmlChar
*)"target")) != NULL
) {
1136 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1137 send_error(client
, EPWMD_LIBXML_ERROR
);
1141 if ((content
= xmlNodeGetContent(a
->children
)) != NULL
) {
1142 if (find_account(client
->reader
, (gchar
*)content
) == FALSE
) {
1144 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1152 account
= (req
) ? g_strdup(req
[0]) : g_strdup(p
);
1157 while (xmlTextReaderNext(client
->reader
) == 1) {
1159 if ((n
= xmlTextReaderCurrentNode(client
->reader
)) == NULL
) {
1160 xml_error
= xmlGetLastError();
1161 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1162 send_error(client
, EPWMD_LIBXML_ERROR
);
1166 if (xmlTextReaderDepth(client
->reader
) == 1 &&
1167 xmlStrcmp(n
->name
, (xmlChar
*)"account") == 0 &&
1168 xmlTextReaderNodeType(client
->reader
) == XML_READER_TYPE_END_ELEMENT
)
1171 if (depth
&& depth
== xmlTextReaderDepth(client
->reader
) &&
1172 xmlTextReaderNodeType(client
->reader
) == XML_READER_TYPE_END_ELEMENT
)
1176 * If the current element has a TARGET attribute, the value of the
1177 * attribute is an element path somewhere else in the document. Use this
1178 * value and not any TEXT element value.
1180 type
= xmlTextReaderNodeType(client
->reader
);
1181 a
= xmlHasProp(n
, (xmlChar
*)"target");
1183 if (type
== XML_READER_TYPE_ELEMENT
&& a
) {
1184 if ((content
= xmlNodeGetContent(a
->children
)) != NULL
) {
1185 path
= xmlGetNodePath(n
);
1187 if ((nreq
= split_input_line((gchar
*)content
, "\t", 0)) == NULL
) {
1189 g_strfreev(elements
);
1193 send_error(client
, EPWMD_INVALID_ELEMENT
);
1200 if ((ret
= do_get_command(client
, &r
, nreq
, &content
, 0, 1)) == TRUE
) {
1201 if (content
&& *content
) {
1203 line
= element_path_to_req(account
, path
, content
);
1205 line
= element_path_to_req(account
, path
);
1209 if (append_to_array(&elements
, &total
, line
) == FALSE
) {
1211 g_strfreev(elements
);
1214 memset(line
, 0, g_utf8_strlen(line
, -1));
1217 xmlFreeTextReader(r
);
1218 send_error(client
, EPWMD_ERROR
);
1222 memset(line
, 0, g_utf8_strlen(line
, -1));
1226 if (xmlTextReaderNext(client
->reader
) == 1) {
1227 if (xmlTextReaderNodeType(client
->reader
) !=
1228 XML_READER_TYPE_TEXT
) {
1230 xmlFreeTextReader(r
);
1238 xmlFreeTextReader(r
);
1244 if (type
== XML_READER_TYPE_TEXT
) {
1245 xmlChar
*np
= xmlGetNodePath(n
);
1248 content
= xmlNodeGetContent(n
);
1249 line
= element_path_to_req(account
, np
, content
);
1252 line
= element_path_to_req(account
, np
);
1255 append_to_array(&elements
, &total
, line
);
1256 memset(line
, 0, g_utf8_strlen(line
, -1));
1262 send_error(client
, EPWMD_EMPTY_ELEMENT
);
1268 line
= g_strjoinv("\n", elements
);
1269 send_to_client(client
, "BEGIN %li\n%s\nOK \n",
1270 g_utf8_strlen(line
, -1), line
);
1271 g_strfreev(elements
);
1277 * The client->reader handle should be at the element in the document where
1278 * the attribute will be created or modified.
1280 static gboolean
add_attribute(struct client_s
*client
, const gchar
*name
, const gchar
*value
)
1284 xmlErrorPtr xml_error
;
1286 if ((n
= xmlTextReaderCurrentNode(client
->reader
)) == NULL
) {
1287 xml_error
= xmlGetLastError();
1288 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1289 send_error(client
, EPWMD_LIBXML_ERROR
);
1293 if ((a
= xmlHasProp(n
, (xmlChar
*)name
)) == NULL
)
1294 a
= xmlNewProp(n
, (xmlChar
*)name
, (xmlChar
*)value
);
1296 xmlNodeSetContent(a
->children
, (xmlChar
*)value
);
1302 * req[0] - element path
1304 static gboolean
attribute_list(struct client_s
*client
, gchar
**req
)
1306 gchar
**attrlist
= NULL
;
1308 gchar
**epath
= NULL
;
1312 xmlErrorPtr xml_error
;
1314 if (!req
|| !req
[0]) {
1315 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1319 if ((epath
= split_input_line(req
[0], "\t", 0)) == NULL
) {
1321 * The first argument may be only an account.
1323 if ((epath
= split_input_line(req
[0], " ", 0)) == NULL
) {
1324 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1329 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1330 xml_error
= xmlGetLastError();
1331 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1332 send_error(client
, EPWMD_LIBXML_ERROR
);
1336 if (find_account(client
->reader
, epath
[0]) == FALSE
) {
1337 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1342 if ((find_elements(client
, client
->reader
, epath
+1, 0)) == FALSE
)
1346 if ((n
= xmlTextReaderCurrentNode(client
->reader
)) == NULL
) {
1347 xml_error
= xmlGetLastError();
1348 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1349 send_error(client
, EPWMD_LIBXML_ERROR
);
1353 for (a
= n
->properties
; a
; a
= a
->next
) {
1354 if ((attrlist
= g_realloc(attrlist
, (i
+ 2) * sizeof(gchar
*))) == NULL
) {
1355 log_write("%s(%i): g_realloc() failed", __FILE__
, __LINE__
);
1356 send_error(client
, EPWMD_ERROR
);
1361 attrlist
[i
++] = g_strdup_printf("%s\t%s", (gchar
*)a
->name
, (gchar
*)an
->content
);
1366 send_error(client
, EPWMD_EMPTY_ELEMENT
);
1370 line
= g_strjoinv("\n", attrlist
);
1371 send_to_client(client
, "BEGIN %li\n%s\n", g_utf8_strlen(line
, -1), line
);
1374 g_strfreev(attrlist
);
1382 * req[0] - attribute
1383 * req[1] - element path
1385 static gboolean
attribute_delete(struct client_s
*client
, gchar
**req
)
1389 gchar
**epath
= NULL
;
1390 xmlErrorPtr xml_error
;
1392 if (!req
|| !req
[0] || !req
[1]) {
1393 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1397 if ((epath
= split_input_line(req
[1], "\t", 0)) == NULL
) {
1399 * The first argument may be only an account.
1401 if ((epath
= split_input_line(req
[1], " ", 0)) == NULL
) {
1402 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1408 * Don't remove the NAME attribute for the account element.
1410 if (!epath
[1] && g_ascii_strcasecmp(req
[0], "NAME") == 0) {
1411 send_error(client
, EPWMD_ATTR_SYNTAX
);
1415 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1416 xml_error
= xmlGetLastError();
1417 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1418 send_error(client
, EPWMD_LIBXML_ERROR
);
1422 if (find_account(client
->reader
, epath
[0]) == FALSE
) {
1423 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1428 if ((find_elements(client
, client
->reader
, epath
+1, 0)) == FALSE
)
1432 if ((n
= xmlTextReaderCurrentNode(client
->reader
)) == NULL
) {
1433 xml_error
= xmlGetLastError();
1434 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1435 send_error(client
, EPWMD_LIBXML_ERROR
);
1439 if ((a
= xmlHasProp(n
, (xmlChar
*)req
[0])) == NULL
) {
1440 send_error(client
, EPWMD_ATTR_NOT_FOUND
);
1444 if (xmlRemoveProp(a
) == -1) {
1445 xml_error
= xmlGetLastError();
1446 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1447 send_error(client
, EPWMD_LIBXML_ERROR
);
1459 * req[0] - source element path
1460 * req[1] - destination element path
1462 static gboolean
target_attribute(struct client_s
*client
, gchar
**req
)
1464 gchar
**src
, **dst
, *line
;
1465 xmlErrorPtr xml_error
;
1467 if (!req
|| !req
[0] || !req
[1]) {
1468 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1472 if ((src
= split_input_line(req
[0], "\t", 0)) == NULL
) {
1474 * The first argument may be only an account.
1476 if ((src
= split_input_line(req
[0], " ", 0)) == NULL
) {
1477 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1482 if ((dst
= split_input_line(req
[1], "\t", 0)) == NULL
) {
1484 * The first argument may be only an account.
1486 if ((dst
= split_input_line(req
[1], " ", 0)) == NULL
) {
1487 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1494 * Prevent an element tree pointing to only and account. Accounts require
1495 * at least one element. Accounts pointing to accounts are allowed.
1497 if ((!src
[1] && dst
[1]) || (!dst
[1] && src
[1])) {
1498 send_error(client
, EPWMD_ATTR_SYNTAX
);
1504 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1505 xml_error
= xmlGetLastError();
1506 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1507 send_error(client
, EPWMD_LIBXML_ERROR
);
1514 * Make sure the destination element path exists.
1516 if (find_account(client
->reader
, dst
[0]) == FALSE
) {
1517 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1524 if (find_elements(client
, client
->reader
, dst
+1, 0) == FALSE
) {
1531 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1532 xml_error
= xmlGetLastError();
1533 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1534 send_error(client
, EPWMD_LIBXML_ERROR
);
1541 * If the source element tree doesn't exist, create it.
1543 if (find_account(client
->reader
, src
[0]) == FALSE
) {
1544 if (new_account(client
->doc
, src
[0]) == FALSE
) {
1545 xml_error
= xmlGetLastError();
1546 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1547 send_error(client
, EPWMD_LIBXML_ERROR
);
1553 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1554 xml_error
= xmlGetLastError();
1555 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1556 send_error(client
, EPWMD_LIBXML_ERROR
);
1562 if (find_account(client
->reader
, src
[0]) == FALSE
) {
1563 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1571 if (find_elements(client
, client
->reader
, src
+1, 1) == FALSE
) {
1572 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1573 xml_error
= xmlGetLastError();
1574 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1575 send_error(client
, EPWMD_LIBXML_ERROR
);
1581 if (find_account(client
->reader
, src
[0]) == FALSE
) {
1582 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1588 xmlTextReaderNext(client
->reader
);
1590 if (create_elements(client
, client
->reader
, src
+1, 1) == FALSE
) {
1596 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1597 xml_error
= xmlGetLastError();
1598 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1599 send_error(client
, EPWMD_LIBXML_ERROR
);
1605 if (find_account(client
->reader
, src
[0]) == FALSE
) {
1606 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1612 if (find_elements(client
, client
->reader
, src
+1, 0) == FALSE
) {
1620 line
= g_strjoinv("\t", dst
);
1622 if (add_attribute(client
, "target", line
) == FALSE
) {
1640 * req[0] - account name
1643 static gboolean
name_attribute(struct client_s
*client
, gchar
**req
)
1645 xmlErrorPtr xml_error
;
1647 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1648 xml_error
= xmlGetLastError();
1649 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1650 send_error(client
, EPWMD_LIBXML_ERROR
);
1654 if (find_account(client
->reader
, req
[0]) == FALSE
) {
1655 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1659 if (strcmp(req
[0], req
[1]) == 0)
1662 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1663 xml_error
= xmlGetLastError();
1664 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1665 send_error(client
, EPWMD_LIBXML_ERROR
);
1670 * Will not overwrite an existing account.
1672 if (find_account(client
->reader
, req
[1]) == TRUE
) {
1673 send_error(client
, EPWMD_ACCOUNT_EXISTS
);
1677 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1678 xml_error
= xmlGetLastError();
1679 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1680 send_error(client
, EPWMD_LIBXML_ERROR
);
1684 if (find_account(client
->reader
, req
[0]) == FALSE
) {
1685 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1690 * Whitespace not allowed in account names.
1692 if (contains_whitespace(req
[1]) == TRUE
) {
1693 send_error(client
, EPWMD_ATTR_SYNTAX
);
1697 return add_attribute(client
, "name", req
[1]);
1701 * req[0] - attribute
1702 * req[1] - element path
1704 * If the element has a "target" attribute it won't be "followed".
1706 static gboolean
attribute_get(struct client_s
*client
, gchar
**req
)
1710 gchar
**nreq
= NULL
;
1711 xmlErrorPtr xml_error
;
1713 if (!req
|| !req
[0] || !req
[1]) {
1714 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1718 if (strchr(req
[1], '\t')) {
1719 if ((nreq
= split_input_line(req
[1], "\t", 0)) == NULL
) {
1720 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1725 if ((nreq
= split_input_line(req
[1], " ", 0)) == NULL
) {
1726 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1731 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1732 xml_error
= xmlGetLastError();
1733 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1735 send_error(client
, EPWMD_LIBXML_ERROR
);
1739 if (find_account(client
->reader
, nreq
[0]) == FALSE
) {
1741 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1746 if (find_elements(client
, client
->reader
, nreq
+ 1, 0) == FALSE
) {
1754 if ((n
= xmlTextReaderCurrentNode(client
->reader
)) == NULL
) {
1755 xml_error
= xmlGetLastError();
1756 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1757 send_error(client
, EPWMD_LIBXML_ERROR
);
1761 if ((a
= xmlGetProp(n
, (xmlChar
*)req
[0])) == NULL
) {
1762 send_error(client
, EPWMD_ATTR_NOT_FOUND
);
1766 send_to_client(client
, "BEGIN %li\n%s\n", xmlStrlen(a
), a
);
1772 * req[0] - attribute
1773 * req[1] - element path
1776 static gboolean
attribute_set(struct client_s
*client
, gchar
**req
)
1778 gchar
**epath
= NULL
;
1779 xmlErrorPtr xml_error
;
1781 if (!req
|| !req
[0] || !req
[1] || !req
[2]) {
1782 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1787 * Reserved attribute names.
1789 if (g_ascii_strcasecmp(req
[0], "NAME") == 0) {
1791 * Only reserved for the account element. Not the rest of the
1794 if (strchr(req
[1], '\t') == NULL
)
1795 return name_attribute(client
, req
+ 1);
1797 else if (g_ascii_strcasecmp(req
[0], "TARGET") == 0)
1798 return target_attribute(client
, req
+ 1);
1800 if ((epath
= split_input_line(req
[1], "\t", 0)) == NULL
) {
1802 * The first argument may be only an account.
1804 if ((epath
= split_input_line(req
[1], " ", 0)) == NULL
) {
1805 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1810 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1811 xml_error
= xmlGetLastError();
1812 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1813 send_error(client
, EPWMD_LIBXML_ERROR
);
1817 if (find_account(client
->reader
, epath
[0]) == FALSE
) {
1818 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1823 if ((find_elements(client
, client
->reader
, epath
+1, 0)) == FALSE
)
1828 return add_attribute(client
, req
[0], req
[2]);
1836 * req[1] - attribute name or element path if command is LIST
1837 * req[2] - element path
1838 * req[2] - element path or value
1840 gboolean
attr_command(struct client_s
*client
, gchar
**req
)
1842 if (!req
|| !req
[0] || !req
[1]) {
1843 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1847 if (g_ascii_strcasecmp(req
[0], "SET") == 0)
1848 return attribute_set(client
, req
+1);
1849 if (g_ascii_strcasecmp(req
[0], "GET") == 0)
1850 return attribute_get(client
, req
+1);
1851 else if (g_ascii_strcasecmp(req
[0], "DELETE") == 0)
1852 return attribute_delete(client
, req
+1);
1853 else if (g_ascii_strcasecmp(req
[0], "LIST") == 0)
1854 return attribute_list(client
, req
+1);
1856 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1861 gboolean
cache_test(const guchar
*md5filename
, gint reset
)
1867 for (p
= shm_data
, len
= 0; len
<= cache_size
;) {
1868 memcpy(&f
, p
, sizeof(file_cache_t
));
1871 memset(&f
, 0, sizeof(file_cache_t
));
1872 memcpy(p
, &f
, sizeof(file_cache_t
));
1873 p
+= sizeof(file_cache_t
);
1874 len
+= sizeof(file_cache_t
);
1876 if (len
+ sizeof(file_cache_t
) > cache_size
)
1881 if (f
.used
== TRUE
) {
1882 if (memcmp((gchar
*)f
.filename
, (gchar
*)md5filename
, sizeof(f
.filename
)) == 0) {
1884 memset(&f
, 0, sizeof(file_cache_t
));
1885 memcpy(p
, &f
, sizeof(file_cache_t
));
1889 return cache_valid_key(f
.key
, sizeof(f
.key
));
1893 p
+= sizeof(file_cache_t
);
1894 len
+= sizeof(file_cache_t
);
1896 if (len
+ sizeof(file_cache_t
) > cache_size
)
1900 return (reset
== 2) ? TRUE
: FALSE
;
1903 static gboolean
file_exists(const gchar
*filename
)
1906 gchar filebuf
[PATH_MAX
], *p
, *p2
;
1908 p
= get_key_file_string("default", "data_directory");
1909 p2
= expand_homedir(p
);
1911 snprintf(filebuf
, sizeof(filebuf
), "%s/%s", p2
, filename
);
1914 if (access(filebuf
, R_OK
) == -1)
1919 if (st
.st_size
== 0)
1925 gboolean
cache_command(struct client_s
*client
, gchar
**req
)
1931 if (g_ascii_strcasecmp(req
[0], "CLEAR") == 0) {
1933 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1937 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[1], strlen(req
[1]));
1939 if (cache_test(md5file
, 1) == FALSE
) {
1940 send_error(client
, EPWMD_CACHE_NOT_FOUND
);
1946 else if (g_ascii_strcasecmp(req
[0], "CLEARALL") == 0) {
1947 cache_test(client
->md5file
, 2);
1950 else if (g_ascii_strcasecmp(req
[0], "ISCACHED") == 0) {
1952 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1956 if (file_exists(req
[1]) == FALSE
) {
1957 send_error(client
, EPWMD_FILE_NOT_FOUND
);
1961 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[1], strlen(req
[1]));
1963 if (cache_test(md5file
, 0) == FALSE
) {
1964 send_error(client
, EPWMD_CACHE_NOT_FOUND
);
1970 else if (g_ascii_strcasecmp(req
[0], "TIMEOUT") == 0) {
1971 if (!req
[1] || !req
[2]) {
1972 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1977 timeout
= strtol(req
[1], &p
, 10);
1979 if (errno
!= 0 || *p
!= 0) {
1980 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1984 if (file_exists(req
[2]) == FALSE
) {
1985 send_error(client
, EPWMD_FILE_NOT_FOUND
);
1989 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[2], strlen(req
[2]));
1991 if (cache_set_timeout(md5file
, timeout
) == FALSE
) {
1992 send_error(client
, EPWMD_CACHE_NOT_FOUND
);
1999 send_error(client
, EPWMD_COMMAND_SYNTAX
);
2004 gboolean
help_command(struct client_s
*client
, const gchar
*what
)
2008 if (!what
|| !*what
)
2010 "NFO Try 'HELP COMMAND' for command help\n"
2011 "NFO OPEN LIST GET STORE DELETE ATTR CACHE SAVE DUMP QUIT\n";
2012 else if (g_ascii_strcasecmp(what
, "GET") == 0)
2014 "NFO syntax: GET account <TAB> element [<TAB> element ...]\n"
2015 "NFO <account> is the account to work on and <element>\n"
2016 "NFO is the element wanted.\n"
2018 "NFO Example: GET isp <TAB> imap <TAB> port\n"
2019 "NFO GET isp <TAB> username\n";
2020 else if (g_ascii_strcasecmp(what
, "QUIT") == 0)
2022 "NFO syntax: QUIT\n"
2023 "NFO close the connection\n";
2024 else if (g_ascii_strcasecmp(what
, "DELETE") == 0)
2026 "NFO syntax: DELETE account <TAB> element [<TAB> element ...]\n";
2027 else if (g_ascii_strcasecmp(what
, "STORE") == 0)
2029 "NFO syntax: STORE account <TAB> element [<TAB> element ...] <TAB> value\n"
2030 "NFO <account> is the account to work on and <element>\n"
2031 "NFO is the element to create or modify\n"
2033 "NFO Example: STORE isp <TAB> imap <TAB> port <TAB> 993\n"
2034 "NFO STORE isp <TAB> username <TAB> someuser\n";
2035 else if (g_ascii_strcasecmp(what
, "OPEN") == 0)
2037 "NFO syntax: OPEN <filename> [<key>]\n"
2038 "NFO opens a (new) file\n";
2039 else if (g_ascii_strcasecmp(what
, "LIST") == 0)
2041 "NFO syntax: LIST [account]\n"
2042 "NFO shows available accounts or account elements\n";
2043 else if (g_ascii_strcasecmp(what
, "ATTR") == 0)
2045 "NFO syntax: ATTR SET|GET|DELETE|LIST [ATTRIBUTE] arg1 [arg2]\n"
2046 "NFO ATTR SET NAME account value\n"
2047 "NFO ATTR SET TARGET account[<TAB>element[...]] account[<TAB>element[...]\n"
2048 "NFO ATTR SET attribute account[<TAB>element[...]] attribute_value\n"
2049 "NFO ATTR DELETE attribute account[<TAB>element[...]]\n"
2050 "NFO ATTR GET attribute account[<TAB>element[...]]\n"
2051 "NFO ATTR LIST account[<TAB>element[...]]\n";
2052 else if (g_ascii_strcasecmp(what
, "SAVE") == 0)
2054 "NFO syntax: SAVE [<key>]\n"
2055 "NFO save any changes to the opened file using <key>\n";
2056 else if (g_ascii_strcasecmp(what
, "CACHE") == 0)
2058 "NFO syntax: CACHE [CLEARALL | [CLEAR | ISCACHED <filename>] |\n"
2059 "NFO TIMEOUT <seconds> <filename>]\n"
2060 "NFO tests or clears the cache entry for <filename>\n";
2061 else if (g_ascii_strcasecmp(what
, "DUMP") == 0)
2063 "NFO syntax: DUMP\n"
2064 "NFO shows the in memory XML document\n";
2066 send_error(client
, EPWMD_COMMAND_SYNTAX
);
2070 send_to_client(client
, "%sOK \n", line
);
2074 gboolean
dump_command(struct client_s
*client
)
2079 xmlDocDumpFormatMemory(client
->doc
, &xml
, &len
, 1);
2080 send_to_client(client
, "BEGIN %li\n%s", len
, xml
);