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) {
111 memcpy(p
, &f
, sizeof(file_cache_t
));
115 p
+= sizeof(file_cache_t
);
116 len
+= sizeof(file_cache_t
);
118 if (len
+ sizeof(file_cache_t
) > cache_size
)
125 gboolean
cache_set_timeout(const guchar
*md5filename
, glong timeout
)
131 for (p
= shm_data
, len
= 0; len
<= cache_size
;) {
132 memcpy(&f
, p
, sizeof(file_cache_t
));
135 if (memcmp((gchar
*)f
.filename
, (gchar
*)md5filename
, sizeof(f
.filename
)) == 0) {
136 f
.when
= f
.timeout
= timeout
;
137 memcpy(p
, &f
, sizeof(file_cache_t
));
142 f
.when
= f
.timeout
= timeout
;
143 memcpy(p
, &f
, sizeof(file_cache_t
));
146 p
+= sizeof(file_cache_t
);
147 len
+= sizeof(file_cache_t
);
149 if (len
+ sizeof(file_cache_t
) > cache_size
)
153 return (md5filename
) ? FALSE
: TRUE
;
156 static gboolean
cache_update_key(const guchar
*md5filename
, const guchar
*shakey
)
162 for (p
= shm_data
, len
= 0; len
<= cache_size
;) {
163 memcpy(&f
, p
, sizeof(file_cache_t
));
165 if (f
.used
== TRUE
) {
166 if (memcmp((gchar
*)f
.filename
, (gchar
*)md5filename
, sizeof(f
.filename
)) == 0) {
167 memcpy(&f
.key
, shakey
, sizeof(f
.key
));
168 memcpy(p
, &f
, sizeof(file_cache_t
));
173 p
+= sizeof(file_cache_t
);
174 len
+= sizeof(file_cache_t
);
176 if (len
+ sizeof(file_cache_t
) > cache_size
)
180 return cache_add_file(md5filename
, shakey
);
183 static gint
cache_valid_key(const guchar
*key
, gsize len
)
187 for (b
= 0; b
< len
; b
++) {
195 static gboolean
cache_get_key(const guchar
*md5file
, guchar
*shakey
)
201 for (p
= shm_data
, len
= 0; len
<= cache_size
;) {
202 memcpy(&f
, p
, sizeof(file_cache_t
));
205 * The slot may be used but not yet contain a key.
207 if (f
.used
== TRUE
) {
208 if (memcmp(&f
.filename
, md5file
, sizeof(f
.filename
)) == 0) {
209 if (cache_valid_key(f
.key
, sizeof(f
.key
)) == FALSE
)
212 memcpy(shakey
, &f
.key
, sizeof(f
.key
));
217 p
+= sizeof(file_cache_t
);
218 len
+= sizeof(file_cache_t
);
220 if (len
+ sizeof(file_cache_t
) > cache_size
)
227 gint
open_file(const gchar
*filename
, struct stat
*st
)
231 if ((fd
= open(filename
, O_RDONLY
)) == -1)
234 if (stat(filename
, st
) == -1) {
242 gboolean
open_command(struct client_s
*client
, gchar
**req
)
247 const gchar
*filename
= req
[0];
248 guchar shakey
[gcrykeysize
];
249 guchar tkey
[gcrykeysize
];
254 gchar filebuf
[PATH_MAX
], *p
, *p2
;
257 struct file_header_s
{
259 guchar iv
[gcryblocksize
];
262 if (!filename
|| !*filename
) {
263 send_error(client
, EPWMD_COMMAND_SYNTAX
);
267 if (valid_filename(filename
) == FALSE
) {
268 send_error(client
, EPWMD_INVALID_FILENAME
);
272 p
= get_key_file_string("default", "data_directory");
273 p2
= expand_homedir(p
);
275 snprintf(filebuf
, sizeof(filebuf
), "%s/%s", p2
, filename
);
278 if (stat(filebuf
, &st
) == 0) {
279 if (!S_ISREG(st
.st_mode
) && !S_ISLNK(st
.st_mode
)) {
280 log_write("%s: %s", filename
, pwmd_strerror(EPWMD_NOT_A_FILE
));
281 send_to_client(client
, "ERR %03i %s\n", EPWMD_NOT_A_FILE
, pwmd_strerror(EPWMD_NOT_A_FILE
));
285 client
->mtime
= st
.st_mtime
;
288 gcry_md_hash_buffer(GCRY_MD_MD5
, client
->md5file
, filename
, strlen(filename
));
291 * New files don't need a key.
293 if (access(filebuf
, R_OK
|W_OK
) != 0) {
294 if (errno
!= ENOENT
) {
296 log_write("%s: %s", filename
, strerror(errno
));
297 send_to_client(client
, "ERR %03i %s: %s\n", EPWMD_ERROR
, filename
,
302 if ((client
->xml
= new_document()) == NULL
) {
304 log_write("%s", strerror(errno
));
305 send_to_client(client
, "ERR %03i malloc(): %s\n", EPWMD_ERROR
,
310 client
->len
= strlen(client
->xml
);
312 if (cache_add_file(client
->md5file
, NULL
) == FALSE
) {
313 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(EPWMD_MAX_SLOTS
));
314 send_error(client
, EPWMD_MAX_SLOTS
);
318 client
->filename
= g_strdup(filename
);
319 return parse_xml(client
);
322 if ((fd
= open_file(filebuf
, &st
)) == -1) {
324 log_write("%s: %s", filename
, strerror(errno
));
325 send_to_client(client
, "ERR %03i %s: %s\n", EPWMD_ERROR
, filename
, strerror(error
));
332 if (cache_get_key(client
->md5file
, shakey
) == TRUE
)
336 * No key specified and no matching filename found in the cache.
338 if (!req
[1] || !*req
[1]) {
340 send_error(client
, EPWMD_KEY
);
345 insize
= st
.st_size
- sizeof(struct file_header_s
);
346 read(fd
, &file_header
, sizeof(struct file_header_s
));
347 inbuf
= gcry_malloc(insize
);
348 read(fd
, inbuf
, insize
);
353 gcry_md_hash_buffer(GCRY_MD_SHA256
, shakey
, req
[1], strlen(req
[1]));
354 memset(req
[1], 0, strlen(req
[1]));
357 if ((gcryerrno
= gcry_cipher_setiv(client
->gh
, file_header
.iv
,
358 sizeof(file_header
.iv
)))) {
360 memset(shakey
, 0, sizeof(shakey
));
361 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
362 send_to_client(client
, "ERR %03i gcrypt: %s\n", EPWMD_ERROR
, gcry_strerror(gcryerrno
));
366 if ((gcryerrno
= gcry_cipher_setkey(client
->gh
, shakey
, gcrykeysize
))) {
368 memset(shakey
, 0, sizeof(shakey
));
369 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
370 send_to_client(client
, "ERR %03i gcrypt: %s\n", EPWMD_ERROR
, gcry_strerror(gcryerrno
));
374 if (decrypt_xml(client
->gh
, inbuf
, insize
, NULL
, 0) == FALSE
) {
380 memset(shakey
, 0, sizeof(shakey
));
382 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
383 send_to_client(client
, "ERR %03i gcrypt: %s\n", EPWMD_ERROR
, gcry_strerror(gcryerrno
));
387 memcpy(tkey
, shakey
, sizeof(tkey
));
390 if ((gcryerrno
= gcry_cipher_setkey(client
->gh
, tkey
, gcrykeysize
))) {
391 memset(tkey
, 0, sizeof(tkey
));
393 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
394 send_to_client(client
, "ERR %03i gcrypt: %s\n", EPWMD_ERROR
, gcry_strerror(gcryerrno
));
398 iter
= file_header
.iter
;
401 if ((gcryerrno
= gcry_cipher_setiv(client
->gh
, file_header
.iv
,
402 sizeof(file_header
.iv
)))) {
403 memset(tkey
, 0, sizeof(tkey
));
405 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
406 send_to_client(client
, "ERR %03i gcrypt: %s\n", EPWMD_ERROR
, gcry_strerror(gcryerrno
));
410 if (decrypt_xml(client
->gh
, inbuf
, insize
, NULL
, 0) == FALSE
) {
416 memset(tkey
, 0, sizeof(tkey
));
418 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
419 send_to_client(client
, "ERR %03i gcrypt: %s\n", EPWMD_ERROR
, gcry_strerror(gcryerrno
));
424 memset(tkey
, 0, sizeof(tkey
));
426 client
->len
= insize
;
428 if (g_strncasecmp(client
->xml
, "<?xml version=\"1.0\"?>", 21) != 0) {
429 send_error(client
, EPWMD_BADKEY
);
434 if (cache_add_file(client
->md5file
, shakey
) == FALSE
) {
435 memset(shakey
, 0, sizeof(shakey
));
436 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(EPWMD_MAX_SLOTS
));
437 send_error(client
, EPWMD_MAX_SLOTS
);
442 memset(shakey
, 0, sizeof(shakey
));
443 client
->filename
= g_strdup(filename
);
446 timeout
= get_key_file_integer(client
->filename
, "cache_timeout");
447 cache_set_timeout(client
->md5file
, timeout
);
450 if ((reset_timeout
= get_key_file_boolean(client
->filename
,
451 "cache_reset_timeout")) == TRUE
)
452 cache_reset_timeout(client
->md5file
);
455 return parse_xml(client
);
459 * client->reader should be at the position in the document where the element
460 * search should start. It won't search past the closing account element.
462 static gboolean
find_elements(struct client_s
*client
, xmlTextReaderPtr reader
,
463 gchar
**req
, gint quiet
)
467 if (!req
|| !req
[0]) {
469 send_error(client
, EPWMD_COMMAND_SYNTAX
);
473 for (i
= 0; req
[i
]; i
++) {
474 if (find_element(reader
, req
[i
], req
[i
+1] != NULL
) == FALSE
) {
476 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
485 gboolean
do_xml_encrypt(struct client_s
*client
, gcry_cipher_hd_t gh
,
486 const gchar
*filename
, const xmlChar
*data
, size_t insize
,
487 const guchar
*shakey
, guint iter
)
492 guchar tkey
[gcrykeysize
];
495 struct file_header_s
{
497 guchar iv
[gcryblocksize
];
500 if (insize
/ gcryblocksize
) {
501 len
= (insize
/ gcryblocksize
) * gcryblocksize
;
503 if (insize
% gcryblocksize
)
504 len
+= gcryblocksize
;
507 inbuf
= gcry_calloc(1, len
);
508 memcpy(inbuf
, data
, insize
);
510 gcry_create_nonce(file_header
.iv
, sizeof(file_header
.iv
));
511 memcpy(tkey
, shakey
, sizeof(tkey
));
514 if ((gcryerrno
= gcry_cipher_setkey(gh
, tkey
, gcrykeysize
))) {
516 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
517 send_to_client(client
, "ERR %03i gcrypt: %s\n", EPWMD_ERROR
, gcry_strerror(gcryerrno
));
521 file_header
.iter
= iter
;
524 if ((gcryerrno
= gcry_cipher_setiv(gh
, file_header
.iv
,
525 sizeof(file_header
.iv
)))) {
527 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
528 send_to_client(client
, "ERR %03i gcrypt: %s\n", EPWMD_ERROR
, gcry_strerror(gcryerrno
));
532 if (encrypt_xml(gh
, inbuf
, insize
, NULL
, 0)
535 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
536 send_to_client(client
, "ERR %03i gcrypt: %s\n", EPWMD_ERROR
, gcry_strerror(gcryerrno
));
541 if ((gcryerrno
= gcry_cipher_setiv(gh
, file_header
.iv
,
542 sizeof(file_header
.iv
)))) {
544 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
545 send_to_client(client
, "ERR %03i gcrypt: %s\n", EPWMD_ERROR
, gcry_strerror(gcryerrno
));
549 if ((gcryerrno
= gcry_cipher_setkey(gh
, shakey
, gcrykeysize
))) {
551 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
552 send_to_client(client
, "ERR %03i gcrypt: %s\n", EPWMD_ERROR
, gcry_strerror(gcryerrno
));
556 if (encrypt_xml(gh
, inbuf
, insize
, NULL
, 0)
559 log_write("%s(%i): %s", __FUNCTION__
, __LINE__
, gcry_strerror(gcryerrno
));
560 send_to_client(client
, "ERR %03i gcrypt: %s\n", EPWMD_ERROR
, gcry_strerror(gcryerrno
));
565 if ((fd
= open(filename
, O_WRONLY
|O_CREAT
|O_TRUNC
, 0600)) == -1) {
568 p
= strrchr(filename
, '/');
570 log_write("%s: %s", p
, strerror(errno
));
571 send_to_client(client
, "ERR %03i %s: %s\n", EPWMD_ERROR
, p
, strerror(error
));
577 * xml_import() from command line.
581 write(fd
, &file_header
, sizeof(struct file_header_s
));
582 write(fd
, inbuf
, insize
);
591 gboolean
save_command(struct client_s
*client
, const gchar
*filename
, gchar
*key
)
596 guchar shakey
[gcrykeysize
];
599 gchar filebuf
[PATH_MAX
], *p
, *p2
;
600 gboolean reset_timeout
;
602 p
= get_key_file_string("default", "data_directory");
603 p2
= expand_homedir(p
);
605 snprintf(filebuf
, sizeof(filebuf
), "%s/%s", p2
, filename
);
608 if (stat(filebuf
, &st
) == 0 && client
->mtime
) {
609 if (client
->mtime
!= st
.st_mtime
) {
610 log_write("%s: %s", filename
, pwmd_strerror(EPWMD_FILE_MODIFIED
));
611 send_error(client
, EPWMD_FILE_MODIFIED
);
617 if (cache_get_key(client
->md5file
, shakey
) == FALSE
) {
618 send_error(client
, EPWMD_KEY
);
625 gcry_md_hash_buffer(GCRY_MD_SHA256
, shakey
, key
, strlen(key
));
626 memset(key
, 0, strlen(key
));
629 xmlDocDumpFormatMemory(client
->doc
, &xmlbuf
, &len
, 0);
631 if ((iter
= get_key_file_integer(client
->filename
, "iterations")) == -1)
634 if (do_xml_encrypt(client
, client
->gh
, filebuf
, xmlbuf
, len
, shakey
,
636 memset(shakey
, 0, sizeof(shakey
));
643 client
->mtime
= st
.st_mtime
;
646 memset(shakey
, 0, sizeof(shakey
));
648 if ((reset_timeout
= get_key_file_boolean(client
->filename
,
649 "cache_reset_timeout")) == TRUE
)
650 cache_reset_timeout(client
->md5file
);
655 if (cache_update_key(client
->md5file
, shakey
) == FALSE
) {
656 memset(shakey
, 0, sizeof(shakey
));
657 log_write("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror(EPWMD_MAX_SLOTS
));
658 send_error(client
, EPWMD_MAX_SLOTS
);
662 memset(shakey
, 0, sizeof(shakey
));
663 cache_reset_timeout(client
->md5file
);
667 static gboolean
contains_whitespace(const gchar
*str
)
669 const gchar
*p
= str
;
672 if (g_ascii_isspace(*p
) == TRUE
) {
681 * the 'reader' should be at the element of the document where the elements
682 * 'req' are to be created.
684 static gboolean
create_elements(struct client_s
*client
, xmlTextReaderPtr reader
,
685 gchar
**req
, gint novalue
)
691 r
= xmlTextReaderCurrentNode(reader
);
693 if (xmlTextReaderDepth(reader
) > 1)
696 for (i
= 0; req
[i
]; i
++) {
700 * Whitespace is allowed in values or attributes but not in element
703 if (req
[i
+1] && valid_xml_element((xmlChar
*)req
[i
]) == FALSE
) {
704 send_error(client
, EPWMD_INVALID_ELEMENT
);
709 * The value of the element tree.
711 if (!req
[i
+1] && !novalue
) {
713 * Prevent creating 'text' elements in the root of the account.
716 send_error(client
, EPWMD_ROOT_TEXT_ELEMENT
);
721 * FIXME ?? overwriting an element tree with a text element:
723 * STORE account element element2 value
724 * STORE account element value
726 * would remove the existing element tree. This may be a bug or
729 xmlNodeSetContent(r
, (xmlChar
*)req
[i
]);
733 if ((n
= find_node(r
, (xmlChar
*)req
[i
])) == NULL
) {
734 n
= xmlNewNode(NULL
, (xmlChar
*)req
[i
]);
735 r
= xmlAddChild(r
, n
);
740 if (!req
[i
+1] && novalue
)
748 * FIXME reuse reader handle
750 static gboolean
reset_reader(xmlDocPtr doc
, xmlTextReaderPtr
*reader
)
753 xmlFreeTextReader(*reader
);
757 if ((*reader
= xmlReaderWalker(doc
)) == NULL
)
763 static void delete_node(xmlNodePtr n
)
769 gboolean
delete_command(struct client_s
*client
, gchar
**req
)
773 xmlErrorPtr xml_error
;
775 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
776 xml_error
= xmlGetLastError();
777 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
778 send_error(client
, EPWMD_LIBXML_ERROR
);
782 if (find_account(client
->reader
, req
[0]) == FALSE
) {
783 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
787 n
= xmlTextReaderCurrentNode(client
->reader
);
790 * No sub-node defined. Remove the entire node (account).
799 * Remove matching sub-nodes starting from the root of the account.
801 while (req
[i
] && find_element(client
->reader
, req
[i
++], req
[i
] != NULL
) == TRUE
)
802 n
= xmlTextReaderCurrentNode(client
->reader
);
804 if (n
&& xmlStrcmp(n
->name
, (xmlChar
*)req
[i
-1]) == 0 &&
805 xmlTextReaderNodeType(client
->reader
) == XML_READER_TYPE_ELEMENT
)
808 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
815 gboolean
store_command(struct client_s
*client
, gchar
**req
)
817 xmlErrorPtr xml_error
;
820 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
821 xml_error
= xmlGetLastError();
822 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
823 send_error(client
, EPWMD_LIBXML_ERROR
);
828 send_error(client
, EPWMD_COMMAND_SYNTAX
);
832 if (find_account(client
->reader
, req
[0]) == FALSE
) {
833 if (contains_whitespace(req
[0]) == TRUE
) {
834 send_error(client
, EPWMD_INVALID_ELEMENT
);
838 if (new_account(client
->doc
, req
[0]) == FALSE
) {
839 send_error(client
, EPWMD_ERROR
);
846 xmlTextReaderNext(client
->reader
);
847 return create_elements(client
, client
->reader
, req
+1, 0);
850 static gboolean
do_get_command(struct client_s
*client
, xmlTextReaderPtr
*reader
,
851 gchar
**req
, xmlChar
**content
, gint quiet
, gint list
)
858 xmlErrorPtr xml_error
;
861 if (reset_reader(client
->doc
, reader
) == FALSE
) {
863 xml_error
= xmlGetLastError();
864 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
865 send_error(client
, EPWMD_LIBXML_ERROR
);
874 if (find_account(*reader
, (literal
) ? req
[0] + 1 : req
[0]) == FALSE
) {
876 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
881 * May be an account with only a "target" attribute.
884 if (find_elements(client
, *reader
, req
+ 1, (list
) ? 1 : quiet
) == FALSE
)
888 if ((n
= xmlTextReaderCurrentNode(*reader
)) == NULL
) {
890 xml_error
= xmlGetLastError();
891 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
892 send_error(client
, EPWMD_LIBXML_ERROR
);
899 * If the current element has a "target" attribute, the value of the
900 * attribute is an element path somewhere else in the document. Use this
901 * value and not any TEXT element value. The value may be another element
902 * with a target attribute and this function will recurse until a
903 * non-target attribute in the element is found.
905 if (!literal
&& (a
= xmlHasProp(n
, (xmlChar
*)"target")) != NULL
) {
906 if ((p
= xmlNodeGetContent(a
->children
)) != NULL
) {
907 if (strchr((gchar
*)p
, '\t') != NULL
) {
908 if ((nreq
= split_input_line((gchar
*)p
, "\t", 0)) == NULL
) {
912 send_error(client
, EPWMD_INVALID_ELEMENT
);
917 if ((nreq
= split_input_line((gchar
*)p
, " ", 0)) == NULL
) {
921 send_error(client
, EPWMD_INVALID_ELEMENT
);
927 ret
= do_get_command(client
, reader
, nreq
, content
, quiet
, list
);
933 switch (xmlTextReaderNext(*reader
)) {
936 xml_error
= xmlGetLastError();
937 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
938 send_error(client
, EPWMD_LIBXML_ERROR
);
944 send_error(client
, EPWMD_EMPTY_ELEMENT
);
950 switch (xmlTextReaderNodeType(*reader
)) {
951 case XML_READER_TYPE_END_ELEMENT
:
953 * May be an empty element after an ATTR DELETE target command.
956 case XML_READER_TYPE_TEXT
:
960 xml_error
= xmlGetLastError();
961 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
962 send_error(client
, EPWMD_LIBXML_ERROR
);
968 if (n
->children
&& !list
)
969 send_error(client
, EPWMD_TRAILING_ELEMENT
);
970 else if (!n
->children
&& !list
)
971 send_error(client
, EPWMD_INVALID_ELEMENT
);
976 if ((*content
= xmlNodeGetContent(n
)) == NULL
) {
978 send_error(client
, EPWMD_EMPTY_ELEMENT
);
986 * Retrieves the value associated with the element tree 'req'.
988 gboolean
get_command(struct client_s
*client
, xmlTextReaderPtr
*reader
,
989 gchar
**req
, gint quiet
)
991 xmlChar
*content
= NULL
;
993 if (do_get_command(client
, reader
, req
, &content
, quiet
, 0) == FALSE
)
998 send_error(client
, EPWMD_EMPTY_ELEMENT
);
1003 send_to_client(client
, "BEGIN %li\n%s\nOK \n", xmlStrlen(content
), content
);
1008 static gchar
*element_path_to_req(const gchar
*account
, xmlChar
*path
)
1017 for (n
= 0; *p
&& n
< 3; p
++) {
1022 if (strstr((gchar
*)p
, "text()") != NULL
)
1023 p
[xmlStrlen(p
) - 7] = 0;
1025 for (n
= 0; p
[n
]; n
++) {
1030 buf
= g_strdup_printf("%s\t%s", account
, p
);
1034 static gboolean
append_to_array(gchar
***array
, gint
*total
, const gchar
*str
)
1039 if ((a
= g_realloc(*array
, (t
+ 2) * sizeof(gchar
*))) == NULL
)
1042 a
[t
++] = g_strdup(str
);
1049 gboolean
list_command(struct client_s
*client
, gchar
*str
)
1053 gchar
**elements
= NULL
;
1054 gint pwmd_errno
= -1;
1057 xmlChar
*path
= NULL
;
1061 xmlTextReaderPtr r
= NULL
;
1062 gchar
**req
= NULL
, **nreq
;
1066 xmlErrorPtr xml_error
;
1069 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1070 xml_error
= xmlGetLastError();
1071 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1072 send_error(client
, EPWMD_LIBXML_ERROR
);
1076 if (strchr(p
, ' ') == NULL
) {
1078 if (list_accounts(client
->reader
, &dst
, &pwmd_errno
) == FALSE
) {
1079 send_error(client
, pwmd_errno
);
1083 send_to_client(client
, "BEGIN %i\n%s\nOK \n",
1084 g_utf8_strlen(dst
, -1), dst
);
1085 memset(dst
, 0, strlen(dst
));
1094 while (*p
&& isspace(*p
))
1100 if (strchr(p
, '\t') != NULL
) {
1101 if ((req
= split_input_line(p
, "\t", 0)) == NULL
) {
1102 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1106 if (find_account(client
->reader
, req
[0]) == FALSE
) {
1107 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1111 if (find_elements(client
, client
->reader
, req
+ 1, 0) == FALSE
) {
1116 depth
= xmlTextReaderDepth(client
->reader
);
1119 if (find_account(client
->reader
, p
) == FALSE
) {
1120 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1125 if ((n
= xmlTextReaderCurrentNode(client
->reader
)) == NULL
) {
1126 xml_error
= xmlGetLastError();
1127 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1128 send_error(client
, EPWMD_LIBXML_ERROR
);
1132 if ((a
= xmlHasProp(n
, (xmlChar
*)"target")) != NULL
) {
1133 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1134 send_error(client
, EPWMD_LIBXML_ERROR
);
1138 if ((content
= xmlNodeGetContent(a
->children
)) != NULL
) {
1139 if (find_account(client
->reader
, (gchar
*)content
) == FALSE
) {
1141 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1149 account
= (req
) ? g_strdup(req
[0]) : g_strdup(p
);
1154 while (xmlTextReaderNext(client
->reader
) == 1) {
1156 if ((n
= xmlTextReaderCurrentNode(client
->reader
)) == NULL
) {
1157 xml_error
= xmlGetLastError();
1158 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1159 send_error(client
, EPWMD_LIBXML_ERROR
);
1163 if (xmlTextReaderDepth(client
->reader
) == 1 &&
1164 xmlStrcmp(n
->name
, (xmlChar
*)"account") == 0 &&
1165 xmlTextReaderNodeType(client
->reader
) == XML_READER_TYPE_END_ELEMENT
)
1168 if (depth
&& depth
== xmlTextReaderDepth(client
->reader
) &&
1169 xmlTextReaderNodeType(client
->reader
) == XML_READER_TYPE_END_ELEMENT
)
1173 * If the current element has a "target" attribute, the value of the
1174 * attribute is an element path somewhere else in the document. Use this
1175 * value and not any TEXT element value.
1177 type
= xmlTextReaderNodeType(client
->reader
);
1178 a
= xmlHasProp(n
, (xmlChar
*)"target");
1180 if (type
== XML_READER_TYPE_ELEMENT
&& a
) {
1181 if ((content
= xmlNodeGetContent(a
->children
)) != NULL
) {
1182 path
= xmlGetNodePath(n
);
1184 if ((nreq
= split_input_line((gchar
*)content
, "\t", 0)) == NULL
) {
1186 g_strfreev(elements
);
1190 send_error(client
, EPWMD_INVALID_ELEMENT
);
1197 if ((ret
= do_get_command(client
, &r
, nreq
, &content
, 0, 1)) == TRUE
) {
1198 if (content
&& *content
) {
1199 line
= element_path_to_req(account
, path
);
1202 if (append_to_array(&elements
, &total
, line
) == FALSE
) {
1204 g_strfreev(elements
);
1207 memset(line
, 0, g_utf8_strlen(line
, -1));
1210 xmlFreeTextReader(r
);
1211 send_error(client
, EPWMD_ERROR
);
1215 memset(line
, 0, g_utf8_strlen(line
, -1));
1219 if (xmlTextReaderNext(client
->reader
) == 1) {
1220 if (xmlTextReaderNodeType(client
->reader
) !=
1221 XML_READER_TYPE_TEXT
) {
1223 xmlFreeTextReader(r
);
1231 xmlFreeTextReader(r
);
1237 if (type
== XML_READER_TYPE_TEXT
) {
1238 xmlChar
*np
= xmlGetNodePath(n
);
1240 line
= element_path_to_req(account
, np
);
1242 append_to_array(&elements
, &total
, line
);
1243 memset(line
, 0, g_utf8_strlen(line
, -1));
1249 send_error(client
, EPWMD_EMPTY_ELEMENT
);
1255 line
= g_strjoinv("\n", elements
);
1256 send_to_client(client
, "BEGIN %li\n%s\nOK \n",
1257 g_utf8_strlen(line
, -1), line
);
1258 g_strfreev(elements
);
1264 * The client->reader handle should be at the element in the document where
1265 * the attribute will be created or modified.
1267 static gboolean
add_attribute(struct client_s
*client
, const gchar
*name
, const gchar
*value
)
1271 xmlErrorPtr xml_error
;
1273 if ((n
= xmlTextReaderCurrentNode(client
->reader
)) == NULL
) {
1274 xml_error
= xmlGetLastError();
1275 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1276 send_error(client
, EPWMD_LIBXML_ERROR
);
1280 if ((a
= xmlHasProp(n
, (xmlChar
*)name
)) == NULL
)
1281 a
= xmlNewProp(n
, (xmlChar
*)name
, (xmlChar
*)value
);
1283 xmlNodeSetContent(a
->children
, (xmlChar
*)value
);
1289 * req[0] - element path
1291 static gboolean
attribute_list(struct client_s
*client
, gchar
**req
)
1293 gchar
**attrlist
= NULL
;
1295 gchar
**epath
= NULL
;
1299 xmlErrorPtr xml_error
;
1301 if (!req
|| !req
[0]) {
1302 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1306 if ((epath
= split_input_line(req
[0], "\t", 0)) == NULL
) {
1308 * The first argument may be only an account.
1310 if ((epath
= split_input_line(req
[0], " ", 0)) == NULL
) {
1311 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1316 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1317 xml_error
= xmlGetLastError();
1318 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1319 send_error(client
, EPWMD_LIBXML_ERROR
);
1323 if (find_account(client
->reader
, epath
[0]) == FALSE
) {
1324 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1329 if ((find_elements(client
, client
->reader
, epath
+1, 0)) == FALSE
)
1333 if ((n
= xmlTextReaderCurrentNode(client
->reader
)) == NULL
) {
1334 xml_error
= xmlGetLastError();
1335 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1336 send_error(client
, EPWMD_LIBXML_ERROR
);
1340 for (a
= n
->properties
; a
; a
= a
->next
) {
1341 if ((attrlist
= g_realloc(attrlist
, (i
+ 2) * sizeof(gchar
*))) == NULL
) {
1342 log_write("%s(%i): g_realloc() failed", __FILE__
, __LINE__
);
1343 send_error(client
, EPWMD_ERROR
);
1348 attrlist
[i
++] = g_strdup_printf("%s\t%s", (gchar
*)a
->name
, (gchar
*)an
->content
);
1353 send_error(client
, EPWMD_EMPTY_ELEMENT
);
1357 line
= g_strjoinv("\n", attrlist
);
1358 send_to_client(client
, "BEGIN %li\n%s\n", g_utf8_strlen(line
, -1), line
);
1361 g_strfreev(attrlist
);
1369 * req[0] - attribute
1370 * req[1] - element path
1372 static gboolean
attribute_delete(struct client_s
*client
, gchar
**req
)
1376 gchar
**epath
= NULL
;
1377 xmlErrorPtr xml_error
;
1379 if (!req
|| !req
[0] || !req
[1]) {
1380 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1384 if ((epath
= split_input_line(req
[1], "\t", 0)) == NULL
) {
1386 * The first argument may be only an account.
1388 if ((epath
= split_input_line(req
[1], " ", 0)) == NULL
) {
1389 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1395 * Don't remove the NAME attribute for the account element.
1397 if (!epath
[1] && g_ascii_strcasecmp(req
[0], "NAME") == 0) {
1398 send_error(client
, EPWMD_ATTR_SYNTAX
);
1402 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1403 xml_error
= xmlGetLastError();
1404 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1405 send_error(client
, EPWMD_LIBXML_ERROR
);
1409 if (find_account(client
->reader
, epath
[0]) == FALSE
) {
1410 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1415 if ((find_elements(client
, client
->reader
, epath
+1, 0)) == FALSE
)
1419 if ((n
= xmlTextReaderCurrentNode(client
->reader
)) == NULL
) {
1420 xml_error
= xmlGetLastError();
1421 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1422 send_error(client
, EPWMD_LIBXML_ERROR
);
1426 if ((a
= xmlHasProp(n
, (xmlChar
*)req
[0])) == NULL
) {
1427 send_error(client
, EPWMD_ATTR_NOT_FOUND
);
1431 if (xmlRemoveProp(a
) == -1) {
1432 xml_error
= xmlGetLastError();
1433 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1434 send_error(client
, EPWMD_LIBXML_ERROR
);
1446 * req[0] - source element path
1447 * req[1] - destination element path
1449 static gboolean
target_attribute(struct client_s
*client
, gchar
**req
)
1451 gchar
**src
, **dst
, *line
;
1452 xmlErrorPtr xml_error
;
1454 if (!req
|| !req
[0] || !req
[1]) {
1455 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1459 if ((src
= split_input_line(req
[0], "\t", 0)) == NULL
) {
1461 * The first argument may be only an account.
1463 if ((src
= split_input_line(req
[0], " ", 0)) == NULL
) {
1464 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1469 if ((dst
= split_input_line(req
[1], "\t", 0)) == NULL
) {
1471 * The first argument may be only an account.
1473 if ((dst
= split_input_line(req
[1], " ", 0)) == NULL
) {
1474 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1481 * Prevent an element tree pointing to only and account. Accounts require
1482 * at least one element. Accounts pointing to accounts are allowed.
1484 if ((!src
[1] && dst
[1]) || (!dst
[1] && src
[1])) {
1485 send_error(client
, EPWMD_ATTR_SYNTAX
);
1491 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1492 xml_error
= xmlGetLastError();
1493 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1494 send_error(client
, EPWMD_LIBXML_ERROR
);
1501 * Make sure the destination element path exists.
1503 if (find_account(client
->reader
, dst
[0]) == FALSE
) {
1504 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1511 if (find_elements(client
, client
->reader
, dst
+1, 0) == FALSE
) {
1518 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1519 xml_error
= xmlGetLastError();
1520 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1521 send_error(client
, EPWMD_LIBXML_ERROR
);
1528 * If the source element tree doesn't exist, create it.
1530 if (find_account(client
->reader
, src
[0]) == FALSE
) {
1531 if (new_account(client
->doc
, src
[0]) == FALSE
) {
1532 xml_error
= xmlGetLastError();
1533 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1534 send_error(client
, EPWMD_LIBXML_ERROR
);
1540 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1541 xml_error
= xmlGetLastError();
1542 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1543 send_error(client
, EPWMD_LIBXML_ERROR
);
1549 if (find_account(client
->reader
, src
[0]) == FALSE
) {
1550 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1558 if (find_elements(client
, client
->reader
, src
+1, 1) == FALSE
) {
1559 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1560 xml_error
= xmlGetLastError();
1561 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1562 send_error(client
, EPWMD_LIBXML_ERROR
);
1568 if (find_account(client
->reader
, src
[0]) == FALSE
) {
1569 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1575 xmlTextReaderNext(client
->reader
);
1577 if (create_elements(client
, client
->reader
, src
+1, 1) == FALSE
) {
1583 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1584 xml_error
= xmlGetLastError();
1585 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1586 send_error(client
, EPWMD_LIBXML_ERROR
);
1592 if (find_account(client
->reader
, src
[0]) == FALSE
) {
1593 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1599 if (find_elements(client
, client
->reader
, src
+1, 0) == FALSE
) {
1607 line
= g_strjoinv("\t", dst
);
1609 if (add_attribute(client
, "target", line
) == FALSE
) {
1627 * req[0] - account name
1630 static gboolean
name_attribute(struct client_s
*client
, gchar
**req
)
1632 xmlErrorPtr xml_error
;
1634 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1635 xml_error
= xmlGetLastError();
1636 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1637 send_error(client
, EPWMD_LIBXML_ERROR
);
1641 if (find_account(client
->reader
, req
[0]) == FALSE
) {
1642 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1646 if (strcmp(req
[0], req
[1]) == 0)
1649 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1650 xml_error
= xmlGetLastError();
1651 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1652 send_error(client
, EPWMD_LIBXML_ERROR
);
1657 * Will not overwrite an existing account.
1659 if (find_account(client
->reader
, req
[1]) == TRUE
) {
1660 send_error(client
, EPWMD_ACCOUNT_EXISTS
);
1664 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1665 xml_error
= xmlGetLastError();
1666 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1667 send_error(client
, EPWMD_LIBXML_ERROR
);
1671 if (find_account(client
->reader
, req
[0]) == FALSE
) {
1672 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1677 * Whitespace not allowed in account names.
1679 if (contains_whitespace(req
[1]) == TRUE
) {
1680 send_error(client
, EPWMD_ATTR_SYNTAX
);
1684 return add_attribute(client
, "name", req
[1]);
1688 * req[0] - attribute
1689 * req[1] - element path
1691 * If the element has a "target" attribute it won't be "followed".
1693 static gboolean
attribute_get(struct client_s
*client
, gchar
**req
)
1697 gchar
**nreq
= NULL
;
1698 xmlErrorPtr xml_error
;
1700 if (!req
|| !req
[0] || !req
[1]) {
1701 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1705 if (strchr(req
[1], '\t')) {
1706 if ((nreq
= split_input_line(req
[1], "\t", 0)) == NULL
) {
1707 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1712 if ((nreq
= split_input_line(req
[1], " ", 0)) == NULL
) {
1713 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1718 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1719 xml_error
= xmlGetLastError();
1720 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1722 send_error(client
, EPWMD_LIBXML_ERROR
);
1726 if (find_account(client
->reader
, nreq
[0]) == FALSE
) {
1728 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1733 if (find_elements(client
, client
->reader
, nreq
+ 1, 0) == FALSE
) {
1741 if ((n
= xmlTextReaderCurrentNode(client
->reader
)) == NULL
) {
1742 xml_error
= xmlGetLastError();
1743 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1744 send_error(client
, EPWMD_LIBXML_ERROR
);
1748 if ((a
= xmlGetProp(n
, (xmlChar
*)req
[0])) == NULL
) {
1749 send_error(client
, EPWMD_ATTR_NOT_FOUND
);
1753 send_to_client(client
, "BEGIN %li\n%s\n", xmlStrlen(a
), a
);
1759 * req[0] - attribute
1760 * req[1] - element path
1763 static gboolean
attribute_set(struct client_s
*client
, gchar
**req
)
1765 gchar
**epath
= NULL
;
1766 xmlErrorPtr xml_error
;
1768 if (!req
|| !req
[0] || !req
[1] || !req
[2]) {
1769 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1774 * Reserved attribute names.
1776 if (strcmp(req
[0], "name") == 0) {
1778 * Only reserved for the account element. Not the rest of the
1781 if (strchr(req
[1], '\t') == NULL
)
1782 return name_attribute(client
, req
+ 1);
1784 else if (strcmp(req
[0], "target") == 0)
1785 return target_attribute(client
, req
+ 1);
1787 if ((epath
= split_input_line(req
[1], "\t", 0)) == NULL
) {
1789 * The first argument may be only an account.
1791 if ((epath
= split_input_line(req
[1], " ", 0)) == NULL
) {
1792 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1797 if (reset_reader(client
->doc
, &client
->reader
) == FALSE
) {
1798 xml_error
= xmlGetLastError();
1799 log_write("%s(%i): %s", __FILE__
, __LINE__
, xml_error
->message
);
1800 send_error(client
, EPWMD_LIBXML_ERROR
);
1804 if (find_account(client
->reader
, epath
[0]) == FALSE
) {
1805 send_error(client
, EPWMD_ELEMENT_NOT_FOUND
);
1810 if ((find_elements(client
, client
->reader
, epath
+1, 0)) == FALSE
)
1815 return add_attribute(client
, req
[0], req
[2]);
1823 * req[1] - attribute name or element path if command is LIST
1824 * req[2] - element path
1825 * req[2] - element path or value
1827 gboolean
attr_command(struct client_s
*client
, gchar
**req
)
1829 if (!req
|| !req
[0] || !req
[1]) {
1830 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1834 if (g_ascii_strcasecmp(req
[0], "SET") == 0)
1835 return attribute_set(client
, req
+1);
1836 if (g_ascii_strcasecmp(req
[0], "GET") == 0)
1837 return attribute_get(client
, req
+1);
1838 else if (g_ascii_strcasecmp(req
[0], "DELETE") == 0)
1839 return attribute_delete(client
, req
+1);
1840 else if (g_ascii_strcasecmp(req
[0], "LIST") == 0)
1841 return attribute_list(client
, req
+1);
1843 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1848 gboolean
cache_clear(const guchar
*md5filename
, gint which
)
1854 for (p
= shm_data
, len
= 0; len
<= cache_size
;) {
1855 memcpy(&f
, p
, sizeof(file_cache_t
));
1858 memset(&f
, 0, sizeof(file_cache_t
));
1859 memcpy(p
, &f
, sizeof(file_cache_t
));
1861 else if (f
.used
== TRUE
&& which
== 1) {
1862 if (memcmp(&f
.filename
, md5filename
, sizeof(f
.filename
)) == 0) {
1863 memset(&f
, 0, sizeof(file_cache_t
));
1864 memcpy(p
, &f
, sizeof(file_cache_t
));
1869 p
+= sizeof(file_cache_t
);
1870 len
+= sizeof(file_cache_t
);
1872 if (len
+ sizeof(file_cache_t
) > cache_size
)
1876 return (which
== 2) ? TRUE
: FALSE
;
1879 gboolean
cache_iscached(const guchar
*md5filename
)
1885 for (p
= shm_data
, len
= 0; len
<= cache_size
;) {
1886 memcpy(&f
, p
, sizeof(file_cache_t
));
1888 if (f
.used
== TRUE
) {
1889 if (memcmp(&f
.filename
, md5filename
, sizeof(f
.filename
)) == 0)
1890 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
)
1903 gboolean
cache_reset(const guchar
*md5filename
, gint which
)
1908 guchar md5file
[sizeof(f
.filename
)];
1911 for (p
= shm_data
, len
= 0; len
<= cache_size
;) {
1912 memcpy(&f
, p
, sizeof(file_cache_t
));
1913 timeout
= f
.timeout
;
1916 if (f
.used
== TRUE
) {
1917 memcpy(&md5file
, f
.filename
, sizeof(md5file
));
1918 memset(&f
, 0, sizeof(file_cache_t
));
1919 memcpy(&f
.filename
, &md5file
, sizeof(md5file
));
1920 f
.timeout
= f
.when
= timeout
;
1922 memcpy(p
, &f
, sizeof(file_cache_t
));
1925 else if (f
.used
== TRUE
&& which
== 1) {
1926 if (memcmp(&f
.filename
, md5filename
, sizeof(f
.filename
)) == 0) {
1927 memcpy(&md5file
, f
.filename
, sizeof(md5file
));
1928 memset(&f
, 0, sizeof(file_cache_t
));
1929 memcpy(&f
.filename
, &md5file
, sizeof(md5file
));
1930 f
.timeout
= f
.when
= timeout
;
1932 memcpy(p
, &f
, sizeof(file_cache_t
));
1937 p
+= sizeof(file_cache_t
);
1938 len
+= sizeof(file_cache_t
);
1940 if (len
+ sizeof(file_cache_t
) > cache_size
)
1944 return (which
== 2) ? TRUE
: FALSE
;
1947 static gboolean
file_exists(const gchar
*filename
)
1950 gchar filebuf
[PATH_MAX
], *p
, *p2
;
1952 p
= get_key_file_string("default", "data_directory");
1953 p2
= expand_homedir(p
);
1955 snprintf(filebuf
, sizeof(filebuf
), "%s/%s", p2
, filename
);
1958 if (access(filebuf
, R_OK
) == -1)
1963 if (st
.st_size
== 0)
1969 gboolean
cache_command(struct client_s
*client
, gchar
**req
)
1975 if (g_ascii_strcasecmp(req
[0], "CLEAR") == 0) {
1977 send_error(client
, EPWMD_COMMAND_SYNTAX
);
1981 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[1], strlen(req
[1]));
1983 if (cache_clear(md5file
, 1) == FALSE
) {
1984 send_error(client
, EPWMD_CACHE_NOT_FOUND
);
1990 else if (g_ascii_strcasecmp(req
[0], "CLEARALL") == 0) {
1991 cache_clear(client
->md5file
, 2);
1994 if (g_ascii_strcasecmp(req
[0], "RESET") == 0) {
1996 send_error(client
, EPWMD_COMMAND_SYNTAX
);
2000 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[1], strlen(req
[1]));
2002 if (cache_reset(md5file
, 1) == FALSE
) {
2003 send_error(client
, EPWMD_CACHE_NOT_FOUND
);
2009 else if (g_ascii_strcasecmp(req
[0], "RESETALL") == 0) {
2010 cache_reset(client
->md5file
, 2);
2013 else if (g_ascii_strcasecmp(req
[0], "ISCACHED") == 0) {
2015 send_error(client
, EPWMD_COMMAND_SYNTAX
);
2019 if (file_exists(req
[1]) == FALSE
) {
2020 send_error(client
, EPWMD_FILE_NOT_FOUND
);
2024 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[1], strlen(req
[1]));
2026 if (cache_iscached(md5file
) == FALSE
) {
2027 send_error(client
, EPWMD_CACHE_NOT_FOUND
);
2033 else if (g_ascii_strcasecmp(req
[0], "TIMEOUT") == 0) {
2034 if (!req
[1] || !req
[2]) {
2035 send_error(client
, EPWMD_COMMAND_SYNTAX
);
2040 timeout
= strtol(req
[1], &p
, 10);
2042 if (errno
!= 0 || *p
!= 0) {
2043 send_error(client
, EPWMD_COMMAND_SYNTAX
);
2047 if (file_exists(req
[2]) == FALSE
) {
2048 send_error(client
, EPWMD_FILE_NOT_FOUND
);
2052 gcry_md_hash_buffer(GCRY_MD_MD5
, md5file
, req
[2], strlen(req
[2]));
2054 if (cache_set_timeout(md5file
, timeout
) == FALSE
) {
2055 send_error(client
, EPWMD_CACHE_NOT_FOUND
);
2062 send_error(client
, EPWMD_COMMAND_SYNTAX
);
2067 gboolean
help_command(struct client_s
*client
, const gchar
*what
)
2071 if (!what
|| !*what
)
2073 "NFO Try 'HELP COMMAND' for command help\n"
2074 "NFO OPEN LIST GET STORE DELETE ATTR CACHE SAVE DUMP QUIT\n";
2075 else if (g_ascii_strcasecmp(what
, "GET") == 0)
2077 "NFO syntax: GET account <TAB> element [<TAB> element ...]\n"
2078 "NFO <account> is the account to work on and <element>\n"
2079 "NFO is the element wanted.\n"
2081 "NFO Example: GET isp <TAB> imap <TAB> port\n"
2082 "NFO GET isp <TAB> username\n";
2083 else if (g_ascii_strcasecmp(what
, "QUIT") == 0)
2085 "NFO syntax: QUIT\n"
2086 "NFO close the connection\n";
2087 else if (g_ascii_strcasecmp(what
, "DELETE") == 0)
2089 "NFO syntax: DELETE account <TAB> element [<TAB> element ...]\n";
2090 else if (g_ascii_strcasecmp(what
, "STORE") == 0)
2092 "NFO syntax: STORE account <TAB> element [<TAB> element ...] <TAB> value\n"
2093 "NFO <account> is the account to work on and <element>\n"
2094 "NFO is the element to create or modify\n"
2096 "NFO Example: STORE isp <TAB> imap <TAB> port <TAB> 993\n"
2097 "NFO STORE isp <TAB> username <TAB> someuser\n";
2098 else if (g_ascii_strcasecmp(what
, "OPEN") == 0)
2100 "NFO syntax: OPEN <filename> [<key>]\n"
2101 "NFO opens a (new) file\n";
2102 else if (g_ascii_strcasecmp(what
, "LIST") == 0)
2104 "NFO syntax: LIST [account]\n"
2105 "NFO shows available accounts or account elements\n";
2106 else if (g_ascii_strcasecmp(what
, "ATTR") == 0)
2108 "NFO syntax: ATTR SET|GET|DELETE|LIST [ATTRIBUTE] arg1 [arg2]\n"
2109 "NFO ATTR SET name account value\n"
2110 "NFO ATTR SET target account[<TAB>element[...]] account[<TAB>element[...]\n"
2111 "NFO ATTR SET attribute account[<TAB>element[...]] attribute_value\n"
2112 "NFO ATTR DELETE attribute account[<TAB>element[...]]\n"
2113 "NFO ATTR GET attribute account[<TAB>element[...]]\n"
2114 "NFO ATTR LIST account[<TAB>element[...]]\n";
2115 else if (g_ascii_strcasecmp(what
, "SAVE") == 0)
2117 "NFO syntax: SAVE [<key>]\n"
2118 "NFO save any changes to the opened file using <key>\n";
2119 else if (g_ascii_strcasecmp(what
, "CACHE") == 0)
2121 "NFO syntax: CACHE [ISCACHED <filename>] |\n"
2122 "NFO [RESETALL] | [RESET <filename>] |\n"
2123 "NFO [CLEARALL] | [CLEAR <filename>] |\n"
2124 "NFO [TIMEOUT <seconds> <filename>]\n";
2125 else if (g_ascii_strcasecmp(what
, "DUMP") == 0)
2127 "NFO syntax: DUMP\n"
2128 "NFO shows the in memory XML document\n";
2130 send_error(client
, EPWMD_COMMAND_SYNTAX
);
2134 send_to_client(client
, "%sOK \n", line
);
2138 gboolean
dump_command(struct client_s
*client
)
2143 xmlDocDumpFormatMemory(client
->doc
, &xml
, &len
, 1);
2144 send_to_client(client
, "BEGIN %li\n%s", len
, xml
);