6 #include <libxml/tree.h>
7 #include <libxml/parser.h>
8 #include <libxml/xmlreader.h>
11 #include <sys/socket.h>
12 #include <netinet/in.h>
24 xmlTextReaderPtr reader
;
38 void catchsig(int sig
)
48 xmlNodePtr
find_node(xmlNodePtr root
, xmlChar
*name
)
52 for (n
= root
->children
; n
; n
= n
->next
) {
53 if (strcmp((char *)name
, (char *)n
->name
) == 0)
60 xmlNodePtr
create_doc(xmlDocPtr
*doc
, const char *root
)
62 xmlDocPtr d
= xmlNewDoc((xmlChar
*)"1.0");
63 xmlNodePtr n
= xmlNewNode(NULL
, (xmlChar
*)root
);
66 xmlDocSetRootElement(d
, n
);
70 int add_node(xmlNodePtr root
, char **exp
)
73 xmlNodePtr n
= NULL
, l
= root
;
75 for (p
= exp
; *p
; p
++) {
76 n
= find_node(l
, (xmlChar
*)*p
);
78 // non-matching element.
81 xmlNodeAddContent(n
, (xmlChar
*)*p
);
85 xmlNewChild(l
, NULL
, (xmlChar
*)*p
, NULL
);
86 l
->next
->type
= XML_ELEMENT_NODE
;
98 xmlNodeAddContent(n
, (xmlChar
*)p
);
103 warnx("add: parent node \"%s\" does not exist", p
);
107 xmlNewChild(n
, NULL
, (xmlChar
*)p
, (xmlChar
*)"value");
115 printf("Usage: %s [-h]\n", pn
);
119 int find_account(xmlTextReaderPtr reader
, xmlChar
*acct
)
124 while (xmlTextReaderRead(reader
) == 1) {
125 if ((n
= xmlTextReaderCurrentNode(reader
)) == NULL
)
129 * "name" is the element that holds the account name. It would be nice
130 * to have an element the is the account name but I wouldn't know how
131 * to do it with the DTD.
133 if (xmlTextReaderDepth(reader
) == 1 &&
134 xmlStrcmp(n
->name
, (xmlChar
*)"name") &&
135 xmlTextReaderNodeType(reader
) == XML_READER_TYPE_ELEMENT
) {
137 if (xmlTextReaderNext(reader
) != 1)
139 type
= xmlTextReaderNodeType(reader
);
140 } while (type
!= -1 && type
!= XML_READER_TYPE_TEXT
);
142 if ((n
= xmlTextReaderCurrentNode(reader
)) == NULL
)
145 if (xmlStrcmp(n
->content
, acct
) == 0)
153 int find_element(xmlTextReaderPtr reader
, xmlChar
*e
, int more
)
158 while (xmlTextReaderRead(reader
) == 1) {
159 if ((n
= xmlTextReaderCurrentNode(reader
)) == NULL
)
162 if (xmlStrcmp(n
->name
, e
) == 0 &&
163 xmlTextReaderNodeType(reader
) == XML_READER_TYPE_ELEMENT
) {
168 * FIXME account/service without details (account/service/host).
171 if (xmlTextReaderNext(reader
) != 1)
173 type
= xmlTextReaderNodeType(reader
);
174 } while (type
!= -1 && type
!= XML_READER_TYPE_TEXT
);
175 return (type
== XML_READER_TYPE_TEXT
) ? 0 : 1;
182 void send_to_client(int fd
, char *fmt
, ...)
188 vasprintf(&buf
, fmt
, ap
);
191 if (send(fd
, buf
, strlen(buf
), 0) == -1)
202 if (access(argv
[optind
], R_OK
) != 0 && errno
== ENOENT
) {
203 root
= create_doc(&doc
, "accounts");
206 err(EXIT_FAILURE
, "%s", argv
[optind
]);
209 if ((doc
= xmlReadFile(argv
[optind
++], NULL
, 0)) == NULL
)
210 errx(EXIT_FAILURE
, "parse error");
212 root
= doc
->children
;
215 if ((reader
= xmlReaderWalker(doc
)) == NULL
)
216 errx(EXIT_FAILURE
, "xmlReaderWalker() failed");
220 while ((p
= strsep(&s
, "/")) != NULL
) {
221 exp
= realloc(exp
, (i
+ 2) * sizeof(xmlChar
*));
222 exp
[i
++] = xmlStrdup((xmlChar
*)p
);
227 errx(EXIT_FAILURE
, "account expression parse error");
231 if (find_account(reader
, exp
[i
++]))
232 errx(EXIT_FAILURE
, "account not found");
235 * We are at the position in the document where the account was found.
236 * Search through the account for the wanted elements.
238 for (; exp
[i
]; i
++) {
241 if (find_element(reader
, exp
[i
], exp
[i
+1] != NULL
))
242 errx(EXIT_FAILURE
, "could not find element %s", exp
[i
]);
245 * We are at the end of the element list. Save the result.
248 n
= xmlTextReaderCurrentNode(reader
);
249 result
= xmlStrdup(n
->content
);
254 for (i
= 0; exp
[i
]; i
++)
260 xmlFreeTextReader(reader
);
267 int parse_account(struct client_s
*cl
, char *str
)
272 while ((p
= strsep(&str
, "/")) != NULL
) {
273 cl
->req
= realloc(cl
->req
, (i
+ 2) * sizeof(xmlChar
*));
274 cl
->req
[i
++] = xmlStrdup((xmlChar
*)p
);
283 if (find_account(cl
->reader
, cl
->req
[i
++])) {
284 send_to_client(cl
->fd
, "000 account \"%s\" not found\n", cl
->req
[0]);
289 * We are at the position in the document where the account was found.
290 * Search through the account for the wanted elements.
292 for (; cl
->req
[i
]; i
++) {
295 if (find_element(cl
->reader
, cl
->req
[i
], cl
->req
[i
+1] != NULL
)) {
296 send_to_client(cl
->fd
, "could not find element \"%s\"",
302 * We are at the end of the element list. Save the result.
305 n
= xmlTextReaderCurrentNode(cl
->reader
);
306 send_to_client(cl
->fd
, "%s\n", n
->content
);
313 void client_help(int fd
, const char *what
)
319 "000 Try 'help topic' for details\n"
320 "000 auth get quit\n";
321 else if (strcasecmp(what
, "get") == 0)
323 "000 syntax: get account[/element[/...]]\n"
324 "000 <account> is the account to work on and <element>\n"
325 "000 is the account elements wanted.\n"
327 "000 Example: get isp/imap/port\n"
328 "000 get isp/username\n";
329 else if (strcasecmp(what
, "quit") == 0)
332 "000 close the connection\n";
333 else if (strcasecmp(what
, "auth") == 0)
335 "000 syntax: auth username password\n";
337 line
= "000 unknown command\n";
339 send_to_client(fd
, line
);
342 char *skip_space(char *str
)
344 while (isspace(*str
))
350 int input_parser(int rfd
, char *str
, char **dst
)
354 if (strcasecmp(str
, "quit") == 0)
356 if (strncasecmp(str
, "help", 4) == 0) {
361 else if (strncasecmp(str
, "get", 3) == 0) {
367 else if (strncasecmp(str
, "auth", 4) == 0) {
378 * The filename will be username.xml.
380 int authenticate_client(struct client_s
*cl
, char *str
)
382 char *user
= NULL
, *pass
= NULL
;
383 char buf
[FILENAME_MAX
];
385 if ((user
= strsep(&str
, " ")) == NULL
)
389 snprintf(buf
, sizeof(buf
), "%s.xml", user
);
392 if (access(argv[optind], R_OK) != 0 && errno == ENOENT) {
393 root = create_doc(&doc, "accounts");
396 err(EXIT_FAILURE, "%s", argv[optind]);
399 if ((cl
->doc
= xmlReadFile(buf
, NULL
, 0)) == NULL
) {
400 send_to_client(cl
->fd
, "000 error while parsing XML\n");
404 if ((cl
->reader
= xmlReaderWalker(cl
->doc
)) == NULL
) {
405 send_to_client(cl
->fd
, "xmlReaderWalker() failed");
409 cl
->filename
= strdup(buf
);
410 cl
->state
= STATE_AUTH
;
415 * Called every time a connection is made.
421 struct client_s
*cl
= calloc(1, sizeof(struct client_s
));
423 cl
->state
= STATE_CONNECTED
;
425 send_to_client(rfd
, "000 Type help for available commands\n");
429 char buf
[LINE_MAX
] = {0};
434 FD_SET(cl
->fd
, &rfds
);
436 FD_SET(cl
->fd
, &wfds
);
441 switch (select(cl
->fd
+ 1, &rfds
, &wfds
, NULL
, NULL
)) {
452 if (FD_ISSET(cl
->fd
, &rfds
)) {
453 int len
= recv(cl
->fd
, buf
, sizeof(buf
), 0);
464 buf
[strlen(buf
) - 1] = 0;
466 switch (input_parser(cl
->fd
, buf
, &dst
)) {
470 if (cl
->state
!= STATE_AUTH
) {
471 send_to_client(cl
->fd
, "000 not authenticated\n");
475 if (parse_account(cl
, dst
)) {
476 send_to_client(cl
->fd
, "000 parse error\n");
481 if (authenticate_client(cl
, dst
))
484 send_to_client(cl
->fd
, "000 authenticated\n");
497 int main(int argc
, char *argv
[])
499 xmlDocPtr doc
= NULL
;
500 xmlTextReaderPtr reader
= NULL
;
503 xmlChar
**exp
= NULL
;
506 xmlChar
*result
= NULL
;
508 struct sockaddr_in laddr
, raddr
;
512 while ((opt
= getopt(argc
, argv
, "h")) != EOF
) {
519 if ((sfd
= socket(PF_INET
, SOCK_STREAM
, 0)) == -1)
520 err(EXIT_FAILURE
, "socket()");
522 if (setsockopt(sfd
, SOL_SOCKET
, SO_REUSEADDR
, &yes
, sizeof(int)) == -1)
523 err(EXIT_FAILURE
, "setsockopt()");
525 laddr
.sin_family
= AF_INET
;
526 laddr
.sin_port
= htons(5555);
527 laddr
.sin_addr
.s_addr
= INADDR_ANY
;
528 memset(&(laddr
.sin_zero
), 0, 8);
530 if (bind(sfd
, (struct sockaddr
*)&laddr
, sizeof(struct sockaddr
)) == -1)
531 err(EXIT_FAILURE
, "bind()");
533 if (listen(sfd
, 10) == -1)
534 err(EXIT_FAILURE
, "listen()");
536 signal(SIGCHLD
, catchsig
);
539 slen
= sizeof(struct sockaddr_in
);
541 if ((rfd
= accept(sfd
, (struct sockaddr_in
*)&raddr
, &slen
)) == -1) {