Send long announce as POST, show OS in useragent
[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 #include "version.h"
31 #include "httpfetch.h"
32
33 Json::Value                 fetchJsonValue(const std::string url,
34                                                                                                         struct curl_slist *chunk) {
35 #if USE_CURL
36
37         HTTPFetchRequest fetchrequest;
38         HTTPFetchResult fetchresult;
39         fetchrequest.url = url;
40         fetchrequest.caller = HTTPFETCH_SYNC;
41
42         struct curl_slist* runptr = chunk;
43         while(runptr) {
44                 fetchrequest.extra_headers.push_back(runptr->data);
45                 runptr = runptr->next;
46         }
47         httpfetch_sync(fetchrequest,fetchresult);
48
49         if (!fetchresult.succeeded) {
50                 return Json::Value();
51         }
52         Json::Value root;
53         Json::Reader reader;
54         std::istringstream stream(fetchresult.data);
55
56         if (!reader.parse( stream, root ) )
57         {
58                 errorstream << "URL: " << url << std::endl;
59                 errorstream << "Failed to parse json data " << reader.getFormattedErrorMessages();
60                 errorstream << "data: \"" << fetchresult.data << "\"" << std::endl;
61                 return Json::Value();
62         }
63
64         if (root.isArray()) {
65                 return root;
66         }
67         if ((root["list"].isArray())) {
68                 return root["list"];
69         }
70         else {
71                 return root;
72         }
73 #endif
74         return Json::Value();
75 }
76
77 std::vector<ModStoreMod>    readModStoreList(Json::Value& modlist) {
78         std::vector<ModStoreMod> retval;
79
80         if (modlist.isArray()) {
81                 for (unsigned int i = 0; i < modlist.size(); i++)
82                 {
83                         ModStoreMod toadd;
84                         toadd.valid = true;
85
86                         //id
87                         if (modlist[i]["id"].asString().size()) {
88                                 std::string id_raw = modlist[i]["id"].asString();
89                                 char* endptr = 0;
90                                 int numbervalue = strtol(id_raw.c_str(),&endptr,10);
91
92                                 if ((id_raw != "") && (*endptr == 0)) {
93                                         toadd.id = numbervalue;
94                                 }
95                                 else {
96                                         errorstream << "readModStoreList: missing id" << std::endl;
97                                         toadd.valid = false;
98                                 }
99                         }
100                         else {
101                                 errorstream << "readModStoreList: missing id" << std::endl;
102                                 toadd.valid = false;
103                         }
104
105                         //title
106                         if (modlist[i]["title"].asString().size()) {
107                                 toadd.title = modlist[i]["title"].asString();
108                         }
109                         else {
110                                 errorstream << "readModStoreList: missing title" << std::endl;
111                                 toadd.valid = false;
112                         }
113
114                         //basename
115                         if (modlist[i]["basename"].asString().size()) {
116                                 toadd.basename = modlist[i]["basename"].asString();
117                         }
118                         else {
119                                 errorstream << "readModStoreList: missing basename" << std::endl;
120                                 toadd.valid = false;
121                         }
122
123                         //author
124
125                         //rating
126
127                         //version
128
129                         if (toadd.valid) {
130                                 retval.push_back(toadd);
131                         }
132                 }
133         }
134         return retval;
135 }
136
137 ModStoreModDetails          readModStoreModDetails(Json::Value& details) {
138
139         ModStoreModDetails retval;
140
141         retval.valid = true;
142
143         //version set
144         if (details["version_set"].isArray()) {
145                 for (unsigned int i = 0; i < details["version_set"].size(); i++)
146                 {
147                         ModStoreVersionEntry toadd;
148
149                         if (details["version_set"][i]["id"].asString().size()) {
150                                 std::string id_raw = details["version_set"][i]["id"].asString();
151                                 char* endptr = 0;
152                                 int numbervalue = strtol(id_raw.c_str(),&endptr,10);
153
154                                 if ((id_raw != "") && (*endptr == 0)) {
155                                         toadd.id = numbervalue;
156                                 }
157                         }
158                         else {
159                                 errorstream << "readModStoreModDetails: missing version_set id" << std::endl;
160                                 retval.valid = false;
161                         }
162
163                         //date
164                         if (details["version_set"][i]["date"].asString().size()) {
165                                 toadd.date = details["version_set"][i]["date"].asString();
166                         }
167
168                         //file
169                         if (details["version_set"][i]["file"].asString().size()) {
170                                 toadd.file = details["version_set"][i]["file"].asString();
171                         }
172                         else {
173                                 errorstream << "readModStoreModDetails: missing version_set file" << std::endl;
174                                 retval.valid = false;
175                         }
176
177                         //approved
178
179                         //mtversion
180
181                         if( retval.valid ) {
182                                 retval.versions.push_back(toadd);
183                         }
184                         else {
185                                 break;
186                         }
187                 }
188         }
189
190         if (retval.versions.size() < 1) {
191                 infostream << "readModStoreModDetails: not a single version specified!" << std::endl;
192                 retval.valid = false;
193         }
194
195         //categories
196         if (details["categories"].isObject()) {
197                 for (unsigned int i = 0; i < details["categories"].size(); i++) {
198                         ModStoreCategoryInfo toadd;
199
200                         if (details["categories"][i]["id"].asString().size()) {
201
202                                 std::string id_raw = details["categories"][i]["id"].asString();
203                                 char* endptr = 0;
204                                 int numbervalue = strtol(id_raw.c_str(),&endptr,10);
205
206                                 if ((id_raw != "") && (*endptr == 0)) {
207                                         toadd.id = numbervalue;
208                                 }
209                         }
210                         else {
211                                 errorstream << "readModStoreModDetails: missing categories id" << std::endl;
212                                 retval.valid = false;
213                         }
214                         if (details["categories"][i]["title"].asString().size()) {
215                                 toadd.name = details["categories"][i]["title"].asString();
216                         }
217                         else {
218                                 errorstream << "readModStoreModDetails: missing categories title" << std::endl;
219                                 retval.valid = false;
220                         }
221
222                         if( retval.valid ) {
223                                 retval.categories.push_back(toadd);
224                         }
225                         else {
226                                 break;
227                         }
228                 }
229         }
230
231         //author
232         if (details["author"].isObject()) {
233                 if (details["author"]["id"].asString().size()) {
234
235                         std::string id_raw = details["author"]["id"].asString();
236                         char* endptr = 0;
237                         int numbervalue = strtol(id_raw.c_str(),&endptr,10);
238
239                         if ((id_raw != "") && (*endptr == 0)) {
240                                 retval.author.id = numbervalue;
241                         }
242                         else {
243                                 errorstream << "readModStoreModDetails: missing author id (convert)" << std::endl;
244                                 retval.valid = false;
245                         }
246                 }
247                 else {
248                         errorstream << "readModStoreModDetails: missing author id" << std::endl;
249                         retval.valid = false;
250                 }
251
252                 if (details["author"]["username"].asString().size()) {
253                         retval.author.username = details["author"]["username"].asString();
254                 }
255                 else {
256                         errorstream << "readModStoreModDetails: missing author username" << std::endl;
257                         retval.valid = false;
258                 }
259         }
260         else {
261                 errorstream << "readModStoreModDetails: missing author" << std::endl;
262                 retval.valid = false;
263         }
264
265         //license
266         if (details["license"].isObject()) {
267                 if (details["license"]["id"].asString().size()) {
268
269                         std::string id_raw = details["license"]["id"].asString();
270                         char* endptr = 0;
271                         int numbervalue = strtol(id_raw.c_str(),&endptr,10);
272
273                         if ((id_raw != "") && (*endptr == 0)) {
274                                 retval.license.id = numbervalue;
275                         }
276                 }
277                 else {
278                         errorstream << "readModStoreModDetails: missing license id" << std::endl;
279                         retval.valid = false;
280                 }
281
282                 if (details["license"]["short"].asString().size()) {
283                         retval.license.shortinfo = details["license"]["short"].asString();
284                 }
285                 else {
286                         errorstream << "readModStoreModDetails: missing license short" << std::endl;
287                         retval.valid = false;
288                 }
289
290                 if (details["license"]["link"].asString().size()) {
291                         retval.license.url = details["license"]["link"].asString();
292                 }
293
294         }
295
296         //titlepic
297         if (details["titlepic"].isObject()) {
298                 if (details["titlepic"]["id"].asString().size()) {
299
300                         std::string id_raw = details["titlepic"]["id"].asString();
301                         char* endptr = 0;
302                         int numbervalue = strtol(id_raw.c_str(),&endptr,10);
303
304                         if ((id_raw != "") && (*endptr == 0)) {
305                                 retval.titlepic.id = numbervalue;
306                         }
307                 }
308
309                 if (details["titlepic"]["file"].asString().size()) {
310                         retval.titlepic.file = details["titlepic"]["file"].asString();
311                 }
312
313                 if (details["titlepic"]["desc"].asString().size()) {
314                         retval.titlepic.description = details["titlepic"]["desc"].asString();
315                 }
316
317                 if (details["titlepic"]["mod"].asString().size()) {
318
319                         std::string mod_raw = details["titlepic"]["mod"].asString();
320                         char* endptr = 0;
321                         int numbervalue = strtol(mod_raw.c_str(),&endptr,10);
322
323                         if ((mod_raw != "") && (*endptr == 0)) {
324                                 retval.titlepic.mod = numbervalue;
325                         }
326                 }
327         }
328
329         //id
330         if (details["id"].asString().size()) {
331
332                 std::string id_raw = details["id"].asString();
333                 char* endptr = 0;
334                 int numbervalue = strtol(id_raw.c_str(),&endptr,10);
335
336                 if ((id_raw != "") && (*endptr == 0)) {
337                         retval.id = numbervalue;
338                 }
339         }
340         else {
341                 errorstream << "readModStoreModDetails: missing id" << std::endl;
342                 retval.valid = false;
343         }
344
345         //title
346         if (details["title"].asString().size()) {
347                 retval.title = details["title"].asString();
348         }
349         else {
350                 errorstream << "readModStoreModDetails: missing title" << std::endl;
351                 retval.valid = false;
352         }
353
354         //basename
355         if (details["basename"].asString().size()) {
356                 retval.basename = details["basename"].asString();
357         }
358         else {
359                 errorstream << "readModStoreModDetails: missing basename" << std::endl;
360                 retval.valid = false;
361         }
362
363         //description
364         if (details["desc"].asString().size()) {
365                 retval.description = details["desc"].asString();
366         }
367
368         //repository
369         if (details["replink"].asString().size()) {
370                 retval.repository = details["replink"].asString();
371         }
372
373         //value
374         if (details["rating"].asString().size()) {
375
376                 std::string id_raw = details["rating"].asString();
377                 char* endptr = 0;
378                 float numbervalue = strtof(id_raw.c_str(),&endptr);
379
380                 if ((id_raw != "") && (*endptr == 0)) {
381                         retval.rating = numbervalue;
382                 }
383         }
384         else {
385                 retval.rating = 0.0;
386         }
387
388         //depends
389         if (details["depends"].isArray()) {
390                 //TODO
391         }
392
393         //softdepends
394         if (details["softdep"].isArray()) {
395                 //TODO
396         }
397
398         //screenshot url
399         if (details["screenshot_url"].asString().size()) {
400                 retval.screenshot_url = details["screenshot_url"].asString();
401         }
402
403         return retval;
404 }