Dont announce server in singleplayer
[oweals/minetest.git] / src / convert_json.cpp
1 /*
2 Minetest
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
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 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include <vector>
21 #include <iostream>
22 #include <sstream>
23
24 #include "convert_json.h"
25 #include "mods.h"
26 #include "config.h"
27 #include "log.h"
28 #include "main.h" // for g_settings
29 #include "settings.h"
30
31 #if USE_CURL
32 #include <curl/curl.h>
33
34 static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp)
35 {
36     ((std::string*)userp)->append((char*)contents, size * nmemb);
37     return size * nmemb;
38 }
39
40 #endif
41
42 Json::Value                 fetchJsonValue(const std::string url,
43                                                                                                         struct curl_slist *chunk) {
44 #if USE_CURL
45         std::string liststring;
46         CURL *curl;
47
48         curl = curl_easy_init();
49         if (curl)
50         {
51                 CURLcode res;
52
53                 curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
54                 curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
55                 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
56                 curl_easy_setopt(curl, CURLOPT_WRITEDATA, &liststring);
57                 curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, g_settings->getS32("curl_timeout"));
58                 curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, g_settings->getS32("curl_timeout"));
59
60                 if (chunk != 0)
61                         curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
62
63                 res = curl_easy_perform(curl);
64                 if (res != CURLE_OK)
65                         errorstream<<"Jsonreader: "<< url <<" not found (" << curl_easy_strerror(res) << ")" <<std::endl;
66                 curl_easy_cleanup(curl);
67         }
68
69         Json::Value root;
70         Json::Reader reader;
71         std::istringstream stream(liststring);
72         if (!liststring.size()) {
73                 return Json::Value();
74         }
75
76         if (!reader.parse( stream, root ) )
77         {
78                 errorstream << "URL: " << url << std::endl;
79                 errorstream << "Failed to parse json data " << reader.getFormattedErrorMessages();
80                 errorstream << "data: \"" << liststring << "\"" << std::endl;
81                 return Json::Value();
82         }
83
84         if (root.isArray()) {
85                 return root;
86         }
87         if ((root["list"].isArray())) {
88                 return root["list"];
89         }
90         else {
91                 return root;
92         }
93 #endif
94         return Json::Value();
95 }
96
97 std::vector<ModStoreMod>    readModStoreList(Json::Value& modlist) {
98         std::vector<ModStoreMod> retval;
99
100         if (modlist.isArray()) {
101                 for (unsigned int i = 0; i < modlist.size(); i++)
102                 {
103                         ModStoreMod toadd;
104                         toadd.valid = true;
105
106                         //id
107                         if (modlist[i]["id"].asString().size()) {
108                                 const char* id_raw = modlist[i]["id"].asString().c_str();
109                                 char* endptr = 0;
110                                 int numbervalue = strtol(id_raw,&endptr,10);
111
112                                 if ((*id_raw != 0) && (*endptr == 0)) {
113                                         toadd.id = numbervalue;
114                                 }
115                         }
116                         else {
117                                 errorstream << "readModStoreList: missing id" << std::endl;
118                                 toadd.valid = false;
119                         }
120
121                         //title
122                         if (modlist[i]["title"].asString().size()) {
123                                 toadd.title = modlist[i]["title"].asString();
124                         }
125                         else {
126                                 errorstream << "readModStoreList: missing title" << std::endl;
127                                 toadd.valid = false;
128                         }
129
130                         //basename
131                         if (modlist[i]["basename"].asString().size()) {
132                                 toadd.basename = modlist[i]["basename"].asString();
133                         }
134                         else {
135                                 errorstream << "readModStoreList: missing basename" << std::endl;
136                                 toadd.valid = false;
137                         }
138
139                         //author
140
141                         //rating
142
143                         //version
144
145                         if (toadd.valid) {
146                                 retval.push_back(toadd);
147                         }
148                 }
149         }
150         return retval;
151 }
152
153 ModStoreModDetails          readModStoreModDetails(Json::Value& details) {
154
155         ModStoreModDetails retval;
156
157         retval.valid = true;
158
159         //version set
160         if (details["version_set"].isArray()) {
161                 for (unsigned int i = 0; i < details["version_set"].size(); i++)
162                 {
163                         ModStoreVersionEntry toadd;
164
165                         if (details["version_set"][i]["id"].asString().size()) {
166                                 const char* id_raw = details["version_set"][i]["id"].asString().c_str();
167                                 char* endptr = 0;
168                                 int numbervalue = strtol(id_raw,&endptr,10);
169
170                                 if ((*id_raw != 0) && (*endptr == 0)) {
171                                         toadd.id = numbervalue;
172                                 }
173                         }
174                         else {
175                                 errorstream << "readModStoreModDetails: missing version_set id" << std::endl;
176                                 retval.valid = false;
177                         }
178
179                         //date
180                         if (details["version_set"][i]["date"].asString().size()) {
181                                 toadd.date = details["version_set"][i]["date"].asString();
182                         }
183
184                         //file
185                         if (details["version_set"][i]["file"].asString().size()) {
186                                 toadd.file = details["version_set"][i]["file"].asString();
187                         }
188                         else {
189                                 errorstream << "readModStoreModDetails: missing version_set file" << std::endl;
190                                 retval.valid = false;
191                         }
192
193                         //approved
194
195                         //mtversion
196
197                         if( retval.valid ) {
198                                 retval.versions.push_back(toadd);
199                         }
200                         else {
201                                 break;
202                         }
203                 }
204         }
205
206         if (retval.versions.size() < 1) {
207                 errorstream << "readModStoreModDetails: not a single version specified!" << std::endl;
208                 retval.valid = false;
209         }
210
211         //categories
212         if (details["categories"].isObject()) {
213                 for (unsigned int i = 0; i < details["categories"].size(); i++) {
214                         ModStoreCategoryInfo toadd;
215
216                         if (details["categories"][i]["id"].asString().size()) {
217
218                                 const char* id_raw = details["categories"][i]["id"].asString().c_str();
219                                 char* endptr = 0;
220                                 int numbervalue = strtol(id_raw,&endptr,10);
221
222                                 if ((*id_raw != 0) && (*endptr == 0)) {
223                                         toadd.id = numbervalue;
224                                 }
225                         }
226                         else {
227                                 errorstream << "readModStoreModDetails: missing categories id" << std::endl;
228                                 retval.valid = false;
229                         }
230                         if (details["categories"][i]["title"].asString().size()) {
231                                 toadd.name = details["categories"][i]["title"].asString();
232                         }
233                         else {
234                                 errorstream << "readModStoreModDetails: missing categories title" << std::endl;
235                                 retval.valid = false;
236                         }
237
238                         if( retval.valid ) {
239                                 retval.categories.push_back(toadd);
240                         }
241                         else {
242                                 break;
243                         }
244                 }
245         }
246
247         //author
248         if (details["author"].isObject()) {
249                 if (details["author"]["id"].asString().size()) {
250
251                         const char* id_raw = details["author"]["id"].asString().c_str();
252                         char* endptr = 0;
253                         int numbervalue = strtol(id_raw,&endptr,10);
254
255                         if ((*id_raw != 0) && (*endptr == 0)) {
256                                 retval.author.id = numbervalue;
257                         }
258                         else {
259                                 errorstream << "readModStoreModDetails: missing author id (convert)" << std::endl;
260                                 retval.valid = false;
261                         }
262                 }
263                 else {
264                         errorstream << "readModStoreModDetails: missing author id" << std::endl;
265                         retval.valid = false;
266                 }
267
268                 if (details["author"]["username"].asString().size()) {
269                         retval.author.username = details["author"]["username"].asString();
270                 }
271                 else {
272                         errorstream << "readModStoreModDetails: missing author username" << std::endl;
273                         retval.valid = false;
274                 }
275         }
276         else {
277                 errorstream << "readModStoreModDetails: missing author" << std::endl;
278                 retval.valid = false;
279         }
280
281         //license
282         if (details["license"].isObject()) {
283                 if (details["license"]["id"].asString().size()) {
284
285                         const char* id_raw = details["license"]["id"].asString().c_str();
286                         char* endptr = 0;
287                         int numbervalue = strtol(id_raw,&endptr,10);
288
289                         if ((*id_raw != 0) && (*endptr == 0)) {
290                                 retval.license.id = numbervalue;
291                         }
292                 }
293                 else {
294                         errorstream << "readModStoreModDetails: missing license id" << std::endl;
295                         retval.valid = false;
296                 }
297
298                 if (details["license"]["short"].asString().size()) {
299                         retval.license.shortinfo = details["license"]["short"].asString();
300                 }
301                 else {
302                         errorstream << "readModStoreModDetails: missing license short" << std::endl;
303                         retval.valid = false;
304                 }
305
306                 if (details["license"]["link"].asString().size()) {
307                         retval.license.url = details["license"]["link"].asString();
308                 }
309
310         }
311
312         //titlepic
313         if (details["titlepic"].isObject()) {
314                 if (details["titlepic"]["id"].asString().size()) {
315
316                         const char* id_raw = details["titlepic"]["id"].asString().c_str();
317                         char* endptr = 0;
318                         int numbervalue = strtol(id_raw,&endptr,10);
319
320                         if ((*id_raw != 0) && (*endptr == 0)) {
321                                 retval.titlepic.id = numbervalue;
322                         }
323                 }
324
325                 if (details["titlepic"]["file"].asString().size()) {
326                         retval.titlepic.file = details["titlepic"]["file"].asString();
327                 }
328
329                 if (details["titlepic"]["desc"].asString().size()) {
330                         retval.titlepic.description = details["titlepic"]["desc"].asString();
331                 }
332
333                 if (details["titlepic"]["mod"].asString().size()) {
334
335                         const char* mod_raw = details["titlepic"]["mod"].asString().c_str();
336                         char* endptr = 0;
337                         int numbervalue = strtol(mod_raw,&endptr,10);
338
339                         if ((*mod_raw != 0) && (*endptr == 0)) {
340                                 retval.titlepic.mod = numbervalue;
341                         }
342                 }
343         }
344
345         //id
346         if (details["id"].asString().size()) {
347
348                 const char* id_raw = details["id"].asString().c_str();
349                 char* endptr = 0;
350                 int numbervalue = strtol(id_raw,&endptr,10);
351
352                 if ((*id_raw != 0) && (*endptr == 0)) {
353                         retval.id = numbervalue;
354                 }
355         }
356         else {
357                 errorstream << "readModStoreModDetails: missing id" << std::endl;
358                 retval.valid = false;
359         }
360
361         //title
362         if (details["title"].asString().size()) {
363                 retval.title = details["title"].asString();
364         }
365         else {
366                 errorstream << "readModStoreModDetails: missing title" << std::endl;
367                 retval.valid = false;
368         }
369
370         //basename
371         if (details["basename"].asString().size()) {
372                 retval.basename = details["basename"].asString();
373         }
374         else {
375                 errorstream << "readModStoreModDetails: missing basename" << std::endl;
376                 retval.valid = false;
377         }
378
379         //description
380         if (details["desc"].asString().size()) {
381                 retval.description = details["desc"].asString();
382         }
383
384         //repository
385         if (details["replink"].asString().size()) {
386                 retval.repository = details["replink"].asString();
387         }
388
389         //value
390         if (details["rating"].asString().size()) {
391
392                 const char* id_raw = details["rating"].asString().c_str();
393                 char* endptr = 0;
394                 float numbervalue = strtof(id_raw,&endptr);
395
396                 if ((*id_raw != 0) && (*endptr == 0)) {
397                         retval.rating = numbervalue;
398                 }
399         }
400         else {
401                 retval.rating = 0.0;
402         }
403
404         //depends
405         if (details["depends"].isArray()) {
406                 //TODO
407         }
408
409         //softdepends
410         if (details["softdep"].isArray()) {
411                 //TODO
412         }
413
414         //screenshot url
415         if (details["screenshot_url"].asString().size()) {
416                 retval.screenshot_url = details["screenshot_url"].asString();
417         }
418
419         return retval;
420 }