forked from yanhan/powaur
/
json.c
175 lines (146 loc) · 4.01 KB
/
json.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#include <limits.h>
#include <string.h>
#include <yajl/yajl_parse.h>
#include "curl.h"
#include "environment.h"
#include "error.h"
#include "handle.h"
#include "json.h"
#include "powaur.h"
#include "query.h"
#include "util.h"
static yajl_handle yajl_init(void)
{
/* Reset the json_ctx */
pwhandle->json_ctx->pkglist = NULL;
pwhandle->json_ctx->curpkg = NULL;
pwhandle->json_ctx->jsondepth = 0;
yajl_handle yajl_hand = yajl_alloc(yajl_cbs, NULL, pwhandle->json_ctx);
if (!yajl_hand) {
die_errno(PW_ERR_MEMORY);
}
return yajl_hand;
}
/* Issues a query to AUR.
* @param pkgname package to query
* @param type type of query: info, search, msearch
* returns an alpm_list_t * of packages if everything is ok,
* otherwise, returns NULL.
*/
alpm_list_t *query_aur(CURL *curl, const char *searchstr, enum aurquery_t query_type)
{
int ret = 0;
yajl_handle hand;
char url[PATH_MAX];
long httpresp;
hand = yajl_init();
/* Query AUR */
curl_reset(curl);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, parse_json);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, hand);
switch (query_type) {
case AUR_QUERY_SEARCH:
snprintf(url, PATH_MAX, AUR_RPC_URL, AUR_RPC_TYPE_SEARCH, searchstr);
break;
case AUR_QUERY_INFO:
snprintf(url, PATH_MAX, AUR_RPC_URL, AUR_RPC_TYPE_INFO, searchstr);
break;
case AUR_QUERY_MSEARCH:
snprintf(url, PATH_MAX, AUR_RPC_URL, AUR_RPC_TYPE_MSEARCH, searchstr);
break;
default:
break;
}
curl_easy_setopt(curl, CURLOPT_URL, url);
if (curl_easy_perform(curl) != CURLE_OK) {
yajl_free(hand);
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpresp);
if (httpresp != 200) {
pw_fprintf(PW_LOG_ERROR, stderr, "curl responded with http code %ld",
httpresp);
}
RET_ERR(PW_ERR_CURL_DOWNLOAD, NULL);
}
yajl_complete_parse(hand);
yajl_free(hand);
return pwhandle->json_ctx->pkglist;
}
/* yajl callback functions */
static int json_string(void *ctx, const unsigned char *ukey, size_t len)
{
struct json_ctx_t *parser = ctx;
const char *key = ukey;
if (strcmp(parser->curkey, "type") == 0 &&
strncmp(key, "error", 5) == 0) {
return 1;
} else if (strcmp(parser->curkey, "ID") == 0) {
parser->curpkg->id = strndup(key, len);
} else if (strcmp(parser->curkey, "Name") == 0) {
parser->curpkg->name = strndup(key, len);
} else if (strcmp(parser->curkey, "Version") == 0) {
parser->curpkg->version = strndup(key, len);
} else if (strcmp(parser->curkey, "CategoryID") == 0) {
parser->curpkg->category = strndup(key, len);
} else if (strcmp(parser->curkey, "Description") == 0) {
parser->curpkg->desc = strndup(key, len);
} else if (strcmp(parser->curkey, "URL") == 0) {
parser->curpkg->url = strndup(key, len);
} else if (strcmp(parser->curkey, "URLPath") == 0) {
parser->curpkg->urlpath = strndup(key, len);
} else if (strcmp(parser->curkey, "License") == 0) {
parser->curpkg->license = strndup(key, len);
} else if (strcmp(parser->curkey, "NumVotes") == 0) {
parser->curpkg->votes = atoi(key);
} else if (strcmp(parser->curkey, "OutOfDate") == 0) {
parser->curpkg->outofdate = atoi(key);
}
return 1;
}
static int json_start_map(void *ctx)
{
struct json_ctx_t *parser = ctx;
if (parser->jsondepth++ > 0) {
parser->curpkg = aurpkg_new();
}
return 1;
}
static int json_map_key(void *ctx, const unsigned char *ukey, size_t len)
{
struct json_ctx_t *parser = ctx;
strncpy(parser->curkey, ukey, len);
parser->curkey[len] = 0;
return 1;
}
static int json_end_map(void *ctx)
{
struct json_ctx_t *parser = ctx;
if (--parser->jsondepth > 0) {
parser->pkglist = alpm_list_add(parser->pkglist, parser->curpkg);
parser->curpkg = NULL;
}
return 1;
}
/* yajl_callback functions.
* They handle the "events" of yajl.
*/
yajl_callbacks yajl_cbs[] = {
NULL,
NULL,
NULL,
NULL,
NULL,
json_string,
json_start_map,
json_map_key,
json_end_map,
NULL,
NULL
};
/* curl WRITEDATA function */
size_t parse_json(void *ptr, size_t sz, size_t nmemb, void *userdata)
{
size_t totalsz = sz * nmemb;
yajl_handle hand = userdata;
yajl_parse(hand, ptr, totalsz);
return totalsz;
}