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_update_key(const guchar
*md5filename
, const guchar
*shakey
)
106 for (p
= shm_data
, len
= 0; len
<= cache_size
;) {
107 memcpy(&f
, p
, sizeof(file_cache_t
));
109 if (f
.used
== TRUE
) {
110 if (memcmp((gchar
*)f
.filename
, (gchar
*)md5filename
, sizeof(f
.filename
)) == 0) {
111 memcpy(&f
.key
, shakey
, sizeof(f
.key
));
112 memcpy(p
, &f
, sizeof(file_cache_t
));
117 p
+= sizeof(file_cache_t
);
118 len
+= sizeof(file_cache_t
);
120 if (len
+ sizeof(file_cache_t
) > cache_size
)
124 return cache_add_file(md5filename
, shakey
);
127 static gint
cache_valid_key(const guchar
*key
, gsize len
)
131 for (b
= 0; b
< len
; b
++) {
139 static gboolean
cache_get_key(const guchar
*md5file
, guchar
*shakey
)
145 for (p
= shm_data
, len
= 0; len
<= cache_size
;) {
146 memcpy(&f
, p
, sizeof(file_cache_t
));
149 * The slot may be used but not yet contain a key.
151 if (f
.used
== TRUE
) {
152 if (memcmp(&f
.filename
, md5file
, sizeof(f
.filename
)) == 0) {
153 if (cache_valid_key(f
.key
, sizeof(f
.key
)) == FALSE
)
156 memcpy(shakey
, &f
.key
, sizeof(f
.key
));
161 p
+= sizeof(file_cache_t
);
162 len
+= sizeof(file_cache_t
);
164 if (len
+ sizeof(file_cache_t
) > cache_size
)
171 gint
open_file(const gchar
*filename
, struct stat
*st
)
175 if ((fd
= open(filename
, O_RDONLY
)) == -1)
178 if (stat(filename
, st
) == -1) {
186 gboolean
open_command(struct client_s
*client
, gchar
**req
)
191 const gchar
*filename
= req
[0];
192 guchar shakey
[gcrykeysize
];
193 guchar tkey
[gcrykeysize
];
197 struct file_header_s
{
199 guchar iv
[gcryblocksize
];
202 if (!filename
|| !*filename
) {
203 send_error(client
, EPWMD_COMMAND_SYNTAX
);
207 if (valid_filename(filename
) == FALSE
) {
208 send_error(client
, EPWMD_INVALID_FILENAME
);
212 if (stat(filename
, &st
) == 0) {
213 if (!S_ISREG(st
.st_mode
) && !S_ISLNK(st
.st_mode
)) {
214 log_write("%s: %s", filename
, pwmd_strerror(EPWMD_NOT_A_FILE
));
215 send_to_client(client
, "ERR %03i %s\n", EPWMD_NOT_A_FILE
, pwmd_strerror(EPWMD_NOT_A_FILE
));
219 client
->mtime
= st
.st_mtime
;
222 gcry_md_hash_buffer(GCRY_MD_MD5
, client
->md5file
, filename
, strlen(filename
));
225 * New files don't need a key.
227 if (access(filename
, R_OK
|W_OK
) != 0) {
228 if (errno
!= ENOENT
) {
229 log_write("%s: %s", filename
, strerror(errno
));
230 send_to_client(client
, "ERR %03i %s: %s\n", EPWMD_ERROR
, filename
,
235 if ((client
->xml
= new_document()) == NULL
) {
236 log_write("%s", strerror(errno
));
237 send_to_client(client
, "ERR %03i malloc(): %s\n", EPWMD_ERROR
,
242 client
->len
= strlen(client
->xml
);
244 if (cache_add_file(client
->md5file
, NULL
) == FALSE
) {
245 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(EPWMD_MAX_SLOTS
));
246 send_error(client
, EPWMD_MAX_SLOTS
);
250 client
->filename
= g_strdup(filename
);
251 return parse_xml(client
);
254 if ((fd
= open_file(filename
, &st
)) == -1) {
255 log_write("%s: %s", filename
, strerror(errno
));
256 send_to_client(client
, "ERR %03i %s: %s\n", EPWMD_ERROR
, filename
, strerror(errno
));
263 if (cache_get_key(client
->md5file
, shakey
) == TRUE
)
267 * No key specified and no matching filename found in the cache.
269 if (!req
[1] || !*req
[1]) {
271 send_error(client
, EPWMD_KEY
);
276 insize
= st
.st_size
- sizeof(struct file_header_s
);
277 read(fd
, &file_header
, sizeof(struct file_header_s
));
278 inbuf
= gcry_malloc(insize
);
279 read(fd
, inbuf
, insize
);
284 gcry_md_hash_buffer(GCRY_MD_SHA256
, shakey
, req
[1], strlen(req
[1]));
285 memset(req
[1], 0, strlen(req
[1]));
288 if ((gcryerrno
= gcry_cipher_setiv(client
->gh
, file_header
.iv
,
289 sizeof(file_header
.iv
)))) {
291 memset(shakey
, 0, sizeof(shakey
));
292 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
293 send_to_client(client
, "ERR %03i gcrypt: %s\n", EPWMD_ERROR
, gcry_strerror(gcryerrno
));
297 if ((gcryerrno
= gcry_cipher_setkey(client
->gh
, shakey
, gcrykeysize
))) {
299 memset(shakey
, 0, sizeof(shakey
));
300 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
301 send_to_client(client
, "ERR %03i gcrypt: %s\n", EPWMD_ERROR
, gcry_strerror(gcryerrno
));
305 if (decrypt_xml(client
->gh
, inbuf
, insize
, NULL
, 0) == FALSE
) {
311 memset(shakey
, 0, sizeof(shakey
));
313 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
314 send_to_client(client
, "ERR %03i gcrypt: %s\n", EPWMD_ERROR
, gcry_strerror(gcryerrno
));
318 memcpy(tkey
, shakey
, sizeof(tkey
));
321 if ((gcryerrno
= gcry_cipher_setkey(client
->gh
, tkey
, gcrykeysize
))) {
322 memset(tkey
, 0, sizeof(tkey
));
324 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
325 send_to_client(client
, "ERR %03i gcrypt: %s\n", EPWMD_ERROR
, gcry_strerror(gcryerrno
));
329 iter
= file_header
.iter
;
332 if ((gcryerrno
= gcry_cipher_setiv(client
->gh
, file_header
.iv
,
333 sizeof(file_header
.iv
)))) {
334 memset(tkey
, 0, sizeof(tkey
));
336 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
337 send_to_client(client
, "ERR %03i gcrypt: %s\n", EPWMD_ERROR
, gcry_strerror(gcryerrno
));
341 if (decrypt_xml(client
->gh
, inbuf
, insize
, NULL
, 0) == FALSE
) {
347 memset(tkey
, 0, sizeof(tkey
));
349 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
350 send_to_client(client
, "ERR %03i gcrypt: %s\n", EPWMD_ERROR
, gcry_strerror(gcryerrno
));
355 memset(tkey
, 0, sizeof(tkey
));
357 client
->len
= insize
;
359 if (g_strncasecmp(client
->xml
, "<?xml version=\"1.0\"?>", 21) != 0) {
360 send_error(client
, EPWMD_BADKEY
);
365 if (cache_add_file(client
->md5file
, shakey
) == FALSE
) {
366 memset(shakey
, 0, sizeof(shakey
));
367 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(EPWMD_MAX_SLOTS
));
368 send_error(client
, EPWMD_MAX_SLOTS
);
373 memset(shakey
, 0, sizeof(shakey
));
374 client
->filename
= g_strdup(filename
);
375 return parse_xml(client
);
379 * client->reader should be at the position in the document where the element
380 * search should start. It won't search past the closing account element.
382 static gboolean
find_elements(struct client_s
*client
, xmlTextReaderPtr reader
,
383 gchar
**req
, gint quiet
)
387 if (!req
|| !req
[0]) {
389 send_error(client
, EPWMD_COMMAND_SYNTAX
);
393 for (i
= 0; req
[i
]; i
++) {
394 if (find_element(reader
, req
[i
], req
[i
+1] != NULL
) == FALSE
) {
396 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
405 gboolean
do_xml_encrypt(struct client_s
*client
, gcry_cipher_hd_t gh
,
406 const gchar
*filename
, const xmlChar
*data
, size_t insize
,
407 const guchar
*shakey
, guint iter
)
412 guchar tkey
[gcrykeysize
];
413 struct file_header_s
{
415 guchar iv
[gcryblocksize
];
418 if (insize
/ gcryblocksize
) {
419 len
= (insize
/ gcryblocksize
) * gcryblocksize
;
421 if (insize
% gcryblocksize
)
422 len
+= gcryblocksize
;
425 inbuf
= gcry_calloc(1, len
);
426 memcpy(inbuf
, data
, insize
);
428 gcry_create_nonce(file_header
.iv
, sizeof(file_header
.iv
));
429 memcpy(tkey
, shakey
, sizeof(tkey
));
432 if ((gcryerrno
= gcry_cipher_setkey(gh
, tkey
, gcrykeysize
))) {
434 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
435 send_to_client(client
, "ERR %03i gcrypt: %s\n", EPWMD_ERROR
, gcry_strerror(gcryerrno
));
439 file_header
.iter
= iter
;
442 if ((gcryerrno
= gcry_cipher_setiv(gh
, file_header
.iv
,
443 sizeof(file_header
.iv
)))) {
445 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
446 send_to_client(client
, "ERR %03i gcrypt: %s\n", EPWMD_ERROR
, gcry_strerror(gcryerrno
));
450 if (encrypt_xml(gh
, inbuf
, insize
, NULL
, 0)
453 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
454 send_to_client(client
, "ERR %03i gcrypt: %s\n", EPWMD_ERROR
, gcry_strerror(gcryerrno
));
459 if ((gcryerrno
= gcry_cipher_setiv(gh
, file_header
.iv
,
460 sizeof(file_header
.iv
)))) {
462 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
463 send_to_client(client
, "ERR %03i gcrypt: %s\n", EPWMD_ERROR
, gcry_strerror(gcryerrno
));
467 if ((gcryerrno
= gcry_cipher_setkey(gh
, shakey
, gcrykeysize
))) {
469 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
470 send_to_client(client
, "ERR %03i gcrypt: %s\n", EPWMD_ERROR
, gcry_strerror(gcryerrno
));
474 if (encrypt_xml(gh
, inbuf
, insize
, NULL
, 0)
477 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
478 send_to_client(client
, "ERR %03i gcrypt: %s\n", EPWMD_ERROR
, gcry_strerror(gcryerrno
));
483 if ((fd
= open(filename
, O_WRONLY
|O_CREAT
|O_TRUNC
, 0600)) == -1) {
485 log_write("%s: %s", filename
, strerror(errno
));
486 send_to_client(client
, "ERR %03i %s: %s\n", EPWMD_ERROR
, filename
, strerror(errno
));
492 * xml_import() from command line.
496 write(fd
, &file_header
, sizeof(struct file_header_s
));
497 write(fd
, inbuf
, insize
);
506 gboolean
save_command(struct client_s
*client
, const gchar
*filename
, gchar
*key
)
511 guchar shakey
[gcrykeysize
];
514 if (stat(filename
, &st
) == 0 && client
->mtime
) {
515 if (client
->mtime
!= st
.st_mtime
) {
516 log_write("%s: %s", filename
, pwmd_strerror(EPWMD_FILE_MODIFIED
));
517 send_error(client
, EPWMD_FILE_MODIFIED
);
523 if (cache_get_key(client
->md5file
, shakey
) == FALSE
) {
524 send_error(client
, EPWMD_KEY
);
531 gcry_md_hash_buffer(GCRY_MD_SHA256
, shakey
, key
, strlen(key
));
532 memset(key
, 0, strlen(key
));
535 xmlDocDumpFormatMemory(client
->doc
, &xmlbuf
, &len
, 0);
537 if (do_xml_encrypt(client
, client
->gh
, filename
, xmlbuf
, len
, shakey
,
538 client
->iter
) == FALSE
) {
539 memset(shakey
, 0, sizeof(shakey
));
546 client
->mtime
= st
.st_mtime
;
549 memset(shakey
, 0, sizeof(shakey
));
553 if (cache_update_key(client
->md5file
, shakey
) == FALSE
) {
554 memset(shakey
, 0, sizeof(shakey
));
555 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(EPWMD_MAX_SLOTS
));
556 send_error(client
, EPWMD_MAX_SLOTS
);
560 memset(shakey
, 0, sizeof(shakey
));
564 static gboolean
contains_whitespace(const gchar
*str
)
566 const gchar
*p
= str
;
569 if (g_ascii_isspace(*p
) == TRUE
) {
578 * the 'reader' should be at the element of the document where the elements
579 * 'req' are to be created.
581 static gboolean
create_elements(struct client_s
*client
, xmlTextReaderPtr reader
,
582 gchar
**req
, gint novalue
)
588 r
= xmlTextReaderCurrentNode(reader
);
590 if (xmlTextReaderDepth(reader
) > 1)
593 for (i
= 0; req
[i
]; i
++) {
597 * Whitespace is allowed in values or attributes but not in element
600 if (req
[i
+1] && valid_xml_element((xmlChar
*)req
[i
]) == FALSE
) {
601 send_error(client
, EPWMD_INVALID_ELEMENT
);
606 * The value of the element tree.
608 if (!req
[i
+1] && !novalue
) {
610 * Prevent creating 'text' elements in the root of the account.
613 send_error(client
, EPWMD_ROOT_TEXT_ELEMENT
);
618 * FIXME ?? overwriting an element tree with a text element:
620 * STORE account element element2 value
621 * STORE account element value
623 * would remove the existing element tree. This may be a bug or
626 xmlNodeSetContent(r
, (xmlChar
*)req
[i
]);
630 if ((n
= find_node(r
, (xmlChar
*)req
[i
])) == NULL
) {
631 n
= xmlNewNode(NULL
, (xmlChar
*)req
[i
]);
632 r
= xmlAddChild(r
, n
);
637 if (!req
[i
+1] && novalue
)
645 * FIXME reuse reader handle
647 static gboolean
reset_reader(xmlDocPtr doc
, xmlTextReaderPtr
*reader
)
650 xmlFreeTextReader(*reader
);
654 if ((*reader
= xmlReaderWalker(doc
)) == NULL
)
660 static void delete_node(xmlNodePtr n
)
666 gboolean
delete_command(struct client_s
*client
, gchar
**req
)
670 xmlErrorPtr xml_error
;
672 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
673 xml_error
= xmlGetLastError();
674 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
675 send_error(client
, EPWMD_LIBXML_ERROR
);
679 if (find_account(client
->reader
, req
[0]) == FALSE
) {
680 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
684 n
= xmlTextReaderCurrentNode(client
->reader
);
687 * No sub-node defined. Remove the entire node (account).
696 * Remove matching sub-nodes starting from the root of the account.
698 while (req
[i
] && find_element(client
->reader
, req
[i
++], req
[i
] != NULL
) == TRUE
)
699 n
= xmlTextReaderCurrentNode(client
->reader
);
701 if (n
&& xmlStrcmp(n
->name
, (xmlChar
*)req
[i
-1]) == 0 &&
702 xmlTextReaderNodeType(client
->reader
) == XML_READER_TYPE_ELEMENT
)
705 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
712 gboolean
store_command(struct client_s
*client
, gchar
**req
)
714 xmlErrorPtr xml_error
;
717 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
718 xml_error
= xmlGetLastError();
719 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
720 send_error(client
, EPWMD_LIBXML_ERROR
);
725 send_error(client
, EPWMD_COMMAND_SYNTAX
);
729 if (find_account(client
->reader
, req
[0]) == FALSE
) {
730 if (contains_whitespace(req
[0]) == TRUE
) {
731 send_error(client
, EPWMD_INVALID_ELEMENT
);
735 if (new_account(client
->doc
, req
[0]) == FALSE
) {
736 send_error(client
, EPWMD_ERROR
);
743 xmlTextReaderNext(client
->reader
);
744 return create_elements(client
, client
->reader
, req
+1, 0);
747 static gboolean
do_get_command(struct client_s
*client
, xmlTextReaderPtr
*reader
,
748 gchar
**req
, xmlChar
**content
, gint quiet
, gint list
)
755 xmlErrorPtr xml_error
;
757 if (reset_reader(client
->doc
, reader
) == FALSE
) {
759 xml_error
= xmlGetLastError();
760 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
761 send_error(client
, EPWMD_LIBXML_ERROR
);
767 if (find_account(*reader
, req
[0]) == FALSE
) {
769 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
774 * May be an account with only a TARGET attribute.
777 if (find_elements(client
, *reader
, req
+ 1, (list
) ? 1 : quiet
) == FALSE
)
781 if ((n
= xmlTextReaderCurrentNode(*reader
)) == NULL
) {
783 xml_error
= xmlGetLastError();
784 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
785 send_error(client
, EPWMD_LIBXML_ERROR
);
792 * If the current element has a TARGET attribute, the value of the
793 * attribute is an element path somewhere else in the document. Use this
794 * value and not any TEXT element value. The value may be another element
795 * with a TARGET attribute and this function will recurse until a non-TARGET
796 * attribute in the element is found.
798 if ((a
= xmlHasProp(n
, (xmlChar
*)"target")) != NULL
) {
799 if ((p
= xmlNodeGetContent(a
->children
)) != NULL
) {
800 if (strchr((gchar
*)p
, '\t') != NULL
) {
801 if ((nreq
= split_input_line((gchar
*)p
, "\t", 0)) == NULL
) {
805 send_error(client
, EPWMD_INVALID_ELEMENT
);
810 if ((nreq
= split_input_line((gchar
*)p
, " ", 0)) == NULL
) {
814 send_error(client
, EPWMD_INVALID_ELEMENT
);
820 ret
= do_get_command(client
, reader
, nreq
, content
, quiet
, list
);
826 switch (xmlTextReaderNext(*reader
)) {
829 xml_error
= xmlGetLastError();
830 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
831 send_error(client
, EPWMD_LIBXML_ERROR
);
837 send_error(client
, EPWMD_EMPTY_ELEMENT
);
843 switch (xmlTextReaderNodeType(*reader
)) {
844 case XML_READER_TYPE_END_ELEMENT
:
846 * May be an empty element after an ATTR DELETE TARGET command.
849 case XML_READER_TYPE_TEXT
:
853 xml_error
= xmlGetLastError();
854 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
855 send_error(client
, EPWMD_LIBXML_ERROR
);
861 if (n
->children
&& !list
)
862 send_error(client
, EPWMD_TRAILING_ELEMENT
);
863 else if (!n
->children
&& !list
)
864 send_error(client
, EPWMD_INVALID_ELEMENT
);
869 if ((*content
= xmlNodeGetContent(n
)) == NULL
) {
871 send_error(client
, EPWMD_EMPTY_ELEMENT
);
879 * Retrieves the value associated with the element tree 'req'.
881 gboolean
get_command(struct client_s
*client
, xmlTextReaderPtr
*reader
,
882 gchar
**req
, gint quiet
)
884 xmlChar
*content
= NULL
;
886 if (do_get_command(client
, reader
, req
, &content
, quiet
, 0) == FALSE
)
891 send_error(client
, EPWMD_EMPTY_ELEMENT
);
896 send_to_client(client
, "BEGIN %li\n%s\nOK \n", xmlStrlen(content
), content
);
902 static gchar
*element_path_to_req(const gchar
*account
, xmlChar
*path
,
903 const xmlChar
*content
)
905 static gchar
*element_path_to_req(const gchar
*account
, xmlChar
*path
)
915 for (n
= 0; *p
&& n
< 3; p
++) {
920 if (strstr((gchar
*)p
, "text()") != NULL
)
921 p
[xmlStrlen(p
) - 7] = 0;
923 for (n
= 0; p
[n
]; n
++) {
929 buf
= g_strdup_printf("%s\t%s\t%s", account
, p
, content
);
931 buf
= g_strdup_printf("%s\t%s", account
, p
);
936 static gboolean
append_to_array(gchar
***array
, gint
*total
, const gchar
*str
)
941 if ((a
= g_realloc(*array
, (t
+ 2) * sizeof(gchar
*))) == NULL
)
944 a
[t
++] = g_strdup(str
);
951 gboolean
list_command(struct client_s
*client
, gchar
*str
)
955 gchar
**elements
= NULL
;
956 gint pwmd_errno
= -1;
959 xmlChar
*path
= NULL
;
963 xmlTextReaderPtr r
= NULL
;
964 gchar
**req
= NULL
, **nreq
;
968 xmlErrorPtr xml_error
;
970 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
971 xml_error
= xmlGetLastError();
972 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
973 send_error(client
, EPWMD_LIBXML_ERROR
);
977 if (strchr(p
, ' ') == NULL
) {
979 if (list_accounts(client
->reader
, &dst
, &pwmd_errno
) == FALSE
) {
980 send_error(client
, pwmd_errno
);
984 send_to_client(client
, "BEGIN %i\n%s\nOK \n",
985 g_utf8_strlen(dst
, -1), dst
);
986 memset(dst
, 0, strlen(dst
));
995 while (*p
&& isspace(*p
))
1001 if (strchr(p
, '\t') != NULL
) {
1002 if ((req
= split_input_line(p
, "\t", 0)) == NULL
) {
1003 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1007 if (find_account(client
->reader
, req
[0]) == FALSE
) {
1008 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1012 if (find_elements(client
, client
->reader
, req
+ 1, 0) == FALSE
) {
1018 if (find_account(client
->reader
, p
) == FALSE
) {
1019 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1024 if ((n
= xmlTextReaderCurrentNode(client
->reader
)) == NULL
) {
1025 xml_error
= xmlGetLastError();
1026 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1027 send_error(client
, EPWMD_LIBXML_ERROR
);
1031 if ((a
= xmlHasProp(n
, (xmlChar
*)"target")) != NULL
) {
1032 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1033 send_error(client
, EPWMD_LIBXML_ERROR
);
1037 if ((content
= xmlNodeGetContent(a
->children
)) != NULL
) {
1038 if (find_account(client
->reader
, (gchar
*)content
) == FALSE
) {
1040 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1048 account
= (req
) ? g_strdup(req
[0]) : g_strdup(p
);
1053 while (xmlTextReaderNext(client
->reader
) == 1) {
1055 if ((n
= xmlTextReaderCurrentNode(client
->reader
)) == NULL
) {
1056 xml_error
= xmlGetLastError();
1057 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1058 send_error(client
, EPWMD_LIBXML_ERROR
);
1062 if (xmlTextReaderDepth(client
->reader
) == 1 &&
1063 xmlStrcmp(n
->name
, (xmlChar
*)"account") == 0 &&
1064 xmlTextReaderNodeType(client
->reader
) == XML_READER_TYPE_END_ELEMENT
)
1068 * If the current element has a TARGET attribute, the value of the
1069 * attribute is an element path somewhere else in the document. Use this
1070 * value and not any TEXT element value.
1072 type
= xmlTextReaderNodeType(client
->reader
);
1073 a
= xmlHasProp(n
, (xmlChar
*)"target");
1075 if (type
== XML_READER_TYPE_ELEMENT
&& a
) {
1076 if ((content
= xmlNodeGetContent(a
->children
)) != NULL
) {
1077 path
= xmlGetNodePath(n
);
1079 if ((nreq
= split_input_line((gchar
*)content
, "\t", 0)) == NULL
) {
1081 g_strfreev(elements
);
1085 send_error(client
, EPWMD_INVALID_ELEMENT
);
1092 if ((ret
= do_get_command(client
, &r
, nreq
, &content
, 0, 1)) == TRUE
) {
1093 if (content
&& *content
) {
1095 line
= element_path_to_req(account
, path
, content
);
1097 line
= element_path_to_req(account
, path
);
1101 if (append_to_array(&elements
, &total
, line
) == FALSE
) {
1103 g_strfreev(elements
);
1106 memset(line
, 0, g_utf8_strlen(line
, -1));
1109 xmlFreeTextReader(r
);
1110 send_error(client
, EPWMD_ERROR
);
1114 memset(line
, 0, g_utf8_strlen(line
, -1));
1118 if (xmlTextReaderNext(client
->reader
) == 1) {
1119 if (xmlTextReaderNodeType(client
->reader
) !=
1120 XML_READER_TYPE_TEXT
) {
1122 xmlFreeTextReader(r
);
1130 xmlFreeTextReader(r
);
1136 if (type
== XML_READER_TYPE_TEXT
) {
1137 xmlChar
*np
= xmlGetNodePath(n
);
1140 content
= xmlNodeGetContent(n
);
1141 line
= element_path_to_req(account
, np
, content
);
1144 line
= element_path_to_req(account
, np
);
1147 append_to_array(&elements
, &total
, line
);
1148 memset(line
, 0, g_utf8_strlen(line
, -1));
1154 send_error(client
, EPWMD_EMPTY_ELEMENT
);
1160 line
= g_strjoinv("\n", elements
);
1161 send_to_client(client
, "BEGIN %li\n%s\nOK \n",
1162 g_utf8_strlen(line
, -1), line
);
1163 g_strfreev(elements
);
1169 * The client->reader handle should be at the element in the document where
1170 * the attribute will be created or modified.
1172 static gboolean
add_attribute(struct client_s
*client
, const gchar
*name
, const gchar
*value
)
1176 xmlErrorPtr xml_error
;
1178 if ((n
= xmlTextReaderCurrentNode(client
->reader
)) == NULL
) {
1179 xml_error
= xmlGetLastError();
1180 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1181 send_error(client
, EPWMD_LIBXML_ERROR
);
1185 if ((a
= xmlHasProp(n
, (xmlChar
*)name
)) == NULL
)
1186 a
= xmlNewProp(n
, (xmlChar
*)name
, (xmlChar
*)value
);
1188 xmlNodeSetContent(a
->children
, (xmlChar
*)value
);
1194 * req[0] - element path
1196 static gboolean
attribute_list(struct client_s
*client
, gchar
**req
)
1198 gchar
**attrlist
= NULL
;
1200 gchar
**epath
= NULL
;
1204 xmlErrorPtr xml_error
;
1206 if (!req
|| !req
[0]) {
1207 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1211 if ((epath
= split_input_line(req
[0], "\t", 0)) == NULL
) {
1213 * The first argument may be only an account.
1215 if ((epath
= split_input_line(req
[0], " ", 0)) == NULL
) {
1216 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1221 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1222 xml_error
= xmlGetLastError();
1223 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1224 send_error(client
, EPWMD_LIBXML_ERROR
);
1228 if (find_account(client
->reader
, epath
[0]) == FALSE
) {
1229 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1234 if ((find_elements(client
, client
->reader
, epath
+1, 0)) == FALSE
)
1238 if ((n
= xmlTextReaderCurrentNode(client
->reader
)) == NULL
) {
1239 xml_error
= xmlGetLastError();
1240 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1241 send_error(client
, EPWMD_LIBXML_ERROR
);
1245 for (a
= n
->properties
; a
; a
= a
->next
) {
1246 if ((attrlist
= g_realloc(attrlist
, (i
+ 2) * sizeof(gchar
*))) == NULL
) {
1247 log_write("%s(%i): g_realloc() failed", __FILE__
, __LINE__
);
1248 send_error(client
, EPWMD_ERROR
);
1253 attrlist
[i
++] = g_strdup_printf("%s\t%s", (gchar
*)a
->name
, (gchar
*)an
->content
);
1258 send_error(client
, EPWMD_EMPTY_ELEMENT
);
1262 line
= g_strjoinv("\n", attrlist
);
1263 send_to_client(client
, "BEGIN %li\n%s\n", g_utf8_strlen(line
, -1), line
);
1266 g_strfreev(attrlist
);
1274 * req[0] - attribute
1275 * req[1] - element path
1277 static gboolean
attribute_delete(struct client_s
*client
, gchar
**req
)
1281 gchar
**epath
= NULL
;
1282 xmlErrorPtr xml_error
;
1284 if (!req
|| !req
[0] || !req
[1]) {
1285 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1289 if ((epath
= split_input_line(req
[1], "\t", 0)) == NULL
) {
1291 * The first argument may be only an account.
1293 if ((epath
= split_input_line(req
[1], " ", 0)) == NULL
) {
1294 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1300 * Don't remove the NAME attribute for the account element.
1302 if (!epath
[1] && g_ascii_strcasecmp(req
[0], "NAME") == 0) {
1303 send_error(client
, EPWMD_ATTR_SYNTAX
);
1307 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1308 xml_error
= xmlGetLastError();
1309 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1310 send_error(client
, EPWMD_LIBXML_ERROR
);
1314 if (find_account(client
->reader
, epath
[0]) == FALSE
) {
1315 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1320 if ((find_elements(client
, client
->reader
, epath
+1, 0)) == FALSE
)
1324 if ((n
= xmlTextReaderCurrentNode(client
->reader
)) == NULL
) {
1325 xml_error
= xmlGetLastError();
1326 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1327 send_error(client
, EPWMD_LIBXML_ERROR
);
1331 if ((a
= xmlHasProp(n
, (xmlChar
*)req
[0])) == NULL
) {
1332 send_error(client
, EPWMD_ATTR_NOT_FOUND
);
1336 if (xmlRemoveProp(a
) == -1) {
1337 xml_error
= xmlGetLastError();
1338 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1339 send_error(client
, EPWMD_LIBXML_ERROR
);
1351 * req[0] - source element path
1352 * req[1] - destination element path
1354 static gboolean
target_attribute(struct client_s
*client
, gchar
**req
)
1356 gchar
**src
, **dst
, *line
;
1357 xmlErrorPtr xml_error
;
1359 if (!req
|| !req
[0] || !req
[1]) {
1360 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1364 if ((src
= split_input_line(req
[0], "\t", 0)) == NULL
) {
1366 * The first argument may be only an account.
1368 if ((src
= split_input_line(req
[0], " ", 0)) == NULL
) {
1369 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1374 if ((dst
= split_input_line(req
[1], "\t", 0)) == NULL
) {
1376 * The first argument may be only an account.
1378 if ((dst
= split_input_line(req
[1], " ", 0)) == NULL
) {
1379 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1386 * Prevent an element tree pointing to only and account. Accounts require
1387 * at least one element. Accounts pointing to accounts are allowed.
1389 if ((!src
[1] && dst
[1]) || (!dst
[1] && src
[1])) {
1390 send_error(client
, EPWMD_ATTR_SYNTAX
);
1396 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1397 xml_error
= xmlGetLastError();
1398 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1399 send_error(client
, EPWMD_LIBXML_ERROR
);
1406 * Make sure the destination element path exists.
1408 if (find_account(client
->reader
, dst
[0]) == FALSE
) {
1409 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1416 if (find_elements(client
, client
->reader
, dst
+1, 0) == FALSE
) {
1423 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1424 xml_error
= xmlGetLastError();
1425 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1426 send_error(client
, EPWMD_LIBXML_ERROR
);
1433 * If the source element tree doesn't exist, create it.
1435 if (find_account(client
->reader
, src
[0]) == FALSE
) {
1436 if (new_account(client
->doc
, src
[0]) == FALSE
) {
1437 xml_error
= xmlGetLastError();
1438 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1439 send_error(client
, EPWMD_LIBXML_ERROR
);
1445 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1446 xml_error
= xmlGetLastError();
1447 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1448 send_error(client
, EPWMD_LIBXML_ERROR
);
1454 if (find_account(client
->reader
, src
[0]) == FALSE
) {
1455 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1463 if (find_elements(client
, client
->reader
, src
+1, 1) == FALSE
) {
1464 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1465 xml_error
= xmlGetLastError();
1466 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1467 send_error(client
, EPWMD_LIBXML_ERROR
);
1473 if (find_account(client
->reader
, src
[0]) == FALSE
) {
1474 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1480 xmlTextReaderNext(client
->reader
);
1482 if (create_elements(client
, client
->reader
, src
+1, 1) == FALSE
) {
1488 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1489 xml_error
= xmlGetLastError();
1490 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1491 send_error(client
, EPWMD_LIBXML_ERROR
);
1497 if (find_account(client
->reader
, src
[0]) == FALSE
) {
1498 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1504 if (find_elements(client
, client
->reader
, src
+1, 0) == FALSE
) {
1512 line
= g_strjoinv("\t", dst
);
1514 if (add_attribute(client
, "target", line
) == FALSE
) {
1532 * req[0] - account name
1535 static gboolean
name_attribute(struct client_s
*client
, gchar
**req
)
1537 xmlErrorPtr xml_error
;
1539 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1540 xml_error
= xmlGetLastError();
1541 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1542 send_error(client
, EPWMD_LIBXML_ERROR
);
1546 if (find_account(client
->reader
, req
[0]) == FALSE
) {
1547 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1551 if (strcmp(req
[0], req
[1]) == 0)
1554 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1555 xml_error
= xmlGetLastError();
1556 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1557 send_error(client
, EPWMD_LIBXML_ERROR
);
1562 * Will not overwrite an existing account.
1564 if (find_account(client
->reader
, req
[1]) == TRUE
) {
1565 send_error(client
, EPWMD_ACCOUNT_EXISTS
);
1569 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1570 xml_error
= xmlGetLastError();
1571 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1572 send_error(client
, EPWMD_LIBXML_ERROR
);
1576 if (find_account(client
->reader
, req
[0]) == FALSE
) {
1577 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1582 * Whitespace not allowed in account names.
1584 if (contains_whitespace(req
[1]) == TRUE
) {
1585 send_error(client
, EPWMD_ATTR_SYNTAX
);
1589 return add_attribute(client
, "name", req
[1]);
1593 * req[0] - attribute
1594 * req[1] - element path
1596 * If the element has a "target" attribute it won't be "followed".
1598 static gboolean
attribute_get(struct client_s
*client
, gchar
**req
)
1602 gchar
**nreq
= NULL
;
1603 xmlErrorPtr xml_error
;
1605 if (!req
|| !req
[0] || !req
[1]) {
1606 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1610 if (strchr(req
[1], '\t')) {
1611 if ((nreq
= split_input_line(req
[1], "\t", 0)) == NULL
) {
1612 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1617 if ((nreq
= split_input_line(req
[1], " ", 0)) == NULL
) {
1618 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1623 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1624 xml_error
= xmlGetLastError();
1625 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1627 send_error(client
, EPWMD_LIBXML_ERROR
);
1631 if (find_account(client
->reader
, nreq
[0]) == FALSE
) {
1633 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1638 if (find_elements(client
, client
->reader
, nreq
+ 1, 0) == FALSE
) {
1646 if ((n
= xmlTextReaderCurrentNode(client
->reader
)) == NULL
) {
1647 xml_error
= xmlGetLastError();
1648 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1649 send_error(client
, EPWMD_LIBXML_ERROR
);
1653 if ((a
= xmlGetProp(n
, (xmlChar
*)req
[0])) == NULL
) {
1654 send_error(client
, EPWMD_ATTR_NOT_FOUND
);
1658 send_to_client(client
, "BEGIN %li\n%s\n", xmlStrlen(a
), a
);
1664 * req[0] - attribute
1665 * req[1] - element path
1668 static gboolean
attribute_set(struct client_s
*client
, gchar
**req
)
1670 gchar
**epath
= NULL
;
1671 xmlErrorPtr xml_error
;
1673 if (!req
|| !req
[0] || !req
[1] || !req
[2]) {
1674 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1679 * Reserved attribute names.
1681 if (g_ascii_strcasecmp(req
[0], "NAME") == 0) {
1683 * Only reserved for the account element. Not the rest of the
1686 if (strchr(req
[1], '\t') == NULL
)
1687 return name_attribute(client
, req
+ 1);
1689 else if (g_ascii_strcasecmp(req
[0], "TARGET") == 0)
1690 return target_attribute(client
, req
+ 1);
1692 if ((epath
= split_input_line(req
[1], "\t", 0)) == NULL
) {
1694 * The first argument may be only an account.
1696 if ((epath
= split_input_line(req
[1], " ", 0)) == NULL
) {
1697 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1702 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1703 xml_error
= xmlGetLastError();
1704 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1705 send_error(client
, EPWMD_LIBXML_ERROR
);
1709 if (find_account(client
->reader
, epath
[0]) == FALSE
) {
1710 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1715 if ((find_elements(client
, client
->reader
, epath
+1, 0)) == FALSE
)
1720 return add_attribute(client
, req
[0], req
[2]);
1728 * req[1] - attribute name or element path if command is LIST
1729 * req[2] - element path
1730 * req[2] - element path or value
1732 gboolean
attr_command(struct client_s
*client
, gchar
**req
)
1734 if (!req
|| !req
[0] || !req
[1]) {
1735 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1739 if (g_ascii_strcasecmp(req
[0], "SET") == 0)
1740 return attribute_set(client
, req
+1);
1741 if (g_ascii_strcasecmp(req
[0], "GET") == 0)
1742 return attribute_get(client
, req
+1);
1743 else if (g_ascii_strcasecmp(req
[0], "DELETE") == 0)
1744 return attribute_delete(client
, req
+1);
1745 else if (g_ascii_strcasecmp(req
[0], "LIST") == 0)
1746 return attribute_list(client
, req
+1);
1748 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1753 static gboolean
cache_test(const guchar
*md5filename
, gint reset
)
1759 for (p
= shm_data
, len
= 0; len
<= cache_size
;) {
1760 memcpy(&f
, p
, sizeof(file_cache_t
));
1763 memset(&f
, 0, sizeof(file_cache_t
));
1764 memcpy(p
, &f
, sizeof(file_cache_t
));
1765 p
+= sizeof(file_cache_t
);
1766 len
+= sizeof(file_cache_t
);
1768 if (len
+ sizeof(file_cache_t
) > cache_size
)
1773 if (f
.used
== TRUE
) {
1774 if (memcmp((gchar
*)f
.filename
, (gchar
*)md5filename
, sizeof(f
.filename
)) == 0) {
1776 memset(&f
, 0, sizeof(file_cache_t
));
1777 memcpy(p
, &f
, sizeof(file_cache_t
));
1781 return (f
.key
[0]) ? TRUE
: FALSE
;
1785 p
+= sizeof(file_cache_t
);
1786 len
+= sizeof(file_cache_t
);
1788 if (len
+ sizeof(file_cache_t
) > cache_size
)
1792 return (reset
== 2) ? TRUE
: FALSE
;
1795 static gboolean
file_exists(const gchar
*filename
)
1799 if (access(filename
, R_OK
) == -1)
1802 stat(filename
, &st
);
1804 if (st
.st_size
== 0)
1810 gboolean
cache_command(struct client_s
*client
, gchar
**req
)
1814 if (g_ascii_strcasecmp(req
[0], "clear") == 0) {
1816 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1820 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[1], strlen(req
[1]));
1822 if (cache_test(md5file
, 1) == FALSE
) {
1823 send_error(client
, EPWMD_CACHE_NOT_FOUND
);
1829 else if (g_ascii_strcasecmp(req
[0], "clearall") == 0) {
1830 cache_test(client
->md5file
, 2);
1833 else if (g_ascii_strcasecmp(req
[0], "iscached") == 0) {
1835 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1839 if (file_exists(req
[1]) == FALSE
) {
1840 send_error(client
, EPWMD_FILE_NOT_FOUND
);
1844 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[1], strlen(req
[1]));
1846 if (cache_test(md5file
, 0) == FALSE
) {
1847 send_error(client
, EPWMD_CACHE_NOT_FOUND
);
1854 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1859 gboolean
help_command(struct client_s
*client
, const gchar
*what
)
1863 if (!what
|| !*what
)
1865 "NFO Try 'HELP COMMAND' for command help\n"
1866 "NFO OPEN LIST GET STORE DELETE ATTR CACHE SAVE DUMP QUIT\n";
1867 else if (g_ascii_strcasecmp(what
, "GET") == 0)
1869 "NFO syntax: GET account <TAB> element [<TAB> element ...]\n"
1870 "NFO <account> is the account to work on and <element>\n"
1871 "NFO is the element wanted.\n"
1873 "NFO Example: GET isp <TAB> imap <TAB> port\n"
1874 "NFO GET isp <TAB> username\n";
1875 else if (g_ascii_strcasecmp(what
, "QUIT") == 0)
1877 "NFO syntax: QUIT\n"
1878 "NFO close the connection\n";
1879 else if (g_ascii_strcasecmp(what
, "DELETE") == 0)
1881 "NFO syntax: DELETE account <TAB> element [<TAB> element ...]\n";
1882 else if (g_ascii_strcasecmp(what
, "STORE") == 0)
1884 "NFO syntax: STORE account <TAB> element [<TAB> element ...] <TAB> value\n"
1885 "NFO <account> is the account to work on and <element>\n"
1886 "NFO is the element to create or modify\n"
1888 "NFO Example: STORE isp <TAB> imap <TAB> port <TAB> 993\n"
1889 "NFO STORE isp <TAB> username <TAB> someuser\n";
1890 else if (g_ascii_strcasecmp(what
, "OPEN") == 0)
1892 "NFO syntax: OPEN <filename> [<key>]\n"
1893 "NFO opens a (new) file\n";
1894 else if (g_ascii_strcasecmp(what
, "LIST") == 0)
1896 "NFO syntax: LIST [account]\n"
1897 "NFO shows available accounts or account elements\n";
1898 else if (g_ascii_strcasecmp(what
, "ATTR") == 0)
1900 "NFO syntax: ATTR SET|GET|DELETE|LIST [ATTRIBUTE] arg1 [arg2]\n"
1901 "NFO ATTR SET NAME account value\n"
1902 "NFO ATTR SET TARGET account[<TAB>element[...]] account[<TAB>element[...]\n"
1903 "NFO ATTR SET attribute account[<TAB>element[...]] attribute_value\n"
1904 "NFO ATTR DELETE attribute account[<TAB>element[...]]\n"
1905 "NFO ATTR GET attribute account[<TAB>element[...]]\n"
1906 "NFO ATTR LIST account[<TAB>element[...]]\n";
1907 else if (g_ascii_strcasecmp(what
, "SAVE") == 0)
1909 "NFO syntax: SAVE [<key>]\n"
1910 "NFO save any changes to the opened file using <key>\n";
1911 else if (g_ascii_strcasecmp(what
, "CACHE") == 0)
1913 "NFO syntax: CACHE [CLEARALL | CLEAR <filename> | ISCACHED <filename>]\n"
1914 "NFO tests or clears the cache entry for <filename>\n";
1915 else if (g_ascii_strcasecmp(what
, "DUMP") == 0)
1917 "NFO syntax: DUMP\n"
1918 "NFO shows the in memory XML document\n";
1920 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1924 send_to_client(client
, "%sOK \n", line
);
1928 gboolean
dump_command(struct client_s
*client
)
1933 xmlDocDumpFormatMemory(client
->doc
, &xml
, &len
, 1);
1934 send_to_client(client
, "BEGIN %li\n%s", len
, xml
);