Move urllib to /lib
authorTimePath <andrew.hardaker1995@gmail.com>
Wed, 26 Aug 2015 23:38:54 +0000 (09:38 +1000)
committerTimePath <andrew.hardaker1995@gmail.com>
Wed, 26 Aug 2015 23:38:54 +0000 (09:38 +1000)
15 files changed:
qcsrc/client/miscfunctions.qc
qcsrc/client/progs.src
qcsrc/common/constants.qh
qcsrc/common/playerstats.qc
qcsrc/common/urllib.qc [deleted file]
qcsrc/common/urllib.qh [deleted file]
qcsrc/lib/_all.inc
qcsrc/lib/urllib.qc [new file with mode: 0644]
qcsrc/lib/urllib.qh [new file with mode: 0644]
qcsrc/menu/progs.src
qcsrc/menu/xonotic/util.qc
qcsrc/server/miscfunctions.qc
qcsrc/server/mutators/mutators_include.qc
qcsrc/server/progs.src
qcsrc/server/weapons/weaponstats.qc

index 845a564..c9c5999 100644 (file)
@@ -7,7 +7,6 @@
 #include "../common/command/generic.qh"
 
 #include "../common/teams.qh"
-#include "../common/urllib.qh"
 #include "../common/util.qh"
 
 #include "../csqcmodellib/cl_model.qh"
index b9006dd..3c6ccc1 100644 (file)
@@ -53,7 +53,6 @@ weapons/projectile.qc // TODO
 ../common/playerstats.qc
 ../common/p2mathlib.qc
 ../common/test.qc
-../common/urllib.qc
 ../common/util.qc
 
 ../common/viewloc.qc
index bc18b4d..7078401 100644 (file)
@@ -362,16 +362,6 @@ const int SPAWN_PRIO_NEAR_TEAMMATE_SAMETEAM = 100;
 const int SPAWN_PRIO_RACE_PREVIOUS_SPAWN = 50;
 const int SPAWN_PRIO_GOOD_DISTANCE = 10;
 
-// URI handles
-const int URI_GET_DISCARD = 0;
-const int URI_GET_IPBAN = 1;
-const int URI_GET_IPBAN_END = 16;
-const int URI_GET_CURL = 17;
-const int URI_GET_CURL_END = 32;
-const int URI_GET_UPDATENOTIFICATION = 33;
-const int URI_GET_URLLIB = 128;
-const int URI_GET_URLLIB_END = 191;
-
 // gametype vote flags
 const int GTV_FORBIDDEN = 0; // Cannot be voted
 const int GTV_AVAILABLE = 1; // Can be voted
index e46e12f..ea783a1 100644 (file)
@@ -5,7 +5,6 @@
     #include "../dpdefs/dpextensions.qh"
     #include "constants.qh"
     #include "util.qh"
-    #include "urllib.qh"
     #include "weapons/all.qh"
     #include "../server/weapons/accuracy.qh"
     #include "../server/defs.qh"
diff --git a/qcsrc/common/urllib.qc b/qcsrc/common/urllib.qc
deleted file mode 100644 (file)
index 8529ebd..0000000
+++ /dev/null
@@ -1,400 +0,0 @@
-#if defined(CSQC)
-       #include "../dpdefs/csprogsdefs.qh"
-       #include "constants.qh"
-       #include "util.qh"
-       #include "urllib.qh"
-#elif defined(MENUQC)
-#elif defined(SVQC)
-       #include "../dpdefs/progsdefs.qh"
-    #include "../dpdefs/dpextensions.qh"
-    #include "constants.qh"
-    #include "util.qh"
-    #include "urllib.qh"
-#endif
-
-// files
-.float url_fh;
-const float URL_FH_CURL = -1;
-const float URL_FH_STDOUT = -2;
-
-// URLs
-.string url_url;
-.float url_wbuf;
-.float url_wbufpos;
-.float url_rbuf;
-.float url_rbufpos;
-.float url_id;
-.url_ready_func url_ready;
-.entity url_ready_pass;
-
-// for multi handles
-.int url_attempt;
-.int url_mode;
-
-entity url_fromid[NUM_URL_ID];
-int autocvar__urllib_nextslot;
-
-float url_URI_Get_Callback(int id, float status, string data)
-{
-       if(id < MIN_URL_ID)
-               return 0;
-       id -= MIN_URL_ID;
-       if(id >= NUM_URL_ID)
-               return 0;
-       entity e;
-       e = url_fromid[id];
-       if(!e)
-               return 0;
-       if(e.url_rbuf >= 0 || e.url_wbuf >= 0)
-       {
-               printf("WARNING: handle %d (%s) has already received data?!?\n", id + NUM_URL_ID, e.url_url);
-               return 0;
-       }
-
-       // whatever happens, we will remove the URL from the list of IDs
-       url_fromid[id] = world;
-
-       // if we get here, we MUST have both buffers cleared
-       if(e.url_rbuf != -1 || e.url_wbuf != -1 || e.url_fh != URL_FH_CURL)
-               error("url_URI_Get_Callback: not a request waiting for data");
-
-       if(status == 0)
-       {
-               // WE GOT DATA!
-               float n, i;
-               n = tokenizebyseparator(data, "\n");
-               e.url_rbuf = buf_create();
-               if(e.url_rbuf < 0)
-               {
-                       print("url_URI_Get_Callback: out of memory in buf_create\n");
-                       e.url_ready(e, e.url_ready_pass, URL_READY_ERROR);
-                       strunzone(e.url_url);
-                       remove(e);
-                       return 1;
-               }
-               e.url_rbufpos = 0;
-               if(e.url_rbuf < 0)
-               {
-                       print("url_URI_Get_Callback: out of memory in buf_create\n");
-                       e.url_ready(e, e.url_ready_pass, URL_READY_ERROR);
-                       strunzone(e.url_url);
-                       remove(e);
-                       return 1;
-               }
-               for(i = 0; i < n; ++i)
-                       bufstr_set(e.url_rbuf, i, argv(i));
-               e.url_ready(e, e.url_ready_pass, URL_READY_CANREAD);
-               return 1;
-       }
-       else
-       {
-               // an ERROR
-               e.url_ready(e, e.url_ready_pass, -fabs(status));
-               strunzone(e.url_url);
-               remove(e);
-               return 1;
-       }
-}
-
-void url_single_fopen(string url, int mode, url_ready_func rdy, entity pass)
-{
-       entity e;
-       int i;
-       if(strstrofs(url, "://", 0) >= 0)
-       {
-               switch(mode)
-               {
-                       case FILE_WRITE:
-                       case FILE_APPEND:
-                               // collect data to a stringbuffer for a POST request
-                               // attempts to close will result in a reading handle
-
-                               // create a writing end that does nothing yet
-                               e = spawn();
-                               e.classname = "url_single_fopen_file";
-                               e.url_url = strzone(url);
-                               e.url_fh = URL_FH_CURL;
-                               e.url_wbuf = buf_create();
-                               if(e.url_wbuf < 0)
-                               {
-                                       print("url_single_fopen: out of memory in buf_create\n");
-                                       rdy(e, pass, URL_READY_ERROR);
-                                       strunzone(e.url_url);
-                                       remove(e);
-                                       return;
-                               }
-                               e.url_wbufpos = 0;
-                               e.url_rbuf = -1;
-                               e.url_ready = rdy;
-                               e.url_ready_pass = pass;
-                               rdy(e, pass, URL_READY_CANWRITE);
-                               break;
-
-                       case FILE_READ:
-                               // read data only
-
-                               // get slot for HTTP request
-                               for(i = autocvar__urllib_nextslot; i < NUM_URL_ID; ++i)
-                                       if(url_fromid[i] == world)
-                                               break;
-                               if(i >= NUM_URL_ID)
-                               {
-                                       for(i = 0; i < autocvar__urllib_nextslot; ++i)
-                                               if(url_fromid[i] == world)
-                                                       break;
-                                       if(i >= autocvar__urllib_nextslot)
-                                       {
-                                               print("url_single_fopen: too many concurrent requests\n");
-                                               rdy(world, pass, URL_READY_ERROR);
-                                               return;
-                                       }
-                               }
-
-                               // GET the data
-                               if(!crypto_uri_postbuf(url, i + MIN_URL_ID, string_null, string_null, -1, 0))
-                               {
-                                       print("url_single_fopen: failure in crypto_uri_postbuf\n");
-                                       rdy(world, pass, URL_READY_ERROR);
-                                       return;
-                               }
-
-                               // Make a dummy handle object (no buffers at
-                               // all). Wait for data to come from the
-                               // server, then call the callback
-                               e = spawn();
-                               e.classname = "url_single_fopen_file";
-                               e.url_url = strzone(url);
-                               e.url_fh = URL_FH_CURL;
-                               e.url_rbuf = -1;
-                               e.url_wbuf = -1;
-                               e.url_ready = rdy;
-                               e.url_ready_pass = pass;
-                               e.url_id = i;
-                               url_fromid[i] = e;
-
-                               // make sure this slot won't be reused quickly even on map change
-                               cvar_set("_urllib_nextslot", ftos((i + 1) % NUM_URL_ID));
-                               break;
-               }
-       }
-       else if(url == "-")
-       {
-               switch(mode)
-               {
-                       case FILE_WRITE:
-                       case FILE_APPEND:
-                               e = spawn();
-                               e.classname = "url_single_fopen_stdout";
-                               e.url_fh = URL_FH_STDOUT;
-                               e.url_ready = rdy;
-                               e.url_ready_pass = pass;
-                               rdy(e, pass, URL_READY_CANWRITE);
-                               break;
-                       case FILE_READ:
-                               print("url_single_fopen: cannot open '-' for reading\n");
-                               rdy(world, pass, URL_READY_ERROR);
-                               break;
-               }
-       }
-       else
-       {
-               float fh;
-               fh = fopen(url, mode);
-               if(fh < 0)
-               {
-                       rdy(world, pass, URL_READY_ERROR);
-                       return;
-               }
-               else
-               {
-                       e = spawn();
-                       e.classname = "url_single_fopen_file";
-                       e.url_fh = fh;
-                       e.url_ready = rdy;
-                       e.url_ready_pass = pass;
-                       if(mode == FILE_READ)
-                               rdy(e, pass, URL_READY_CANREAD);
-                       else
-                               rdy(e, pass, URL_READY_CANWRITE);
-               }
-       }
-}
-
-// close a file
-void url_fclose(entity e)
-{
-       int i;
-
-       if(e.url_fh == URL_FH_CURL)
-       {
-               if(e.url_rbuf == -1 || e.url_wbuf != -1) // not(post GET/POST request)
-               if(e.url_rbuf != -1 || e.url_wbuf == -1) // not(pre POST request)
-                       error("url_fclose: not closable in current state");
-
-               // closing an URL!
-               if(e.url_wbuf >= 0)
-               {
-                       // we are closing the write end (HTTP POST request)
-
-                       // get slot for HTTP request
-                       for(i = autocvar__urllib_nextslot; i < NUM_URL_ID; ++i)
-                               if(url_fromid[i] == world)
-                                       break;
-                       if(i >= NUM_URL_ID)
-                       {
-                               for(i = 0; i < autocvar__urllib_nextslot; ++i)
-                                       if(url_fromid[i] == world)
-                                               break;
-                               if(i >= autocvar__urllib_nextslot)
-                               {
-                                       print("url_fclose: too many concurrent requests\n");
-                                       e.url_ready(e,e.url_ready_pass, URL_READY_ERROR);
-                                       buf_del(e.url_wbuf);
-                                       strunzone(e.url_url);
-                                       remove(e);
-                                       return;
-                               }
-                       }
-
-                       // POST the data
-                       if(!crypto_uri_postbuf(e.url_url, i + MIN_URL_ID, "text/plain", "", e.url_wbuf, 0))
-                       {
-                               print("url_fclose: failure in crypto_uri_postbuf\n");
-                               e.url_ready(e, e.url_ready_pass, URL_READY_ERROR);
-                               buf_del(e.url_wbuf);
-                               strunzone(e.url_url);
-                               remove(e);
-                               return;
-                       }
-
-                       // delete write end. File handle is now in unusable
-                       // state. Wait for data to come from the server, then
-                       // call the callback
-                       buf_del(e.url_wbuf);
-                       e.url_wbuf = -1;
-                       e.url_id = i;
-                       url_fromid[i] = e;
-
-                       // make sure this slot won't be reused quickly even on map change
-                       cvar_set("_urllib_nextslot", ftos((i + 1) % NUM_URL_ID));
-               }
-               else
-               {
-                       // we have READ all data, just close
-                       e.url_ready(e, e.url_ready_pass, URL_READY_CLOSED);
-                       buf_del(e.url_rbuf);
-                       strunzone(e.url_url);
-                       remove(e);
-               }
-       }
-       else if(e.url_fh == URL_FH_STDOUT)
-       {
-               e.url_ready(e, e.url_ready_pass, URL_READY_CLOSED); // closing creates no reading handle
-               remove(e);
-       }
-       else
-       {
-               // file
-               fclose(e.url_fh);
-               e.url_ready(e, e.url_ready_pass, URL_READY_CLOSED); // closing creates no reading handle
-               remove(e);
-       }
-}
-
-// with \n (blame FRIK_FILE)
-string url_fgets(entity e)
-{
-       if(e.url_fh == URL_FH_CURL)
-       {
-               if(e.url_rbuf == -1)
-                       error("url_fgets: not readable in current state");
-               // curl
-               string s;
-               s = bufstr_get(e.url_rbuf, e.url_rbufpos);
-               e.url_rbufpos += 1;
-               return s;
-       }
-       else if(e.url_fh == URL_FH_STDOUT)
-       {
-               // stdout
-               return string_null;
-       }
-       else
-       {
-               // file
-               return fgets(e.url_fh);
-       }
-}
-
-// without \n (blame FRIK_FILE)
-void url_fputs(entity e, string s)
-{
-       if(e.url_fh == URL_FH_CURL)
-       {
-               if(e.url_wbuf == -1)
-                       error("url_fputs: not writable in current state");
-               // curl
-               bufstr_set(e.url_wbuf, e.url_wbufpos, s);
-               e.url_wbufpos += 1;
-       }
-       else if(e.url_fh == URL_FH_STDOUT)
-       {
-               // stdout
-               print(s);
-       }
-       else
-       {
-               // file
-               fputs(e.url_fh, s);
-       }
-}
-
-// multi URL object, tries URLs separated by space in sequence
-void url_multi_ready(entity fh, entity me, float status)
-{
-       float n;
-       if(status == URL_READY_ERROR || status < 0)
-       {
-               if(status == -422) // Unprocessable Entity
-               {
-                       print("uri_multi_ready: got HTTP error 422, data is in unusable format - not continuing\n");
-                       me.url_ready(fh, me.url_ready_pass, status);
-                       strunzone(me.url_url);
-                       remove(me);
-                       return;
-               }
-               me.url_attempt += 1;
-               n = tokenize_console(me.url_url);
-               if(n <= me.url_attempt)
-               {
-                       me.url_ready(fh, me.url_ready_pass, status);
-                       strunzone(me.url_url);
-                       remove(me);
-                       return;
-               }
-               url_single_fopen(argv(me.url_attempt), me.url_mode, url_multi_ready, me);
-               return;
-       }
-       me.url_ready(fh, me.url_ready_pass, status);
-}
-void url_multi_fopen(string url, int mode, url_ready_func rdy, entity pass)
-{
-       float n;
-       n = tokenize_console(url);
-       if(n <= 0)
-       {
-               print("url_multi_fopen: need at least one URL\n");
-               rdy(world, pass, URL_READY_ERROR);
-               return;
-       }
-
-       entity me;
-       me = spawn();
-       me.classname = "url_multi";
-       me.url_url = strzone(url);
-       me.url_attempt = 0;
-       me.url_mode = mode;
-       me.url_ready = rdy;
-       me.url_ready_pass = pass;
-       url_single_fopen(argv(0), mode, url_multi_ready, me);
-}
diff --git a/qcsrc/common/urllib.qh b/qcsrc/common/urllib.qh
deleted file mode 100644 (file)
index d58a0b1..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef URLLIB_H
-#define URLLIB_H
-
-const float URL_READY_ERROR    = -1;
-const float URL_READY_CLOSED   =  0;
-const float URL_READY_CANWRITE =  1;
-const float URL_READY_CANREAD  =  2;
-// errors: -1, or negative HTTP status code
-typedef void(entity handle, entity pass, float status) url_ready_func;
-
-void url_single_fopen(string url, float mode, url_ready_func rdy, entity pass);
-void url_fclose(entity e);
-string url_fgets(entity e);
-void url_fputs(entity e, string s);
-
-// returns true if handled
-float url_URI_Get_Callback(int id, float status, string data);
-#define MIN_URL_ID URI_GET_URLLIB
-#define NUM_URL_ID (URI_GET_URLLIB_END - URI_GET_URLLIB + 1)
-
-void url_multi_fopen(string url, float mode, url_ready_func rdy, entity pass);
-#endif
index 410eac7..1e7b85f 100644 (file)
@@ -7,3 +7,4 @@
 #include "OO.qh"
 #include "Progname.qh"
 #include "Registry.qh"
+#include "urllib.qc"
diff --git a/qcsrc/lib/urllib.qc b/qcsrc/lib/urllib.qc
new file mode 100644 (file)
index 0000000..ce8de50
--- /dev/null
@@ -0,0 +1,388 @@
+#include "urllib.qh"
+
+// files
+.float url_fh;
+const float URL_FH_CURL = -1;
+const float URL_FH_STDOUT = -2;
+
+// URLs
+.string url_url;
+.float url_wbuf;
+.float url_wbufpos;
+.float url_rbuf;
+.float url_rbufpos;
+.float url_id;
+.url_ready_func url_ready;
+.entity url_ready_pass;
+
+// for multi handles
+.int url_attempt;
+.int url_mode;
+
+entity url_fromid[NUM_URL_ID];
+int autocvar__urllib_nextslot;
+
+float url_URI_Get_Callback(int id, float status, string data)
+{
+       if(id < MIN_URL_ID)
+               return 0;
+       id -= MIN_URL_ID;
+       if(id >= NUM_URL_ID)
+               return 0;
+       entity e;
+       e = url_fromid[id];
+       if(!e)
+               return 0;
+       if(e.url_rbuf >= 0 || e.url_wbuf >= 0)
+       {
+               printf("WARNING: handle %d (%s) has already received data?!?\n", id + NUM_URL_ID, e.url_url);
+               return 0;
+       }
+
+       // whatever happens, we will remove the URL from the list of IDs
+       url_fromid[id] = NULL;
+
+       // if we get here, we MUST have both buffers cleared
+       if(e.url_rbuf != -1 || e.url_wbuf != -1 || e.url_fh != URL_FH_CURL)
+               error("url_URI_Get_Callback: not a request waiting for data");
+
+       if(status == 0)
+       {
+               // WE GOT DATA!
+               float n, i;
+               n = tokenizebyseparator(data, "\n");
+               e.url_rbuf = buf_create();
+               if(e.url_rbuf < 0)
+               {
+                       print("url_URI_Get_Callback: out of memory in buf_create\n");
+                       e.url_ready(e, e.url_ready_pass, URL_READY_ERROR);
+                       strunzone(e.url_url);
+                       remove(e);
+                       return 1;
+               }
+               e.url_rbufpos = 0;
+               if(e.url_rbuf < 0)
+               {
+                       print("url_URI_Get_Callback: out of memory in buf_create\n");
+                       e.url_ready(e, e.url_ready_pass, URL_READY_ERROR);
+                       strunzone(e.url_url);
+                       remove(e);
+                       return 1;
+               }
+               for(i = 0; i < n; ++i)
+                       bufstr_set(e.url_rbuf, i, argv(i));
+               e.url_ready(e, e.url_ready_pass, URL_READY_CANREAD);
+               return 1;
+       }
+       else
+       {
+               // an ERROR
+               e.url_ready(e, e.url_ready_pass, -fabs(status));
+               strunzone(e.url_url);
+               remove(e);
+               return 1;
+       }
+}
+
+void url_single_fopen(string url, int mode, url_ready_func rdy, entity pass)
+{
+       entity e;
+       int i;
+       if(strstrofs(url, "://", 0) >= 0)
+       {
+               switch(mode)
+               {
+                       case FILE_WRITE:
+                       case FILE_APPEND:
+                               // collect data to a stringbuffer for a POST request
+                               // attempts to close will result in a reading handle
+
+                               // create a writing end that does nothing yet
+                               e = spawn();
+                               e.classname = "url_single_fopen_file";
+                               e.url_url = strzone(url);
+                               e.url_fh = URL_FH_CURL;
+                               e.url_wbuf = buf_create();
+                               if(e.url_wbuf < 0)
+                               {
+                                       print("url_single_fopen: out of memory in buf_create\n");
+                                       rdy(e, pass, URL_READY_ERROR);
+                                       strunzone(e.url_url);
+                                       remove(e);
+                                       return;
+                               }
+                               e.url_wbufpos = 0;
+                               e.url_rbuf = -1;
+                               e.url_ready = rdy;
+                               e.url_ready_pass = pass;
+                               rdy(e, pass, URL_READY_CANWRITE);
+                               break;
+
+                       case FILE_READ:
+                               // read data only
+
+                               // get slot for HTTP request
+                               for(i = autocvar__urllib_nextslot; i < NUM_URL_ID; ++i)
+                                       if(url_fromid[i] == NULL)
+                                               break;
+                               if(i >= NUM_URL_ID)
+                               {
+                                       for(i = 0; i < autocvar__urllib_nextslot; ++i)
+                                               if(url_fromid[i] == NULL)
+                                                       break;
+                                       if(i >= autocvar__urllib_nextslot)
+                                       {
+                                               print("url_single_fopen: too many concurrent requests\n");
+                                               rdy(NULL, pass, URL_READY_ERROR);
+                                               return;
+                                       }
+                               }
+
+                               // GET the data
+                               if(!crypto_uri_postbuf(url, i + MIN_URL_ID, string_null, string_null, -1, 0))
+                               {
+                                       print("url_single_fopen: failure in crypto_uri_postbuf\n");
+                                       rdy(NULL, pass, URL_READY_ERROR);
+                                       return;
+                               }
+
+                               // Make a dummy handle object (no buffers at
+                               // all). Wait for data to come from the
+                               // server, then call the callback
+                               e = spawn();
+                               e.classname = "url_single_fopen_file";
+                               e.url_url = strzone(url);
+                               e.url_fh = URL_FH_CURL;
+                               e.url_rbuf = -1;
+                               e.url_wbuf = -1;
+                               e.url_ready = rdy;
+                               e.url_ready_pass = pass;
+                               e.url_id = i;
+                               url_fromid[i] = e;
+
+                               // make sure this slot won't be reused quickly even on map change
+                               cvar_set("_urllib_nextslot", ftos((i + 1) % NUM_URL_ID));
+                               break;
+               }
+       }
+       else if(url == "-")
+       {
+               switch(mode)
+               {
+                       case FILE_WRITE:
+                       case FILE_APPEND:
+                               e = spawn();
+                               e.classname = "url_single_fopen_stdout";
+                               e.url_fh = URL_FH_STDOUT;
+                               e.url_ready = rdy;
+                               e.url_ready_pass = pass;
+                               rdy(e, pass, URL_READY_CANWRITE);
+                               break;
+                       case FILE_READ:
+                               print("url_single_fopen: cannot open '-' for reading\n");
+                               rdy(NULL, pass, URL_READY_ERROR);
+                               break;
+               }
+       }
+       else
+       {
+               float fh;
+               fh = fopen(url, mode);
+               if(fh < 0)
+               {
+                       rdy(NULL, pass, URL_READY_ERROR);
+                       return;
+               }
+               else
+               {
+                       e = spawn();
+                       e.classname = "url_single_fopen_file";
+                       e.url_fh = fh;
+                       e.url_ready = rdy;
+                       e.url_ready_pass = pass;
+                       if(mode == FILE_READ)
+                               rdy(e, pass, URL_READY_CANREAD);
+                       else
+                               rdy(e, pass, URL_READY_CANWRITE);
+               }
+       }
+}
+
+// close a file
+void url_fclose(entity e)
+{
+       int i;
+
+       if(e.url_fh == URL_FH_CURL)
+       {
+               if(e.url_rbuf == -1 || e.url_wbuf != -1) // not(post GET/POST request)
+               if(e.url_rbuf != -1 || e.url_wbuf == -1) // not(pre POST request)
+                       error("url_fclose: not closable in current state");
+
+               // closing an URL!
+               if(e.url_wbuf >= 0)
+               {
+                       // we are closing the write end (HTTP POST request)
+
+                       // get slot for HTTP request
+                       for(i = autocvar__urllib_nextslot; i < NUM_URL_ID; ++i)
+                               if(url_fromid[i] == NULL)
+                                       break;
+                       if(i >= NUM_URL_ID)
+                       {
+                               for(i = 0; i < autocvar__urllib_nextslot; ++i)
+                                       if(url_fromid[i] == NULL)
+                                               break;
+                               if(i >= autocvar__urllib_nextslot)
+                               {
+                                       print("url_fclose: too many concurrent requests\n");
+                                       e.url_ready(e,e.url_ready_pass, URL_READY_ERROR);
+                                       buf_del(e.url_wbuf);
+                                       strunzone(e.url_url);
+                                       remove(e);
+                                       return;
+                               }
+                       }
+
+                       // POST the data
+                       if(!crypto_uri_postbuf(e.url_url, i + MIN_URL_ID, "text/plain", "", e.url_wbuf, 0))
+                       {
+                               print("url_fclose: failure in crypto_uri_postbuf\n");
+                               e.url_ready(e, e.url_ready_pass, URL_READY_ERROR);
+                               buf_del(e.url_wbuf);
+                               strunzone(e.url_url);
+                               remove(e);
+                               return;
+                       }
+
+                       // delete write end. File handle is now in unusable
+                       // state. Wait for data to come from the server, then
+                       // call the callback
+                       buf_del(e.url_wbuf);
+                       e.url_wbuf = -1;
+                       e.url_id = i;
+                       url_fromid[i] = e;
+
+                       // make sure this slot won't be reused quickly even on map change
+                       cvar_set("_urllib_nextslot", ftos((i + 1) % NUM_URL_ID));
+               }
+               else
+               {
+                       // we have READ all data, just close
+                       e.url_ready(e, e.url_ready_pass, URL_READY_CLOSED);
+                       buf_del(e.url_rbuf);
+                       strunzone(e.url_url);
+                       remove(e);
+               }
+       }
+       else if(e.url_fh == URL_FH_STDOUT)
+       {
+               e.url_ready(e, e.url_ready_pass, URL_READY_CLOSED); // closing creates no reading handle
+               remove(e);
+       }
+       else
+       {
+               // file
+               fclose(e.url_fh);
+               e.url_ready(e, e.url_ready_pass, URL_READY_CLOSED); // closing creates no reading handle
+               remove(e);
+       }
+}
+
+// with \n (blame FRIK_FILE)
+string url_fgets(entity e)
+{
+       if(e.url_fh == URL_FH_CURL)
+       {
+               if(e.url_rbuf == -1)
+                       error("url_fgets: not readable in current state");
+               // curl
+               string s;
+               s = bufstr_get(e.url_rbuf, e.url_rbufpos);
+               e.url_rbufpos += 1;
+               return s;
+       }
+       else if(e.url_fh == URL_FH_STDOUT)
+       {
+               // stdout
+               return string_null;
+       }
+       else
+       {
+               // file
+               return fgets(e.url_fh);
+       }
+}
+
+// without \n (blame FRIK_FILE)
+void url_fputs(entity e, string s)
+{
+       if(e.url_fh == URL_FH_CURL)
+       {
+               if(e.url_wbuf == -1)
+                       error("url_fputs: not writable in current state");
+               // curl
+               bufstr_set(e.url_wbuf, e.url_wbufpos, s);
+               e.url_wbufpos += 1;
+       }
+       else if(e.url_fh == URL_FH_STDOUT)
+       {
+               // stdout
+               print(s);
+       }
+       else
+       {
+               // file
+               fputs(e.url_fh, s);
+       }
+}
+
+// multi URL object, tries URLs separated by space in sequence
+void url_multi_ready(entity fh, entity me, float status)
+{
+       float n;
+       if(status == URL_READY_ERROR || status < 0)
+       {
+               if(status == -422) // Unprocessable Entity
+               {
+                       print("uri_multi_ready: got HTTP error 422, data is in unusable format - not continuing\n");
+                       me.url_ready(fh, me.url_ready_pass, status);
+                       strunzone(me.url_url);
+                       remove(me);
+                       return;
+               }
+               me.url_attempt += 1;
+               n = tokenize_console(me.url_url);
+               if(n <= me.url_attempt)
+               {
+                       me.url_ready(fh, me.url_ready_pass, status);
+                       strunzone(me.url_url);
+                       remove(me);
+                       return;
+               }
+               url_single_fopen(argv(me.url_attempt), me.url_mode, url_multi_ready, me);
+               return;
+       }
+       me.url_ready(fh, me.url_ready_pass, status);
+}
+void url_multi_fopen(string url, int mode, url_ready_func rdy, entity pass)
+{
+       float n;
+       n = tokenize_console(url);
+       if(n <= 0)
+       {
+               print("url_multi_fopen: need at least one URL\n");
+               rdy(NULL, pass, URL_READY_ERROR);
+               return;
+       }
+
+       entity me;
+       me = spawn();
+       me.classname = "url_multi";
+       me.url_url = strzone(url);
+       me.url_attempt = 0;
+       me.url_mode = mode;
+       me.url_ready = rdy;
+       me.url_ready_pass = pass;
+       url_single_fopen(argv(0), mode, url_multi_ready, me);
+}
diff --git a/qcsrc/lib/urllib.qh b/qcsrc/lib/urllib.qh
new file mode 100644 (file)
index 0000000..6f19678
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef URLLIB_H
+#define URLLIB_H
+
+#include "../common/util.qh"
+
+// URI handles
+const int URI_GET_DISCARD = 0;
+const int URI_GET_IPBAN = 1;
+const int URI_GET_IPBAN_END = 16;
+const int URI_GET_CURL = 17;
+const int URI_GET_CURL_END = 32;
+const int URI_GET_UPDATENOTIFICATION = 33;
+const int URI_GET_URLLIB = 128;
+const int URI_GET_URLLIB_END = 191;
+
+const float URL_READY_ERROR    = -1;
+const float URL_READY_CLOSED   =  0;
+const float URL_READY_CANWRITE =  1;
+const float URL_READY_CANREAD  =  2;
+// errors: -1, or negative HTTP status code
+typedef void(entity handle, entity pass, float status) url_ready_func;
+
+void url_single_fopen(string url, float mode, url_ready_func rdy, entity pass);
+void url_fclose(entity e);
+string url_fgets(entity e);
+void url_fputs(entity e, string s);
+
+// returns true if handled
+float url_URI_Get_Callback(int id, float status, string data);
+#define MIN_URL_ID URI_GET_URLLIB
+#define NUM_URL_ID (URI_GET_URLLIB_END - URI_GET_URLLIB + 1)
+
+void url_multi_fopen(string url, float mode, url_ready_func rdy, entity pass);
+#endif
index 0a1a715..4192c69 100644 (file)
@@ -21,7 +21,6 @@ xonotic/util.qc
 ../common/mapinfo.qc
 ../common/playerstats.qc
 ../common/test.qc
-../common/urllib.qc
 ../common/util.qc
 
 ../common/items/all.qc
index a50fb4c..a5fa9da 100644 (file)
@@ -4,7 +4,6 @@
 #include "../../common/campaign_common.qh"
 #include "../../common/constants.qh"
 #include "../../common/mapinfo.qh"
-#include "../../common/urllib.qh"
 #include "../../common/util.qh"
 #include "../../common/command/generic.qh"
 
index e757e01..71fb2de 100644 (file)
@@ -18,7 +18,6 @@
 #include "../common/playerstats.qh"
 #include "../common/teams.qh"
 #include "../common/triggers/subs.qh"
-#include "../common/urllib.qh"
 #include "../common/util.qh"
 #include "../common/turrets/sv_turrets.qh"
 #include "../common/weapons/all.qh"
index 1286317..a703fdc 100644 (file)
@@ -15,7 +15,6 @@
     #include "../../common/nades.qh"
     #include "../../common/buffs.qh"
     #include "../../common/test.qh"
-    #include "../../common/urllib.qh"
     #include "../../common/command/markup.qh"
     #include "../../common/command/rpn.qh"
     #include "../../common/command/generic.qh"
index 4aea59e..0cf64ca 100644 (file)
@@ -102,7 +102,6 @@ weapons/weaponsystem.qc
 ../common/test.qc
 ../common/viewloc.qc
 ../common/triggers/include.qc
-../common/urllib.qc
 ../common/util.qc
 
 ../common/items/all.qc
index a849699..09d2770 100644 (file)
@@ -3,7 +3,6 @@
 
 #include "../g_world.qh"
 
-#include "../../common/urllib.qh"
 #include "../../common/weapons/all.qh"
 
 void WeaponStats_Init()