Quake II RTX doxygen  1.0 dev
download.c
Go to the documentation of this file.
1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18 
19 //
20 // cl_download.c -- queue manager and UDP downloads
21 //
22 
23 #include "client.h"
24 #include "format/md2.h"
25 #include "format/sp2.h"
26 
27 #define CL_DOWNLOAD_IGNORES "download-ignores.txt"
28 
29 typedef enum {
34 } precache_t;
35 
37 static int precache_sexed_sounds[MAX_SOUNDS];
39 
40 /*
41 ===============
42 CL_QueueDownload
43 
44 Adds new download path into queue, incrementing pending count.
45 Entry will stay in queue for entire lifetime of server connection,
46 to make sure each path is tried exactly once.
47 ===============
48 */
49 qerror_t CL_QueueDownload(const char *path, dltype_t type)
50 {
51  dlqueue_t *q;
52  size_t len;
53 
54  FOR_EACH_DLQ(q) {
55  // avoid sending duplicate requests
56  if (!FS_pathcmp(path, q->path)) {
57  Com_DPrintf("%s: %s [DUP]\n", __func__, path);
58  return Q_ERR_EXIST;
59  }
60  }
61 
62  len = strlen(path);
63  if (len >= MAX_QPATH) {
64  Com_Error(ERR_DROP, "%s: oversize quake path", __func__);
65  }
66 
67  q = Z_Malloc(sizeof(*q) + len);
68  memcpy(q->path, path, len + 1);
69  q->type = type;
70  q->state = DL_PENDING;
71 
72 #if USE_CURL
73  // paks get bumped to the top and HTTP switches to single downloading.
74  // this prevents someone on 28k dialup trying to do both the main .pak
75  // and referenced configstrings data at once.
76  if (type == DL_PAK)
77  List_Insert(&cls.download.queue, &q->entry);
78  else
79 #endif
80  List_Append(&cls.download.queue, &q->entry);
81 
83  Com_DPrintf("%s: %s [%d]\n", __func__, path, cls.download.pending);
84  return Q_ERR_SUCCESS;
85 }
86 
87 /*
88 ===============
89 CL_IgnoreDownload
90 
91 Returns true if specified path matches against an entry in download ignore
92 list.
93 ===============
94 */
95 qboolean CL_IgnoreDownload(const char *path)
96 {
97  string_entry_t *entry;
98 
99  for (entry = cls.download.ignores; entry; entry = entry->next) {
100  if (Com_WildCmp(entry->string, path)) {
101  return qtrue;
102  }
103  }
104 
105  return qfalse;
106 }
107 
108 /*
109 ===============
110 CL_FinishDownload
111 
112 Mark the queue entry as done, decrementing pending count.
113 ===============
114 */
116 {
117  if (q->state == DL_DONE) {
118  Com_Error(ERR_DROP, "%s: already done", __func__);
119  }
120  if (!cls.download.pending) {
121  Com_Error(ERR_DROP, "%s: bad pending count", __func__);
122  }
123 
124  q->state = DL_DONE;
125  cls.download.pending--;
126  Com_DPrintf("%s: %s [%d]\n", __func__, q->path, cls.download.pending);
127 }
128 
129 /*
130 ===============
131 CL_CleanupDownloads
132 
133 Disconnected from server, clean up.
134 ===============
135 */
137 {
138  dlqueue_t *q, *n;
139 
141 
142  FOR_EACH_DLQ_SAFE(q, n) {
143  Z_Free(q);
144  }
145 
146  List_Init(&cls.download.queue);
147  cls.download.pending = 0;
148 
149  cls.download.current = NULL;
150  cls.download.percent = 0;
151  cls.download.position = 0;
152 
153  if (cls.download.file) {
155  cls.download.file = 0;
156  }
157 
158  cls.download.temp[0] = 0;
159 
160 #if USE_ZLIB
161  inflateEnd(&cls.download.z);
162 #endif
163 }
164 
165 /*
166 ===============
167 CL_LoadDownloadIgnores
168 
169 Allow mods to provide a list of paths that are known to be non-existent and
170 should never be downloaded (e.g. model specific sounds).
171 ===============
172 */
174 {
175  string_entry_t *entry, *next;
176  char *raw, *data, *p;
177  int count, line;
178  ssize_t len;
179 
180  // free previous entries
181  for (entry = cls.download.ignores; entry; entry = next) {
182  next = entry->next;
183  Z_Free(entry);
184  }
185 
186  cls.download.ignores = NULL;
187 
188  // load new list
189  len = FS_LoadFile(CL_DOWNLOAD_IGNORES, (void **)&raw);
190  if (!raw) {
191  if (len != Q_ERR_NOENT)
192  Com_EPrintf("Couldn't load %s: %s\n",
194  return;
195  }
196 
197  count = 0;
198  line = 1;
199  data = raw;
200 
201  while (*data) {
202  p = strchr(data, '\n');
203  if (p) {
204  if (p > data && *(p - 1) == '\r')
205  *(p - 1) = 0;
206  *p = 0;
207  }
208 
209  // ignore empty lines and comments
210  if (*data && *data != '#' && *data != '/') {
211  len = strlen(data);
212  if (len < MAX_QPATH) {
213  entry = Z_Malloc(sizeof(*entry) + len);
214  memcpy(entry->string, data, len + 1);
215  entry->next = cls.download.ignores;
216  cls.download.ignores = entry;
217  count++;
218  } else {
219  Com_WPrintf("Oversize filter on line %d in %s\n",
220  line, CL_DOWNLOAD_IGNORES);
221  }
222  }
223 
224  if (!p)
225  break;
226 
227  data = p + 1;
228  line++;
229  }
230 
231  Com_DPrintf("Loaded %d filters from %s\n", count, CL_DOWNLOAD_IGNORES);
232 
233  FS_FreeFile(raw);
234 }
235 
236 static qboolean start_udp_download(dlqueue_t *q)
237 {
238  size_t len;
239  qhandle_t f;
240  ssize_t ret;
241 
242  len = strlen(q->path);
243  if (len >= MAX_QPATH) {
244  Com_Error(ERR_DROP, "%s: oversize quake path", __func__);
245  }
246 
247  // download to a temp name, and only rename
248  // to the real name when done, so if interrupted
249  // a runt file wont be left
250  memcpy(cls.download.temp, q->path, len);
251  memcpy(cls.download.temp + len, ".tmp", 5);
252 
253  // check to see if we already have a tmp for this file, if so, try to resume
254  // open the file if not opened yet
255  ret = FS_FOpenFile(cls.download.temp, &f, FS_MODE_RDWR);
256  if (ret >= 0) { // it exists
257  cls.download.file = f;
258  cls.download.position = ret;
259  // give the server an offset to start the download
260  Com_DPrintf("[UDP] Resuming %s\n", q->path);
261 #if USE_ZLIB
262  if (cls.serverProtocol == PROTOCOL_VERSION_R1Q2)
263  CL_ClientCommand(va("download \"%s\" %"PRIz" udp-zlib", q->path, ret));
264  else
265 #endif
266  CL_ClientCommand(va("download \"%s\" %"PRIz, q->path, ret));
267  } else if (ret == Q_ERR_NOENT) { // it doesn't exist
268  Com_DPrintf("[UDP] Downloading %s\n", q->path);
269 #if USE_ZLIB
270  if (cls.serverProtocol == PROTOCOL_VERSION_R1Q2)
271  CL_ClientCommand(va("download \"%s\" %"PRIz" udp-zlib", q->path, (size_t)0));
272  else
273 #endif
274  CL_ClientCommand(va("download \"%s\"", q->path));
275  } else { // error happened
276  Com_EPrintf("[UDP] Couldn't open %s for appending: %s\n",
279  return qfalse;
280  }
281 
282  q->state = DL_RUNNING;
283  cls.download.current = q;
284  return qtrue;
285 }
286 
287 /*
288 ===============
289 CL_StartNextDownload
290 
291 Start another UDP download if possible
292 ===============
293 */
295 {
296  dlqueue_t *q;
297 
299  return;
300  }
301 
302  FOR_EACH_DLQ(q) {
303  if (q->state == DL_PENDING) {
304  if (start_udp_download(q)) {
305  break;
306  }
307  }
308  }
309 }
310 
311 static void finish_udp_download(const char *msg)
312 {
314 
315  // finished with current path
317 
318  cls.download.current = NULL;
319  cls.download.percent = 0;
320  cls.download.position = 0;
321 
322  if (cls.download.file) {
324  cls.download.file = 0;
325  }
326 
327  cls.download.temp[0] = 0;
328 
329 #if USE_ZLIB
330  inflateReset(&cls.download.z);
331 #endif
332 
333  if (msg) {
334  Com_Printf("[UDP] %s [%s] [%d remaining file%s]\n",
335  q->path, msg, cls.download.pending,
336  cls.download.pending == 1 ? "" : "s");
337  }
338 
339  // get another file if needed
342 }
343 
344 static int write_udp_download(byte *data, int size)
345 {
346  ssize_t ret;
347 
348  ret = FS_Write(data, size, cls.download.file);
349  if (ret != size) {
350  Com_EPrintf("[UDP] Couldn't write %s: %s\n",
352  finish_udp_download(NULL);
353  return -1;
354  }
355 
356  return 0;
357 }
358 
359 // handles both continuous deflate stream for entire download and chunked
360 // per-packet streams for compatibility.
361 static int inflate_udp_download(byte *data, int inlen, int outlen)
362 {
363 #if USE_ZLIB
364 
365 #define CHUNK 0x10000
366 
367  z_streamp z = &cls.download.z;
368  byte buffer[CHUNK];
369  int ret;
370 
371  // initialize stream if not done yet
372  if (z->state == NULL && inflateInit2(z, -MAX_WBITS) != Z_OK)
373  Com_Error(ERR_FATAL, "%s: inflateInit2() failed", __func__);
374 
375  z->next_in = data;
376  z->avail_in = inlen;
377 
378  // run inflate() until output buffer not full
379  do {
380  z->next_out = buffer;
381  z->avail_out = CHUNK;
382 
383  ret = inflate(z, Z_SYNC_FLUSH);
384  if (ret != Z_OK && ret != Z_STREAM_END) {
385  Com_EPrintf("[UDP] inflate() failed: %s\n", z->msg);
386  finish_udp_download(NULL);
387  return -1;
388  }
389 
390  Com_DDPrintf("%s: %u --> %u [%d]\n",
391  __func__,
392  inlen - z->avail_in,
393  CHUNK - z->avail_out,
394  ret);
395 
396  if (write_udp_download(buffer, CHUNK - z->avail_out))
397  return -1;
398  } while (z->avail_out == 0);
399 
400  // check uncompressed length if known
401  if (outlen > 0 && outlen != z->total_out)
402  Com_WPrintf("[UDP] Decompressed length mismatch: %d != %lu\n", outlen, z->total_out);
403 
404  // prepare for the next stream if done
405  if (ret == Z_STREAM_END)
406  inflateReset(z);
407 
408  return 0;
409 #else
410  // should never happen
411  Com_Error(ERR_DROP, "Compressed server packet received, "
412  "but no zlib support linked in.");
413  return 0;
414 #endif
415 }
416 
417 /*
418 =====================
419 CL_HandleDownload
420 
421 An UDP download data has been received from the server.
422 =====================
423 */
424 void CL_HandleDownload(byte *data, int size, int percent, int compressed)
425 {
427  qerror_t ret;
428 
429  if (!q) {
430  Com_Error(ERR_DROP, "%s: no download requested", __func__);
431  }
432 
433  if (size == -1) {
434  if (!percent) {
435  finish_udp_download("FAIL");
436  } else {
437  finish_udp_download("STOP");
438  }
439  return;
440  }
441 
442  // open the file if not opened yet
443  if (!cls.download.file) {
444  ret = FS_FOpenFile(cls.download.temp, &cls.download.file, FS_MODE_WRITE);
445  if (!cls.download.file) {
446  Com_EPrintf("[UDP] Couldn't open %s for writing: %s\n",
448  finish_udp_download(NULL);
449  return;
450  }
451  }
452 
453  if (compressed) {
454  if (inflate_udp_download(data, size, compressed))
455  return;
456  } else {
457  if (write_udp_download(data, size))
458  return;
459  }
460 
461  if (percent != 100) {
462  // request next block
463  // change display routines by zoid
464  cls.download.percent = percent;
465  cls.download.position += size;
466 
467  CL_ClientCommand("nextdl");
468  } else {
469  // close the file before renaming
471  cls.download.file = 0;
472 
473  // rename the temp file to its final name
474  ret = FS_RenameFile(cls.download.temp, q->path);
475  if (ret) {
476  Com_EPrintf("[UDP] Couldn't rename %s to %s: %s\n",
477  cls.download.temp, q->path, Q_ErrorString(ret));
478  finish_udp_download(NULL);
479  } else {
480  finish_udp_download("DONE");
481  }
482  }
483 }
484 
485 
486 /*
487 ===============
488 CL_CheckDownloadExtension
489 
490 Only predefined set of filename extensions is allowed,
491 to prevent the server from uploading arbitrary files.
492 ===============
493 */
494 qboolean CL_CheckDownloadExtension(const char *ext)
495 {
496  static const char allowed[][4] = {
497  "pcx", "wal", "wav", "md2", "sp2", "tga", "png",
498  "jpg", "bsp", "ent", "txt", "dm2", "loc", "md3"
499  };
500  int i;
501 
502  for (i = 0; i < q_countof(allowed); i++)
503  if (!Q_stricmp(ext, allowed[i]))
504  return qtrue;
505 
506  return qfalse;
507 }
508 
509 // attempts to start a download from the server if file doesn't exist.
510 static qerror_t check_file_len(const char *path, size_t len, dltype_t type)
511 {
512  char buffer[MAX_QPATH], *ext;
513  qerror_t ret;
514  int valid;
515 
516  // check for oversize path
517  if (len >= MAX_QPATH)
518  return Q_ERR_NAMETOOLONG;
519 
520  // normalize path
521  len = FS_NormalizePath(buffer, path);
522 
523  // check for empty path
524  if (len == 0)
525  return Q_ERR_NAMETOOSHORT;
526 
527  valid = FS_ValidatePath(buffer);
528 
529  // check path
530  if (valid == PATH_INVALID
531  || !Q_ispath(buffer[0])
532  || !Q_ispath(buffer[len - 1])
533  || strstr(buffer, "..")
534  || !strchr(buffer, '/')) {
535  // some of these checks are too conservative or even redundant
536  // once we have normalized the path, however they have to stay for
537  // compatibility reasons with older servers (some would even ban us
538  // for sending .. for example)
539  return Q_ERR_INVALID_PATH;
540  }
541 
542  // check extension
543  ext = COM_FileExtension(buffer);
544  if (*ext != '.' || !CL_CheckDownloadExtension(ext + 1))
545  return Q_ERR_INVALID_PATH;
546 
547  if (FS_FileExists(buffer))
548  // it exists, no need to download
549  return Q_ERR_EXIST;
550 
551  if (valid == PATH_MIXED_CASE)
552  // convert to lower case to make download server happy
553  Q_strlwr(buffer);
554 
555  if (CL_IgnoreDownload(buffer))
556  return Q_ERR_PERM;
557 
558  ret = HTTP_QueueDownload(buffer, type);
559  if (ret != Q_ERR_NOSYS)
560  return ret;
561 
562  // queue and start legacy UDP download
563  ret = CL_QueueDownload(buffer, type);
564  if (ret == Q_ERR_SUCCESS)
566 
567  return ret;
568 }
569 
570 #define check_file(path, type) \
571  check_file_len(path, strlen(path), type)
572 
573 static void check_skins(const char *name)
574 {
575  size_t i, num_skins, ofs_skins, end_skins;
576  byte *model;
577  size_t len;
578  dmd2header_t *md2header;
579  dsp2header_t *sp2header;
580  char *md2skin;
581  dsp2frame_t *sp2frame;
582  uint32_t ident;
583  char fn[MAX_QPATH];
584 
585  len = FS_LoadFile(name, (void **)&model);
586  if (!model) {
587  // couldn't load it
588  return;
589  }
590 
591  if (len < sizeof(ident)) {
592  // file too small
593  goto done;
594  }
595 
596  // check ident
597  ident = LittleLong(*(uint32_t *)model);
598  switch (ident) {
599  case MD2_IDENT:
600  // alias model
601  md2header = (dmd2header_t *)model;
602  if (len < sizeof(*md2header) ||
603  LittleLong(md2header->ident) != MD2_IDENT ||
604  LittleLong(md2header->version) != MD2_VERSION) {
605  // not an alias model
606  goto done;
607  }
608 
609  num_skins = LittleLong(md2header->num_skins);
610  ofs_skins = LittleLong(md2header->ofs_skins);
611  end_skins = ofs_skins + num_skins * MD2_MAX_SKINNAME;
612  if (num_skins > MD2_MAX_SKINS || end_skins < ofs_skins || end_skins > len) {
613  // bad alias model
614  goto done;
615  }
616 
617  md2skin = (char *)model + ofs_skins;
618  for (i = 0; i < num_skins; i++) {
619  if (!Q_memccpy(fn, md2skin, 0, sizeof(fn))) {
620  // bad alias model
621  goto done;
622  }
623  check_file(fn, DL_OTHER);
624  md2skin += MD2_MAX_SKINNAME;
625  }
626  break;
627 
628  case SP2_IDENT:
629  // sprite model
630  sp2header = (dsp2header_t *)model;
631  if (len < sizeof(*sp2header) ||
632  LittleLong(sp2header->ident) != SP2_IDENT ||
633  LittleLong(sp2header->version) != SP2_VERSION) {
634  // not a sprite model
635  goto done;
636  }
637 
638  num_skins = LittleLong(sp2header->numframes);
639  ofs_skins = sizeof(*sp2header);
640  end_skins = ofs_skins + num_skins * sizeof(dsp2frame_t);
641  if (num_skins > SP2_MAX_FRAMES || end_skins < ofs_skins || end_skins > len) {
642  // bad sprite model
643  goto done;
644  }
645 
646  sp2frame = (dsp2frame_t *)(model + ofs_skins);
647  for (i = 0; i < num_skins; i++) {
648  if (!Q_memccpy(fn, sp2frame->name, 0, sizeof(fn))) {
649  // bad sprite model
650  goto done;
651  }
652  check_file(fn, DL_OTHER);
653  sp2frame++;
654  }
655  break;
656 
657  default:
658  // unknown file format
659  goto done;
660  }
661 
662 done:
663  FS_FreeFile(model);
664 }
665 
666 static void check_player(const char *name)
667 {
668  char fn[MAX_QPATH], model[MAX_QPATH], skin[MAX_QPATH], *p;
669  size_t len;
670  int i, j;
671 
672  CL_ParsePlayerSkin(NULL, model, skin, name);
673 
674  // model
675  len = Q_concat(fn, sizeof(fn), "players/", model, "/tris.md2", NULL);
676  check_file_len(fn, len, DL_OTHER);
677 
678  // weapon models
679  for (i = 0; i < cl.numWeaponModels; i++) {
680  len = Q_concat(fn, sizeof(fn), "players/", model, "/", cl.weaponModels[i], NULL);
681  check_file_len(fn, len, DL_OTHER);
682  }
683 
684  // default weapon skin
685  len = Q_concat(fn, sizeof(fn), "players/", model, "/weapon.pcx", NULL);
686  check_file_len(fn, len, DL_OTHER);
687 
688  // skin
689  len = Q_concat(fn, sizeof(fn), "players/", model, "/", skin, ".pcx", NULL);
690  check_file_len(fn, len, DL_OTHER);
691 
692  // skin_i
693  len = Q_concat(fn, sizeof(fn), "players/", model, "/", skin, "_i.pcx", NULL);
694  check_file_len(fn, len, DL_OTHER);
695 
696  // sexed sounds
697  for (i = 0; i < precache_sexed_total; i++) {
698  j = precache_sexed_sounds[i];
699  p = cl.configstrings[CS_SOUNDS + j];
700 
701  if (*p == '*') {
702  len = Q_concat(fn, sizeof(fn), "players/", model, "/", p + 1, NULL);
703  check_file_len(fn, len, DL_OTHER);
704  }
705  }
706 }
707 
708 // for precaching dependencies
709 static qboolean downloads_pending(dltype_t type)
710 {
711  dlqueue_t *q;
712 
713  // DL_OTHER just checks for any download
714  if (type == DL_OTHER) {
715  return !!cls.download.pending;
716  }
717 
718  // see if there are pending downloads of the given type
719  FOR_EACH_DLQ(q) {
720  if (q->state != DL_DONE && q->type == type) {
721  return qtrue;
722  }
723  }
724 
725  return qfalse;
726 }
727 
728 /*
729 =====================
730 CL_RequestNextDownload
731 
732 Runs precache check and dispatches downloads.
733 =====================
734 */
736 {
737  char fn[MAX_QPATH], *name;
738  size_t len;
739  int i;
740 
741  if (cls.state != ca_connected && cls.state != ca_loading)
742  return;
743 
744  if (allow_download->integer <= 0 || NET_IsLocalAddress(&cls.serverAddress)) {
745  if (precache_check <= PRECACHE_MAP) {
747  }
748 
749  CL_Begin();
750  return;
751  }
752 
753  switch (precache_check) {
754  case PRECACHE_MODELS:
755  // confirm map
756  if (allow_download_maps->integer)
757  check_file(cl.configstrings[CS_MODELS + 1], DL_MAP);
758 
759  // checking for models
760  if (allow_download_models->integer) {
761  for (i = 2; i < MAX_MODELS; i++) {
762  name = cl.configstrings[CS_MODELS + i];
763  if (!name[0]) {
764  break;
765  }
766  if (name[0] == '*' || name[0] == '#') {
767  continue;
768  }
769  check_file(name, DL_MODEL);
770  }
771  }
772 
774  // fall through
775 
776  case PRECACHE_OTHER:
777  if (allow_download_models->integer) {
779  // pending downloads (models), let's wait here before we can check skins.
780  Com_DPrintf("%s: waiting for models...\n", __func__);
781  return;
782  }
783 
784  for (i = 2; i < MAX_MODELS; i++) {
785  name = cl.configstrings[CS_MODELS + i];
786  if (!name[0]) {
787  break;
788  }
789  if (name[0] == '*' || name[0] == '#') {
790  continue;
791  }
792  check_skins(name);
793  }
794  }
795 
796  if (allow_download_sounds->integer) {
797  for (i = 1; i < MAX_SOUNDS; i++) {
798  name = cl.configstrings[CS_SOUNDS + i];
799  if (!name[0]) {
800  break;
801  }
802  if (name[0] == '*') {
803  continue;
804  }
805  if (name[0] == '#') {
806  len = Q_strlcpy(fn, name + 1, sizeof(fn));
807  } else {
808  len = Q_concat(fn, sizeof(fn), "sound/", name, NULL);
809  }
810  check_file_len(fn, len, DL_OTHER);
811  }
812  }
813 
814  if (allow_download_pics->integer) {
815  for (i = 1; i < MAX_IMAGES; i++) {
816  name = cl.configstrings[CS_IMAGES + i];
817  if (!name[0]) {
818  break;
819  }
820  if (name[0] == '/' || name[0] == '\\') {
821  len = Q_strlcpy(fn, name + 1, sizeof(fn));
822  } else {
823  len = Q_concat(fn, sizeof(fn), "pics/", name, ".pcx", NULL);
824  }
825  check_file_len(fn, len, DL_OTHER);
826  }
827  }
828 
829  if (allow_download_players->integer) {
830  // find sexed sounds
832  for (i = 1; i < MAX_SOUNDS; i++) {
833  if (cl.configstrings[CS_SOUNDS + i][0] == '*') {
835  }
836  }
837 
838  for (i = 0; i < MAX_CLIENTS; i++) {
839  name = cl.configstrings[CS_PLAYERSKINS + i];
840  if (!name[0]) {
841  continue;
842  }
843  check_player(name);
844  }
845  }
846 
847  if (allow_download_textures->integer) {
848  static const char env_suf[6][3] = {
849  "rt", "bk", "lf", "ft", "up", "dn"
850  };
851 
852  for (i = 0; i < 6; i++) {
853  len = Q_concat(fn, sizeof(fn), "env/", cl.configstrings[CS_SKY], env_suf[i], ".tga", NULL);
854  check_file_len(fn, len, DL_OTHER);
855  }
856  }
857 
859  // fall through
860 
861  case PRECACHE_MAP:
862  if (downloads_pending(DL_MAP)) {
863  // map might still be downloading?
864  Com_DPrintf("%s: waiting for map...\n", __func__);
865  return;
866  }
867 
868  // load the map file before checking textures
870 
871  if (allow_download_textures->integer) {
872  for (i = 0; i < cl.bsp->numtexinfo; i++) {
873  len = Q_concat(fn, sizeof(fn), "textures/", cl.bsp->texinfo[i].name, ".wal", NULL);
874  check_file_len(fn, len, DL_OTHER);
875  }
876  }
877 
879  // fall through
880 
881  case PRECACHE_FINAL:
883  // pending downloads (possibly textures), let's wait here.
884  Com_DPrintf("%s: waiting for others...\n", __func__);
885  return;
886  }
887 
888  // all done, tell server we are ready
889  CL_Begin();
890  break;
891 
892  default:
893  Com_Error(ERR_DROP, "%s: bad precache_check\n", __func__);
894  }
895 }
896 
898 {
900 }
901 
902 /*
903 ===============
904 CL_Download_f
905 
906 Request a download from the server
907 ===============
908 */
909 static void CL_Download_f(void)
910 {
911  char *path;
912  qerror_t ret;
913 
914  if (cls.state < ca_connected) {
915  Com_Printf("Must be connected to a server.\n");
916  return;
917  }
918 
919  if (allow_download->integer == -1) {
920  Com_Printf("Downloads are permanently disabled.\n");
921  return;
922  }
923 
924  if (Cmd_Argc() != 2) {
925  Com_Printf("Usage: download <filename>\n");
926  return;
927  }
928 
929  path = Cmd_Argv(1);
930 
931  ret = check_file(path, DL_OTHER);
932  if (ret) {
933  Com_Printf("Couldn't download %s: %s\n", path, Q_ErrorString(ret));
934  }
935 }
936 
938 {
939  Cmd_AddCommand("download", CL_Download_f);
940 
941  List_Init(&cls.download.queue);
942 }
943 
client_state_s::bsp
bsp_t * bsp
Definition: client.h:300
client_state_s::configstrings
char configstrings[MAX_CONFIGSTRINGS][MAX_QPATH]
Definition: client.h:289
PRECACHE_FINAL
@ PRECACHE_FINAL
Definition: download.c:33
CL_IgnoreDownload
qboolean CL_IgnoreDownload(const char *path)
Definition: download.c:95
allow_download_players
cvar_t * allow_download_players
Definition: common.c:106
dlqueue_t
Definition: client.h:367
DL_OTHER
@ DL_OTHER
Definition: client.h:351
client_static_s::file
qhandle_t file
Definition: client.h:443
dlqueue_t::entry
list_t entry
Definition: client.h:368
FOR_EACH_DLQ_SAFE
#define FOR_EACH_DLQ_SAFE(q, n)
Definition: client.h:346
Cmd_AddCommand
void Cmd_AddCommand(const char *name, xcommand_t function)
Definition: cmd.c:1562
PRECACHE_OTHER
@ PRECACHE_OTHER
Definition: download.c:31
CL_DOWNLOAD_IGNORES
#define CL_DOWNLOAD_IGNORES
Definition: download.c:27
precache_check
static precache_t precache_check
Definition: download.c:36
client_state_s::numWeaponModels
int numWeaponModels
Definition: client.h:312
check_player
static void check_player(const char *name)
Definition: download.c:666
HTTP_CleanupDownloads
void HTTP_CleanupDownloads(void)
Definition: http.c:386
Q_ErrorString
const char * Q_ErrorString(qerror_t error)
Definition: error.c:51
CL_ResetPrecacheCheck
void CL_ResetPrecacheCheck(void)
Definition: download.c:897
DL_MAP
@ DL_MAP
Definition: client.h:352
dltype_t
dltype_t
Definition: client.h:349
PRECACHE_MAP
@ PRECACHE_MAP
Definition: download.c:32
client_static_s::state
connstate_t state
Definition: client.h:375
ca_connected
@ ca_connected
Definition: client.h:337
CL_FinishDownload
void CL_FinishDownload(dlqueue_t *q)
Definition: download.c:115
CL_Begin
void CL_Begin(void)
Definition: main.c:1757
CL_InitDownloads
void CL_InitDownloads(void)
Definition: download.c:937
ext
char ext[4]
Definition: images.c:657
CL_LoadDownloadIgnores
void CL_LoadDownloadIgnores(void)
Definition: download.c:173
client_state_s::weaponModels
char weaponModels[MAX_CLIENTWEAPONMODELS][MAX_QPATH]
Definition: client.h:311
check_skins
static void check_skins(const char *name)
Definition: download.c:573
client_static_s::ignores
string_entry_t * ignores
Definition: client.h:448
inflate_udp_download
static int inflate_udp_download(byte *data, int inlen, int outlen)
Definition: download.c:361
Cmd_Argv
char * Cmd_Argv(int arg)
Definition: cmd.c:899
Cmd_Argc
int Cmd_Argc(void)
Definition: cmd.c:889
CL_RegisterBspModels
void CL_RegisterBspModels(void)
Definition: precache.c:226
FS_ValidatePath
int FS_ValidatePath(const char *s)
Definition: files.c:271
FS_FOpenFile
ssize_t FS_FOpenFile(const char *name, qhandle_t *f, unsigned mode)
Definition: files.c:1692
CL_CheckDownloadExtension
qboolean CL_CheckDownloadExtension(const char *ext)
Definition: download.c:494
Com_Error
void Com_Error(error_type_t type, const char *fmt,...)
Definition: g_main.c:258
allow_download_maps
cvar_t * allow_download_maps
Definition: common.c:109
allow_download_textures
cvar_t * allow_download_textures
Definition: common.c:110
CL_ParsePlayerSkin
void CL_ParsePlayerSkin(char *name, char *model, char *skin, const char *s)
Definition: precache.c:35
client_static_s::current
dlqueue_t * current
Definition: client.h:440
DL_MODEL
@ DL_MODEL
Definition: client.h:353
write_udp_download
static int write_udp_download(byte *data, int size)
Definition: download.c:344
downloads_pending
static qboolean downloads_pending(dltype_t type)
Definition: download.c:709
check_file_len
static qerror_t check_file_len(const char *path, size_t len, dltype_t type)
Definition: download.c:510
va
char * va(const char *format,...)
Definition: shared.c:429
Z_Free
void Z_Free(void *ptr)
Definition: zone.c:147
DL_DONE
@ DL_DONE
Definition: client.h:364
client_static_s::serverProtocol
int serverProtocol
Definition: client.h:422
dlqueue_t::state
dlstate_t state
Definition: client.h:370
client_static_s::pending
int pending
Definition: client.h:439
Q_strlcpy
size_t Q_strlcpy(char *dst, const char *src, size_t size)
Definition: shared.c:715
client_static_s::percent
int percent
Definition: client.h:441
dlqueue_t::path
char path[1]
Definition: client.h:371
precache_sexed_total
static int precache_sexed_total
Definition: download.c:38
precache_sexed_sounds
static int precache_sexed_sounds[MAX_SOUNDS]
Definition: download.c:37
PRECACHE_MODELS
@ PRECACHE_MODELS
Definition: download.c:30
cl
client_state_t cl
Definition: main.c:99
FS_Write
ssize_t FS_Write(const void *buf, size_t len, qhandle_t f)
Definition: files.c:1643
allow_download_sounds
cvar_t * allow_download_sounds
Definition: common.c:108
HTTP_QueueDownload
qerror_t HTTP_QueueDownload(const char *path, dltype_t type)
Definition: http.c:530
cls
client_static_t cls
Definition: main.c:98
CL_RequestNextDownload
void CL_RequestNextDownload(void)
Definition: download.c:735
FOR_EACH_DLQ
#define FOR_EACH_DLQ(q)
Definition: client.h:344
DL_RUNNING
@ DL_RUNNING
Definition: client.h:363
client_static_s::queue
list_t queue
Definition: client.h:438
CL_StartNextDownload
void CL_StartNextDownload(void)
Definition: download.c:294
finish_udp_download
static void finish_udp_download(const char *msg)
Definition: download.c:311
client_static_s::download
struct client_static_s::@2 download
allow_download_pics
cvar_t * allow_download_pics
Definition: common.c:111
client.h
CL_Download_f
static void CL_Download_f(void)
Definition: download.c:909
allow_download
cvar_t * allow_download
Definition: common.c:105
DL_PENDING
@ DL_PENDING
Definition: client.h:362
msg
const char * msg
Definition: win.h:25
CL_QueueDownload
qerror_t CL_QueueDownload(const char *path, dltype_t type)
Definition: download.c:49
client_static_s::temp
char temp[MAX_QPATH+4]
Definition: client.h:444
Q_memccpy
void * Q_memccpy(void *dst, const void *src, int c, size_t size)
Definition: shared.c:895
ca_loading
@ ca_loading
Definition: client.h:338
CL_ClientCommand
void CL_ClientCommand(const char *string)
Definition: main.c:299
FS_FCloseFile
void FS_FCloseFile(qhandle_t f)
Definition: files.c:759
Q_concat
size_t Q_concat(char *dest, size_t size,...)
Definition: shared.c:758
allow_download_models
cvar_t * allow_download_models
Definition: common.c:107
client_static_s::serverAddress
netadr_t serverAddress
Definition: client.h:409
check_file
#define check_file(path, type)
Definition: download.c:570
start_udp_download
static qboolean start_udp_download(dlqueue_t *q)
Definition: download.c:236
CL_CleanupDownloads
void CL_CleanupDownloads(void)
Definition: download.c:136
dlqueue_t::type
dltype_t type
Definition: client.h:369
COM_FileExtension
char * COM_FileExtension(const char *in)
Definition: shared.c:199
client_static_s::position
int position
Definition: client.h:442
CL_HandleDownload
void CL_HandleDownload(byte *data, int size, int percent, int compressed)
Definition: download.c:424
FS_NormalizePath
size_t FS_NormalizePath(char *out, const char *in)
Definition: files.c:331
precache_t
precache_t
Definition: download.c:29