Volume breaks output format, removed for now.
[shell-fm.git] / source / xmlrpc.c
bloba175bce11b2695e3dc193e7ed714a44bd6a22907
1 /*
2 Copyright (C) 2006 by Jonas Kramer
3 Published under the terms of the GNU General Public License (GPL).
4 */
6 #include <string.h>
7 #include <stdarg.h>
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include <stdint.h>
11 #include <assert.h>
13 #include "md5.h"
14 #include "settings.h"
15 #include "http.h"
17 extern void purge(char **);
19 static void append(char **, unsigned *, const char *);
20 static void sparam(char **, unsigned *, const char *);
21 static void aparam(char **, unsigned *, const char **);
22 char * xmlize(const char *);
24 int xmlrpc(const char * method, const char * fmt, ...) {
25 unsigned size = 1024, narg, x;
26 const unsigned char * md5;
27 va_list argv;
28 int result = 0;
30 char
31 * xml = malloc(size),
32 ** resp, * url = "http://ws.audioscrobbler.com/1.0/rw/xmlrpc.php",
33 md5hex[32 + 1] = { 0 }, tmp[32 + 8 + 1] = { 0 };
35 assert(xml != NULL);
37 const char
38 * challenge = "Shell.FM",
39 * xmlhead =
40 "<?xml version=\"1.0\"?>\n"
41 "<methodCall>\n"
42 "\t<methodName>%s</methodName>\n"
43 "\t<params>\n";
46 /* generate password/challenge hash */
47 snprintf(tmp, sizeof(tmp), "%s%s", value(& rc, "password"), challenge);
48 md5 = MD5((unsigned char *) tmp, sizeof(tmp) - 1);
49 for(x = 0; x < 16; ++x)
50 sprintf(2 * x + md5hex, "%02x", md5[x]);
52 va_start(argv, fmt);
53 memset(xml, (char) 0, size);
55 snprintf(xml, size, xmlhead, method);
57 sparam(& xml, & size, value(& rc, "username"));
58 sparam(& xml, & size, challenge);
59 sparam(& xml, & size, md5hex);
61 for(narg = 0; narg < strlen(fmt); ++narg) {
62 const char * string, ** array;
64 switch(fmt[narg]) {
65 case 's': /* string */
66 string = va_arg(argv, const char *);
67 sparam(& xml, & size, string);
68 break;
70 case 'a': /* array */
71 array = va_arg(argv, const char **);
72 aparam(& xml, & size, array);
73 break;
77 append(& xml, & size, "\t</params>\n</methodCall>\n");
79 if((resp = fetch(url, NULL, xml, "text/xml")) != NULL) {
80 for(x = 0; resp[x]; ++x) {
81 if(strstr(resp[x], ">OK<") != NULL)
82 result = !0;
85 purge(resp);
88 free(xml);
90 return result;
94 static void append(char ** string, unsigned * size, const char * appendix) {
95 if(string && size && appendix) {
96 char * copy;
98 * size = strlen(* string) + strlen(appendix) + 1;
99 copy = realloc(* string, * size);
101 assert(copy != NULL);
103 if(!copy)
104 fputs("Out of memory!\n", stderr);
105 else {
106 strcat(copy, appendix);
107 copy[(* size) - 1] = 0;
108 * string = copy;
114 static void sparam(char ** xml, unsigned * size, const char * param) {
115 if(xml && size && param) {
116 char * encoded = xmlize(param);
117 append(xml, size, "\t\t<param><value><string>");
118 append(xml, size, encoded);
119 append(xml, size, "</string></value></param>\n");
120 free(encoded);
125 static void aparam(char ** xml, unsigned * size, const char ** param) {
126 if(xml && size) {
127 unsigned n;
129 append(xml, size, "\t\t<param><value><array><data>");
131 for(n = 0; param && param[n] != NULL; ++n) {
132 char * encoded = xmlize(param[n]);
133 append(xml, size, "<value><string>");
134 append(xml, size, encoded);
135 append(xml, size, "</string></value>");
136 free(encoded);
139 append(xml, size, "</data></array></value></param>\n");
143 char * xmlize(const char * orig) {
144 register unsigned i = 0, x = 0;
145 char * encoded = calloc((strlen(orig) * 6) + 1, sizeof(char));
147 assert(encoded != NULL);
149 while(i < strlen(orig)) {
150 if(strchr("&<>'\"", orig[i])) {
151 snprintf(
152 encoded + x,
153 strlen(orig) * 6 - strlen(encoded) + 1,
154 "&#x%02X;",
155 (uint8_t) orig[i]
157 x += 6;
159 else {
160 encoded[x++] = orig[i];
162 ++i;
165 return encoded;