UFO: Alien Invasion
Loading...
Searching...
No Matches
web_cgame.cpp
Go to the documentation of this file.
1
5
6/*
7Copyright (C) 2002-2025 UFO: Alien Invasion.
8
9This program is free software; you can redistribute it and/or
10modify it under the terms of the GNU General Public License
11as published by the Free Software Foundation; either version 2
12of the License, or (at your option) any later version.
13
14This program is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17
18See the GNU General Public License for more details.m
19
20You should have received a copy of the GNU General Public License
21along with this program; if not, write to the Free Software
22Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23*/
24
25#include "web_cgame.h"
26#include "web_main.h"
27#include "../cl_shared.h"
28#include "../cgame/cl_game.h"
29#include "../ui/ui_main.h"
30#include "../../shared/parse.h"
31
36
37#define URL_SIZE 576
38
50static const char* WEB_CGameGetURL (char* out, size_t outSize, const char* url, const char* cgameId, int category, const char* filename, int userId = -1)
51{
52 char categoryStr[MAX_VAR];
53 Com_sprintf(categoryStr, sizeof(categoryStr), "%i", category);
54 char userIdStr[MAX_VAR];
55 Com_sprintf(userIdStr, sizeof(userIdStr), "%i", userId);
56
57 const struct urlIds_s {
58 const char* id;
59 const char* replace;
60 bool mandatory;
61 } urlIds[] = {
62 {"$cgame$", cgameId, true},
63 {"$category$", categoryStr, category >= 0},
64 {"$file$", filename, filename != nullptr},
65 {"$userid$", userIdStr, userId > 0}
66 };
67
68 Q_strncpyz(out, url, outSize);
69
70 const size_t entries = lengthof(urlIds);
71 for (int i = 0; i < entries; i++) {
72 const urlIds_s& id = urlIds[i];
73 if (strstr(out, id.id) != nullptr) {
74 char encoded[256] = { '\0' };
75 const char* replace = encoded;
76 if (id.replace != nullptr) {
77 if (!HTTP_Encode(id.replace, encoded, sizeof(encoded))) {
78 Com_Printf("failed to encode '%s'\n", id.replace);
79 return nullptr;
80 }
81 }
82 char buf1[URL_SIZE];
83 if (!Q_strreplace(out, id.id, replace, buf1, sizeof(buf1))) {
84 Com_Printf("failed to replace '%s'\n", id.id);
85 return nullptr;
86 }
87 Q_strncpyz(out, buf1, outSize);
88 } else if (id.mandatory) {
89 Com_Printf("'%s' is missing in the url\n", id.id);
90 return nullptr;
91 }
92 }
93
94 return out;
95}
96
106bool WEB_CGameUpload (const char* cgameId, int category, const char* filename)
107{
108 if (Q_strnull(cgameId))
109 return false;
110
111 if (Q_strnull(filename))
112 return false;
113
114 if (!WEB_CheckAuth())
115 return false;
116
117 const char* fullPath = va("%s/%s", FS_Gamedir(), filename);
118 /* we ignore this, because this file is not in the users save path,
119 * but part of the game data. Don't upload this. */
120 if (!FS_FileExists("%s", fullPath)) {
121 Com_Printf("no user data: '%s'\n", fullPath);
122 UI_ExecuteConfunc("cgame_uploadfailed");
123 return false;
124 }
125
126 char url[URL_SIZE];
127 const char* encodedURL = WEB_CGameGetURL(url, sizeof(url), web_cgameuploadurl->string, cgameId, category, nullptr);
128 if (encodedURL == nullptr) {
129 UI_ExecuteConfunc("cgame_uploadfailed");
130 return false;
131 }
132
133 if (!WEB_PutFile("cgame", fullPath, encodedURL)) {
134 Com_Printf("failed to upload the team from file '%s'\n", filename);
135 UI_ExecuteConfunc("cgame_uploadfailed");
136 return false;
137 }
138
139 Com_Printf("uploaded the team '%s'\n", filename);
140 UI_ExecuteConfunc("cgame_uploadsuccessful");
141 return true;
142}
143
152bool WEB_CGameDelete (const char* cgameId, int category, const char* filename)
153{
154 if (!WEB_CheckAuth())
155 return false;
156
157 char url[URL_SIZE];
158 const char* encodedURL = WEB_CGameGetURL(url, sizeof(url), web_cgamedeleteurl->string, cgameId, category, filename);
159 if (encodedURL == nullptr)
160 return false;
161
162 if (!WEB_GetURL(encodedURL, nullptr)) {
163 Com_Printf("failed to delete the cgame file '%s' from the server\n", filename);
164 UI_ExecuteConfunc("cgame_deletefailed");
165 return false;
166 }
167
168 Com_Printf("deleted the cgame file '%s'\n", filename);
169
170 char idBuf[MAX_VAR];
171 const char* id = Com_SkipPath(filename);
172 Com_StripExtension(id, idBuf, sizeof(idBuf));
173
174 UI_ExecuteConfunc("cgame_deletesuccessful \"%s\" %i %i", idBuf, category, web_userid->integer);
175 return true;
176}
177
187bool WEB_CGameDownloadFromUser (const char* cgameId, int category, const char* filename, int userId)
188{
189 char url[URL_SIZE];
190 const char* encodedURL = WEB_CGameGetURL(url, sizeof(url), web_cgamedownloadurl->string, cgameId, category, filename, userId);
191 if (encodedURL == nullptr)
192 return false;
193
194 char buf[MAX_OSPATH];
196 Q_strcat(buf, sizeof(buf), "%s", filename);
197
200 if (!f) {
201 Com_Printf("Could not open the target file\n");
202 return false;
203 }
204
205 /* no login is needed here */
206 if (!HTTP_GetToFile(encodedURL, f.getFile())) {
207 Com_Printf("cgame file download failed from '%s'\n", url);
208 return false;
209 }
210 return true;
211}
212
218static void WEB_ListCGameFilesCallback (const char* responseBuf, void* userdata)
219{
220 int* count = (int*)userdata;
221
222 if (count != nullptr)
223 *count = 0;
224
225 if (!responseBuf) {
226 Com_Printf("Could not load the cgame list\n");
227 return;
228 }
229
230 struct entry_s {
231 int userId;
232 int category;
233 char file[MAX_OSPATH];
234 char name[MAX_VAR];
235 };
236
237 const value_t values[] = {
238 {"userid", V_INT, offsetof(entry_s, userId), MEMBER_SIZEOF(entry_s, userId)},
239 {"category", V_INT, offsetof(entry_s, category), MEMBER_SIZEOF(entry_s, category)},
240 {"file", V_STRING, offsetof(entry_s, file), 0},
241 {"name", V_STRING, offsetof(entry_s, name), 0},
242 {nullptr, V_NULL, 0, 0}
243 };
244
245 entry_s entry;
246
247 const char* token = Com_Parse(&responseBuf);
248 if (token[0] != '{') {
249 Com_Printf("invalid token: '%s' - expected {\n", token);
250 return;
251 }
252 int num = 0;
253 int level = 1;
254 for (;;) {
255 token = Com_Parse(&responseBuf);
256 if (!responseBuf)
257 break;
258 if (token[0] == '{') {
259 level++;
260 OBJZERO(entry);
261 continue;
262 }
263 if (token[0] == '}') {
264 level--;
265 if (level == 0) {
266 break;
267 }
268 char idBuf[MAX_VAR];
269 const char* id = Com_SkipPath(entry.file);
270 Com_StripExtension(id, idBuf, sizeof(idBuf));
271 const bool ownEntry = entry.userId == web_userid->integer;
272 UI_ExecuteConfunc("cgamefiles_add \"%s\" %i %i \"%s\" \"%s\" %i", idBuf, entry.category, entry.userId, id, entry.name, ownEntry ? 1 : 0);
273 num++;
274 continue;
275 }
276
277 const value_t* value;
278 for (value = values; value->string; value++) {
279 if (!Q_streq(token, value->string))
280 continue;
281 token = Com_Parse(&responseBuf);
282 if (!responseBuf)
283 break;
284 /* found a normal particle value */
285 Com_EParseValue(&entry, token, value->type, value->ofs, value->size);
286 break;
287 }
288 if (value->string == nullptr) {
289 Com_DPrintf(DEBUG_CLIENT, "invalid value found: '%s'\n", token);
290 // skip the invalid value for this and try to go on
291 token = Com_Parse(&responseBuf);
292 }
293 }
294 if (num == 0) {
295 UI_ExecuteConfunc("cgamefiles_nofilesfound");
296 }
297 Com_Printf("found %i cgame file entries\n", num);
298 if (count != nullptr)
299 *count = num;
300}
301
310int WEB_CGameListForUser (const char* cgameId, int category, int userId)
311{
312 if (userId == -1) {
313 if (!WEB_CheckAuth())
314 return -1;
315
316 userId = web_userid->integer;
317 }
318
319 char url[URL_SIZE];
320 const char* encodedURL = WEB_CGameGetURL(url, sizeof(url), web_cgamelisturl->string, cgameId, category, nullptr, userId);
321 if (encodedURL == nullptr)
322 return -1;
323
324 UI_ExecuteConfunc("cgamefiles_clear");
325 int count = 0;
326 if (!WEB_GetURL(encodedURL, WEB_ListCGameFilesCallback, &count)) {
327 Com_Printf("failed to query the cgame list for '%s' in category %i and for user %i\n", cgameId, category, userId);
328 return -1;
329 }
330
331 return count;
332}
333
334static void WEB_UploadCGame_f (void)
335{
336 if (Cmd_Argc() < 3) {
337 Com_Printf("Usage: %s <category> <filename>\n", Cmd_Argv(0));
338 return;
339 }
340 const char* name = GAME_GetCurrentName();
341 if (name == nullptr) {
342 Com_Printf("No active cgame type\n");
343 return;
344 }
345 const int category = atoi(Cmd_Argv(1));
346 char filename[MAX_OSPATH];
348 Q_strcat(filename, sizeof(filename), "%s", Cmd_Argv(2));
349 WEB_CGameUpload(name, category, filename);
350}
351
352static void WEB_DeleteCGame_f (void)
353{
354 if (Cmd_Argc() < 3) {
355 Com_Printf("Usage: %s <category> <filename>\n", Cmd_Argv(0));
356 return;
357 }
358 const char* name = GAME_GetCurrentName();
359 if (name == nullptr) {
360 Com_Printf("No active cgame type\n");
361 return;
362 }
363 const int category = atoi(Cmd_Argv(1));
364 const char* filename = Cmd_Argv(2);
365 WEB_CGameDelete(name, category, filename);
366}
367
368static void WEB_DownloadCGame_f (void)
369{
370 if (Cmd_Argc() < 3) {
371 Com_Printf("Usage: %s <category> <filename> [<userid>]\n", Cmd_Argv(0));
372 return;
373 }
374 const char* name = GAME_GetCurrentName();
375 if (name == nullptr) {
376 Com_Printf("No active cgame type\n");
377 return;
378 }
379 const int category = atoi(Cmd_Argv(1));
380 const char* filename = Cmd_Argv(2);
381 const int userId = Cmd_Argc() == 4 ? atoi(Cmd_Argv(3)) : -1;
382 WEB_CGameDownloadFromUser(name, category, filename, userId);
383}
384
385static void WEB_ListCGame_f (void)
386{
387 if (Cmd_Argc() < 2) {
388 Com_Printf("Usage: %s <category> [<userid>]\n", Cmd_Argv(0));
389 return;
390 }
391 const char* name = GAME_GetCurrentName();
392 if (name == nullptr) {
393 Com_Printf("No active cgame type\n");
394 return;
395 }
396 const int category = atoi(Cmd_Argv(1));
397 const int userId = Cmd_Argc() == 3 ? atoi(Cmd_Argv(2)) : -1;
398 if (WEB_CGameListForUser(name, category, userId) == -1) {
399 Com_Printf("failed to list the cgame files for '%s' in category %i for userid %i\n", name, category, userId);
400 }
401}
402
403void WEB_CGameCvars (void)
404{
405 web_cgamedownloadurl = Cvar_Get("web_cgamedownloadurl", WEB_API_SERVER "cgame/$cgame$/$userid$/$category$/$file$", 0, "The url to download a shared cgame file from. Use $userid$, $category$, $cgame$ and $file$ as placeholders.");
406 web_cgamelisturl = Cvar_Get("web_cgamelisturl", WEB_API_SERVER "api/cgamelist.php?cgame=$cgame$&category=$category$&userid=$userid$", 0, "The url to get the cgame file list from.");
407 web_cgamedeleteurl = Cvar_Get("web_cgamedeleteurl", WEB_API_SERVER "api/cgamedelete.php?cgame=$cgame$&category=$category$&file=$file$", 0, "The url to call if you want to delete one of your own cgame files again.");
408 web_cgameuploadurl = Cvar_Get("web_cgameuploadurl", WEB_API_SERVER "api/cgameupload.php?cgame=$cgame$&category=$category$", 0, "The url to upload a cgame file to.");
409}
410
412{
413 Cmd_AddCommand("web_uploadcgame", WEB_UploadCGame_f, "Upload a file for a cgame to the UFOAI server");
414 Cmd_AddCommand("web_deletecgame", WEB_DeleteCGame_f, "Delete one of your own cgame files from the server");
415 Cmd_AddCommand("web_downloadcgame", WEB_DownloadCGame_f, "Download a cgame file from the UFOAI server");
416 Cmd_AddCommand("web_listcgame", WEB_ListCGame_f, "Show all files for a cgame on the UFOAI server");
417}
const char * GAME_GetCurrentName(void)
Definition cl_game.cpp:232
const char * GAME_GetRelativeSavePath(char *buf, size_t bufSize)
Definition cl_game.cpp:1411
Shared game type headers.
Share stuff between the different cgame implementations.
const char * Cmd_Argv(int arg)
Returns a given argument.
Definition cmd.cpp:516
int Cmd_Argc(void)
Return the number of arguments of the current command. "command parameter" will result in a argc of 2...
Definition cmd.cpp:505
void Cmd_AddCommand(const char *cmdName, xcommand_t function, const char *desc)
Add a new command to the script interface.
Definition cmd.cpp:744
void Com_DPrintf(int level, const char *fmt,...)
A Com_Printf that only shows up if the "developer" cvar is set.
Definition common.cpp:440
void Com_Printf(const char *const fmt,...)
Definition common.cpp:428
cvar_t * Cvar_Get(const char *var_name, const char *var_value, int flags, const char *desc)
Init or return a cvar.
Definition cvar.cpp:342
#define DEBUG_CLIENT
Definition defines.h:59
int FS_OpenFile(const char *filename, qFILE *file, filemode_t mode)
Finds and opens the file in the search path.
Definition files.cpp:162
const char * FS_Gamedir(void)
Called to find where to write a file (savegames, etc).
Definition files.cpp:68
bool FS_FileExists(const char *filename,...)
Checks whether a file exists (not in virtual filesystem).
Definition files.cpp:1583
#define MAX_OSPATH
Definition filesys.h:44
@ FILE_WRITE
Definition filesys.h:111
level_locals_t level
Definition g_main.cpp:38
bool HTTP_GetToFile(const char *url, FILE *file, const char *postfields)
Downloads the given url into the given file.
Definition http.cpp:346
bool HTTP_Encode(const char *url, char *out, size_t outLength)
This function converts the given url to an URL encoded string. All input characters that are not a-z,...
Definition http.cpp:362
const char * filename
Definition ioapi.h:41
voidpf void * buf
Definition ioapi.h:42
const char * Com_Parse(const char *data_p[], char *target, size_t size, bool replaceWhitespaces)
Parse a token out of a string.
Definition parse.cpp:107
Shared parsing functions.
QGL_EXTERN GLuint count
Definition r_gl.h:99
QGL_EXTERN GLfloat f
Definition r_gl.h:114
QGL_EXTERN GLint i
Definition r_gl.h:113
QGL_EXTERN GLuint GLsizei GLsizei GLint GLenum GLchar * name
Definition r_gl.h:110
QGL_EXTERN GLuint * id
Definition r_gl.h:86
int Com_EParseValue(void *base, const char *token, valueTypes_t type, int ofs, size_t size)
Definition scripts.cpp:964
@ V_NULL
Definition scripts.h:49
@ V_STRING
Definition scripts.h:58
@ V_INT
Definition scripts.h:52
#define MEMBER_SIZEOF(TYPE, MEMBER)
Definition scripts.h:34
#define Q_streq(a, b)
Definition shared.h:136
bool Q_strnull(const char *string)
Definition shared.h:138
#define OBJZERO(obj)
Definition shared.h:178
#define MAX_VAR
Definition shared.h:36
#define lengthof(x)
Definition shared.h:105
void Com_StripExtension(const char *in, char *out, const size_t size)
Removes the file extension from a filename.
Definition shared.cpp:259
const char * Com_SkipPath(const char *pathname)
Returns just the filename from a given path.
Definition shared.cpp:37
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition shared.cpp:457
void Q_strcat(char *dest, size_t destsize, const char *format,...)
Safely (without overflowing the destination buffer) concatenates two strings.
Definition shared.cpp:475
bool Q_strreplace(const char *source, const char *pattern, const char *replace, char *dest, size_t destsize)
Replaces the first occurence of the given pattern in the source string with the given replace string.
Definition shared.cpp:596
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition shared.cpp:494
const char * va(const char *format,...)
does a varargs printf into a temp buffer, so I don't need to have varargs versions of all text functi...
Definition shared.cpp:410
This is a cvar definition. Cvars can be user modified and used in our menus e.g.
Definition cvar.h:71
size_t ofs
Definition scripts.h:170
const char * string
Definition scripts.h:168
size_t size
Definition scripts.h:171
valueTypes_t type
Definition scripts.h:169
void UI_ExecuteConfunc(const char *fmt,...)
Executes confunc - just to identify those confuncs in the code - in this frame.
Definition ui_main.cpp:110
static cvar_t * web_cgamedownloadurl
Definition web_cgame.cpp:32
static cvar_t * web_cgamedeleteurl
Definition web_cgame.cpp:33
static cvar_t * web_cgamelisturl
Definition web_cgame.cpp:35
static void WEB_ListCGameFilesCallback(const char *responseBuf, void *userdata)
The http callback for the cgame list command.
bool WEB_CGameUpload(const char *cgameId, int category, const char *filename)
Uploads a file to the server.
static cvar_t * web_cgameuploadurl
Definition web_cgame.cpp:34
#define URL_SIZE
Definition web_cgame.cpp:37
bool WEB_CGameDelete(const char *cgameId, int category, const char *filename)
Deletes a user owned file on the server.
void WEB_CGameCommands(void)
int WEB_CGameListForUser(const char *cgameId, int category, int userId)
Shows the uploaded files for the particular cgame category and the given userid.
bool WEB_CGameDownloadFromUser(const char *cgameId, int category, const char *filename, int userId)
Downloads a file from the server and store it in the user directory.
static const char * WEB_CGameGetURL(char *out, size_t outSize, const char *url, const char *cgameId, int category, const char *filename, int userId=-1)
Replaces placeholders in the urls with given values.
Definition web_cgame.cpp:50
static void WEB_UploadCGame_f(void)
static void WEB_DownloadCGame_f(void)
void WEB_CGameCvars(void)
static void WEB_ListCGame_f(void)
static void WEB_DeleteCGame_f(void)
UFOAI web interface management. c(lient)game related stuff.
bool WEB_CheckAuth(void)
Pushes the webauth window if the password is not yet set.
Definition web_main.cpp:176
bool WEB_PutFile(const char *formName, const char *fileName, const char *url, upparam_t *params)
Uploads a file to the server with the login credentials.
Definition web_main.cpp:87
bool WEB_GetURL(const char *url, http_callback_t callback, void *userdata)
Downloads the given url and notify the callback. The login credentials are automatically added as GET...
Definition web_main.cpp:44
cvar_t * web_userid
Definition web_main.cpp:35
UFOAI web interface management. Authentication as well as uploading/downloading stuff to and from you...
#define WEB_API_SERVER
Definition web_main.h:31