]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/urllib.qc
Merge branch 'master' into terencehill/arena_stuff
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / urllib.qc
1 // files (-1 for URL)
2 .float url_fh;
3
4 // URLs
5 .string url_url;
6 .float url_wbuf;
7 .float url_wbufpos;
8 .float url_rbuf;
9 .float url_rbufpos;
10 .float url_id;
11 .url_ready_func url_ready;
12 .entity url_ready_pass;
13
14 entity url_fromid[NUM_URL_ID];
15 float autocvar__urllib_nextslot;
16
17 float url_URI_Get_Callback(float id, float status, string data)
18 {
19         if(id < MIN_URL_ID)
20                 return 0;
21         id -= MIN_URL_ID;
22         if(id >= NUM_URL_ID)
23                 return 0;
24         entity e;
25         e = url_fromid[id];
26         if(!e)
27                 return 0;
28         if(e.url_rbuf >= 0 || e.url_wbuf >= 0)
29         {
30                 print(sprintf("WARNING: handle %d (%s) has already received data?!?\n", id + NUM_URL_ID, e.url_url));
31                 return 0;
32         }
33
34         // whatever happens, we will remove the URL from the list of IDs
35         url_fromid[id] = world;
36
37         if(status == 0)
38         {
39                 // WE GOT DATA!
40                 float n, i;
41                 n = tokenizebyseparator(data, "\n");
42                 e.url_rbuf = buf_create();
43                 e.url_rbufpos = 0;
44                 if(e.url_rbuf < 0)
45                 {
46                         print("buf_create: out of memory\n");
47                         e.url_ready(e, e.url_ready_pass, URL_READY_ERROR);
48                         strunzone(e.url_url);
49                         remove(e);
50                 }
51                 for(i = 0; i < n; ++i)
52                         bufstr_set(e.url_rbuf, i, argv(i));
53                 e.url_ready(e, e.url_ready_pass, URL_READY_CANREAD);
54                 return 1;
55         }
56         else
57         {
58                 // an ERROR
59                 e.url_ready(e, e.url_ready_pass, -status);
60                 strunzone(e.url_url);
61                 remove(e);
62                 return 1;
63         }
64 }
65
66 void url_fopen(string url, float mode, url_ready_func rdy, entity pass)
67 {
68         entity e;
69         float i;
70         if(strstrofs(url, "://", 0) >= 0)
71         {
72                 switch(mode)
73                 {
74                         case FILE_WRITE:
75                         case FILE_APPEND:
76                                 // collect data to a stringbuffer for a POST request
77                                 // attempts to close will result in a reading handle
78                                 e = spawn();
79                                 e.classname = "url_fopen_file";
80                                 e.url_url = strzone(url);
81                                 e.url_fh = -1;
82                                 e.url_wbuf = buf_create();
83                                 if(e.url_wbuf < 0)
84                                 {
85                                         print("buf_create: out of memory\n");
86                                         rdy(e, pass, URL_READY_ERROR);
87                                         strunzone(e.url_url);
88                                         remove(e);
89                                         return;
90                                 }
91                                 e.url_wbufpos = 0;
92                                 e.url_rbuf = -1;
93                                 rdy(e, pass, URL_READY_CANWRITE);
94                                 break;
95
96                         case FILE_READ:
97                                 // read data only
98                                 for(i = autocvar__urllib_nextslot; i < NUM_URL_ID; ++i)
99                                         if(url_fromid[i] == world)
100                                                 break;
101                                 if(i >= NUM_URL_ID)
102                                 {
103                                         for(i = 0; i < autocvar__urllib_nextslot; ++i)
104                                                 if(url_fromid[i] == world)
105                                                         break;
106                                         if(i >= autocvar__urllib_nextslot)
107                                         {
108                                                 rdy(world, pass, URL_READY_ERROR);
109                                                 return;
110                                         }
111                                 }
112
113                                 e = spawn();
114                                 e.classname = "url_fopen_file";
115                                 e.url_url = strzone(url);
116                                 e.url_fh = -1;
117                                 e.url_rbuf = -1;
118                                 e.url_wbuf = -1;
119                                 if(!crypto_uri_postbuf(url, i + MIN_URL_ID, string_null, string_null, -1, 0))
120                                 {
121                                         rdy(e, pass, URL_READY_ERROR);
122                                         strunzone(e.url_url);
123                                         remove(e);
124                                         return;
125                                 }
126                                 e.url_ready = rdy;
127                                 e.url_ready_pass = pass;
128                                 e.url_id = i;
129                                 url_fromid[i] = e;
130                                 cvar_set("_urllib_nextslot", ftos(mod(i + 1, NUM_URL_ID)));
131                                 break;
132                 }
133         }
134         else
135         {
136                 float fh;
137                 fh = fopen(url, mode);
138                 if(fh < 0)
139                 {
140                         rdy(world, pass, URL_READY_ERROR);
141                         return;
142                 }
143                 else
144                 {
145                         e = spawn();
146                         e.classname = "url_fopen_file";
147                         e.url_fh = fh;
148                         if(mode == FILE_READ)
149                                 rdy(e, pass, URL_READY_CANREAD);
150                         else
151                                 rdy(e, pass, URL_READY_CANWRITE);
152                 }
153         }
154 }
155
156 void url_fclose(entity e, url_ready_func rdy, entity pass)
157 {
158         float i;
159
160         if(e.url_fh < 0)
161         {
162                 if(e.url_wbuf >= 0)
163                 {
164                         for(i = autocvar__urllib_nextslot; i < NUM_URL_ID; ++i)
165                                 if(url_fromid[i] == world)
166                                         break;
167                         if(i >= NUM_URL_ID)
168                         {
169                                 for(i = 0; i < autocvar__urllib_nextslot; ++i)
170                                         if(url_fromid[i] == world)
171                                                 break;
172                                 if(i >= autocvar__urllib_nextslot)
173                                 {
174                                         buf_del(e.url_wbuf);
175                                         rdy(e, pass, URL_READY_ERROR);
176                                         strunzone(e.url_url);
177                                         remove(e);
178                                         return;
179                                 }
180                         }
181                         print(ftos(i), "\n");
182
183                         if(!crypto_uri_postbuf(e.url_url, i + MIN_URL_ID, "text/plain", "", e.url_wbuf, 0))
184                         {
185                                 buf_del(e.url_wbuf);
186                                 rdy(e, pass, URL_READY_ERROR);
187                                 strunzone(e.url_url);
188                                 remove(e);
189                                 return;
190                         }
191
192                         buf_del(e.url_wbuf);
193                         e.url_wbuf = -1;
194                         e.url_ready = rdy;
195                         e.url_ready_pass = pass;
196                         e.url_id = i;
197                         url_fromid[i] = e;
198                         cvar_set("_urllib_nextslot", ftos(mod(i + 1, NUM_URL_ID)));
199                 }
200                 else
201                 {
202                         // we have READ all data
203                         rdy(e, pass, URL_READY_CLOSED);
204                         buf_del(e.url_rbuf);
205                         strunzone(e.url_url);
206                         remove(e);
207                 }
208         }
209         else
210         {
211                 // file
212                 fclose(e.url_fh);
213                 rdy(e, pass, URL_READY_CLOSED); // closing creates no reading handle
214                 remove(e);
215         }
216 }
217
218 // with \n
219 string url_fgets(entity e)
220 {
221         if(e.url_fh < 0)
222         {
223                 // curl
224                 string s;
225                 s = bufstr_get(e.url_rbuf, e.url_rbufpos);
226                 e.url_rbufpos += 1;
227                 return s;
228         }
229         else
230         {
231                 // file
232                 return fgets(e.url_fh);
233         }
234 }
235
236 // without \n
237 void url_fputs(entity e, string s)
238 {
239         if(e.url_fh < 0)
240         {
241                 // curl
242                 bufstr_set(e.url_wbuf, e.url_wbufpos, s);
243                 e.url_wbufpos += 1;
244         }
245         else
246         {
247                 // file
248                 fputs(e.url_fh, s);
249         }
250 }