Coverage Report

Created: 2026-10-28 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/httrack/src/htscore.h
Line
Count
Source
1
/* ------------------------------------------------------------ */
2
/*
3
HTTrack Website Copier, Offline Browser for Windows and Unix
4
Copyright (C) 1998 Xavier Roche and other contributors
5
6
SPDX-License-Identifier: GPL-3.0-or-later
7
8
This program is free software: you can redistribute it and/or modify
9
it under the terms of the GNU General Public License as published by
10
the Free Software Foundation, either version 3 of the License, or
11
(at your option) any later version.
12
13
This program is distributed in the hope that it will be useful,
14
but WITHOUT ANY WARRANTY; without even the implied warranty of
15
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
GNU General Public License for more details.
17
18
You should have received a copy of the GNU General Public License
19
along with this program. If not, see <http://www.gnu.org/licenses/>.
20
21
Ethical use: we kindly ask that you NOT use this software to harvest email
22
addresses or to collect any other private information about people. Doing so
23
would dishonor our work and waste the many hours we have spent on it.
24
25
Please visit our Website: http://www.httrack.com
26
*/
27
28
/* ------------------------------------------------------------ */
29
/* File: Main file .h                                           */
30
/* Author: Xavier Roche                                         */
31
/* ------------------------------------------------------------ */
32
33
/* Core engine declarations. Not an installed header, but part of the de-facto
34
   API surface: external consumers (e.g. httrack-android) read these structs and
35
   constants and call functions declared here. */
36
#ifndef HTS_CORE_DEFH
37
#define HTS_CORE_DEFH
38
39
#include "htsglobal.h"
40
41
/* specific definitions */
42
#include "htsbase.h"
43
/* Includes and definitions */
44
#include <limits.h>
45
#include <sys/types.h>
46
#include <sys/stat.h>
47
#ifdef _WIN32
48
#include <conio.h>
49
#include <direct.h>
50
#else
51
#ifndef _WIN32
52
#include <unistd.h>
53
#endif
54
#endif
55
/* END specific definitions */
56
57
/* Forward definitions */
58
#ifndef HTS_DEF_FWSTRUCT_lien_url
59
#define HTS_DEF_FWSTRUCT_lien_url
60
typedef struct lien_url lien_url;
61
#endif
62
#ifndef HTS_DEF_FWSTRUCT_lien_back
63
#define HTS_DEF_FWSTRUCT_lien_back
64
typedef struct lien_back lien_back;
65
#endif
66
#ifndef HTS_DEF_FWSTRUCT_struct_back
67
#define HTS_DEF_FWSTRUCT_struct_back
68
typedef struct struct_back struct_back;
69
#endif
70
#ifndef HTS_DEF_FWSTRUCT_cache_back
71
#define HTS_DEF_FWSTRUCT_cache_back
72
typedef struct cache_back cache_back;
73
#endif
74
#ifndef HTS_DEF_FWSTRUCT_hash_struct
75
#define HTS_DEF_FWSTRUCT_hash_struct
76
typedef struct hash_struct hash_struct;
77
#endif
78
#ifndef HTS_DEF_FWSTRUCT_filecreate_params
79
#define HTS_DEF_FWSTRUCT_filecreate_params
80
typedef struct filecreate_params filecreate_params;
81
#endif
82
83
// Include htslib.h for all types
84
#include "htslib.h"
85
86
// options
87
#include "htsopt.h"
88
89
// HTTrack engine sub-headers
90
91
// main entry point
92
#include "htscoremain.h"
93
94
// core routines
95
#include "htscore.h"
96
97
// misc tools for httrack.c
98
#include "htstools.h"
99
100
// command-line help
101
#include "htshelp.h"
102
103
// build the on-disk save filename
104
#include "htsname.h"
105
106
// FTP support
107
#include "htsftp.h"
108
109
// URL interception
110
#include "htscatchurl.h"
111
112
// robots.txt handling
113
#include "htsrobots.h"
114
115
// link-acceptance rules
116
#include "htswizard.h"
117
118
// regexp/filter routines
119
#include "htsfilters.h"
120
121
// download backing (the back[] slot ring)
122
#include "htsback.h"
123
124
// cache handling
125
#include "htscache.h"
126
127
// hashing
128
#include "htshash.h"
129
#include "coucal.h"
130
131
#include "htsdefines.h"
132
133
#include "hts-indextmpl.h"
134
135
/** A remote URL split into host and path, each a fixed inline buffer
136
    (HTS_URLMAXSIZE*2 bytes, NUL-terminated). */
137
#ifndef HTS_DEF_FWSTRUCT_lien_adrfil
138
#define HTS_DEF_FWSTRUCT_lien_adrfil
139
typedef struct lien_adrfil lien_adrfil;
140
#endif
141
struct lien_adrfil {
142
  char adr[HTS_URLMAXSIZE * 2]; /**< host (address) */
143
  char fil[HTS_URLMAXSIZE * 2]; /**< remote file path */
144
};
145
146
/** A remote URL plus the local on-disk path it is saved to. */
147
#ifndef HTS_DEF_FWSTRUCT_lien_adrfilsave
148
#define HTS_DEF_FWSTRUCT_lien_adrfilsave
149
typedef struct lien_adrfilsave lien_adrfilsave;
150
#endif
151
struct lien_adrfilsave {
152
  lien_adrfil af;
153
  char save[HTS_URLMAXSIZE * 2]; /**< local save path (with directory) */
154
};
155
156
/** Per-slot connect-fallback bookkeeping (parallel to struct_back.lnk).
157
    Tracks which resolved address the slot is currently connecting to so a
158
    stuck connect can be retried against the next one. */
159
typedef struct hts_connect_fallback {
160
  int addr_index;       /**< candidate being connected (0-based) */
161
  int addr_count;       /**< resolved addresses; -1 = not yet probed */
162
} hts_connect_fallback;
163
164
/** The download-slot ring: the set of concurrent transfers in flight.
165
    Allocated/owned by the engine; consumers (status callbacks, the loop)
166
    read it but do not resize or free it. */
167
#ifndef HTS_DEF_FWSTRUCT_struct_back
168
#define HTS_DEF_FWSTRUCT_struct_back
169
typedef struct struct_back struct_back;
170
#endif
171
struct struct_back {
172
  lien_back *lnk;         /**< slot array, valid indices [0..count-1]
173
                               (count+1 entries allocated); a slot is
174
                               active iff lnk[i].status != STATUS_FREE.
175
                               See struct lien_back in htsopt.h and the
176
                               STATUS_* codes in htsbasenet.h. */
177
  int count;              /**< number of usable slots (back_max) */
178
  coucal ready;           /**< index of slots whose transfer completed */
179
  LLint ready_size_bytes; /**< total bytes buffered in completed slots */
180
  hts_connect_fallback *connect_fallback; /**< per-slot, count+1 entries */
181
  hts_fetch_meta *fetch; /**< per-slot Sec-Fetch-* values, count+1 entries */
182
  hts_boolean bot_challenge_noted; /**< the bot-protection note is already in
183
                                        this mirror's log (#1732) */
184
  TStamp retry_after_until; /**< Retry-After: no new launch before this local
185
                                 ms timestamp; 0 holds nothing */
186
};
187
188
/** Open handle to the mirror cache (the read-from-old / write-to-new state
189
    used to resume and to avoid re-fetching unchanged files). Engine-owned. */
190
#ifndef HTS_DEF_FWSTRUCT_cache_back
191
#define HTS_DEF_FWSTRUCT_cache_back
192
typedef struct cache_back cache_back;
193
#endif
194
struct cache_back {
195
  int version; /**< cache-file format version being read */
196
  /* */
197
  int type;
198
  int ro;                   /**< read-only: no new cache is written */
199
200
  FILE *lst;                /**< file list, used for purge */
201
  FILE *txt;                /**< human-readable file list (info) */
202
  char lastmodified[256];
203
  // HASH
204
  coucal hashtable;
205
  // HASH for tests (naming subsystem)
206
  coucal cached_tests;
207
  /** URLs whose previous entry this run already carried forward (#1421), so a
208
      retry of the same link does not store it again. */
209
  coucal kept;
210
  /* optional log files */
211
  FILE *log;
212
  FILE *errlog;
213
  /* read-ahead cursors into the old cache */
214
  int ptr_ant;
215
  int ptr_last;
216
  /* ZIP-backed cache backend (newer format) */
217
  void *zipInput;
218
  void *zipOutput;
219
  hts_boolean
220
      zipWriteFailed; /**< a cache write failed; stop touching the stream */
221
  int zipWriteFailures; /**< consecutive entry write failures; reset on store */
222
};
223
224
#ifndef HTS_DEF_FWSTRUCT_hash_struct
225
#define HTS_DEF_FWSTRUCT_hash_struct
226
typedef struct hash_struct hash_struct;
227
#endif
228
/** Lookup indexes over the link heap: map save-name / URL back to a link, so a
229
    URL seen twice resolves to one entry. The coucal tables index into liens;
230
    they do not own the links. */
231
struct hash_struct {
232
  /* points at the engine's link array (opt->liens); not owned */
233
  const lien_url *const*const*liens;
234
  /* save-name -> link index (case-insensitive: keys lowercased) */
235
  coucal sav;
236
  /* address+path -> link index */
237
  coucal adrfil;
238
  /* former address+path -> link index (renamed/moved entries) */
239
  coucal former_adrfil;
240
  /* effective urlhack sub-flags: www.==host / // collapse / query-arg sort */
241
  hts_boolean norm_host;
242
  hts_boolean norm_slash;
243
  hts_boolean norm_query;
244
  /* query-strip keys (not owned); set from opt->strip_query at hash_init */
245
  const char *strip_query;
246
  /* host-alias rules (not owned); set from opt->host_alias at hash_init */
247
  const char *host_alias;
248
  /* scratch: the hash key is a host plus a path, the compare one a path */
249
  char normfil[HTS_URLMAXSIZE * 4];
250
  char normfil2[HTS_URLMAXSIZE * 2];
251
  char catbuff[CATBUFF_SIZE];
252
};
253
254
#ifndef HTS_DEF_FWSTRUCT_filecreate_params
255
#define HTS_DEF_FWSTRUCT_filecreate_params
256
typedef struct filecreate_params filecreate_params;
257
#endif
258
/** Parameters threaded through file-creation callbacks (filenote). */
259
struct filecreate_params {
260
  FILE *lst; /**< open file list to append created paths to */
261
  char path[HTS_URLMAXSIZE * 2];
262
};
263
264
/* Convenience accessors over the link heap; assume `opt` (and where used,
265
   `ptr`/`parent_relative`/`module_base`) are in scope. heap(N) is the Nth link;
266
   heap_top_index() is the last recorded link's index. */
267
0
#define heap(N)            (opt->liens[N])
268
269
0
#define heap_top_index()   (opt->lien_tot - 1)
270
271
0
#define heap_top()         (heap(heap_top_index()))
272
273
0
#define urladr()           (heap(ptr)->adr)
274
275
0
#define urlfil()           (heap(ptr)->fil)
276
277
0
#define savename()         (heap(ptr)->sav)
278
279
0
#define parenturladr()     (heap(heap(ptr)->precedent)->adr)
280
281
0
#define parenturlfil()     (heap(heap(ptr)->precedent)->fil)
282
283
0
#define parentsavename()   (heap(heap(ptr)->precedent)->sav)
284
285
/* A module specifier takes the script's own base even in a .js document. */
286
0
#define relative_to_parent() (parent_relative && !module_base)
287
288
0
#define relativeurladr() ((!relative_to_parent()) ? urladr() : parenturladr())
289
290
0
#define relativeurlfil() ((!relative_to_parent()) ? urlfil() : parenturlfil())
291
292
#define relativesavename()                                                     \
293
0
  ((!relative_to_parent()) ? savename() : parentsavename())
294
295
/* Library-internal helpers (engine-only, HTS_INTERNAL_BYTECODE). */
296
#ifdef HTS_INTERNAL_BYTECODE
297
298
/* True if a new cache is being written (plain or zip backend). */
299
0
HTS_STATIC int cache_writable(cache_back * cache) {
300
0
  return (cache != NULL && cache->zipOutput != NULL);
301
0
}
Unexecuted instantiation: htslib.c:cache_writable
Unexecuted instantiation: htsfetch.c:cache_writable
Unexecuted instantiation: htswizard.c:cache_writable
Unexecuted instantiation: htshash.c:cache_writable
Unexecuted instantiation: htstools.c:cache_writable
Unexecuted instantiation: htscore.c:cache_writable
Unexecuted instantiation: htschanges.c:cache_writable
Unexecuted instantiation: htscache.c:cache_writable
Unexecuted instantiation: htsback.c:cache_writable
Unexecuted instantiation: htsftp.c:cache_writable
Unexecuted instantiation: htsname.c:cache_writable
Unexecuted instantiation: htscodec.c:cache_writable
Unexecuted instantiation: htszlib.c:cache_writable
Unexecuted instantiation: htswarc.c:cache_writable
Unexecuted instantiation: htsbundle.c:cache_writable
Unexecuted instantiation: htsbauth.c:cache_writable
Unexecuted instantiation: htspsl.c:cache_writable
Unexecuted instantiation: htscoremain.c:cache_writable
Unexecuted instantiation: htscatchurl.c:cache_writable
Unexecuted instantiation: htsproxy.c:cache_writable
Unexecuted instantiation: htsrobots.c:cache_writable
Unexecuted instantiation: htssitemap.c:cache_writable
Unexecuted instantiation: htsparse.c:cache_writable
Unexecuted instantiation: htssinglefile.c:cache_writable
Unexecuted instantiation: htsselftest.c:cache_writable
Unexecuted instantiation: htsback_selftest.c:cache_writable
Unexecuted instantiation: htsselftest_util.c:cache_writable
Unexecuted instantiation: htscache_selftest.c:cache_writable
Unexecuted instantiation: htscharset_selftest.c:cache_writable
Unexecuted instantiation: htscmdline_selftest.c:cache_writable
Unexecuted instantiation: htscookie_selftest.c:cache_writable
Unexecuted instantiation: htsdns_selftest.c:cache_writable
Unexecuted instantiation: htsfetch_selftest.c:cache_writable
Unexecuted instantiation: htspsl_selftest.c:cache_writable
Unexecuted instantiation: htsbundle_selftest.c:cache_writable
Unexecuted instantiation: htsfilters_selftest.c:cache_writable
Unexecuted instantiation: htsheader_selftest.c:cache_writable
Unexecuted instantiation: htsio_selftest.c:cache_writable
Unexecuted instantiation: htslib_selftest.c:cache_writable
Unexecuted instantiation: htslines_selftest.c:cache_writable
Unexecuted instantiation: htsmime_selftest.c:cache_writable
Unexecuted instantiation: htsname_selftest.c:cache_writable
Unexecuted instantiation: htsnet_selftest.c:cache_writable
Unexecuted instantiation: htsopt_selftest.c:cache_writable
Unexecuted instantiation: htsparse_selftest.c:cache_writable
Unexecuted instantiation: htstools_selftest.c:cache_writable
Unexecuted instantiation: htswarc_selftest.c:cache_writable
Unexecuted instantiation: htswizard_selftest.c:cache_writable
302
303
/* True if an old cache is available to read (plain or zip backend). */
304
0
HTS_STATIC int cache_readable(cache_back * cache) {
305
0
  return (cache != NULL && cache->zipInput != NULL);
306
0
}
Unexecuted instantiation: htslib.c:cache_readable
Unexecuted instantiation: htsfetch.c:cache_readable
Unexecuted instantiation: htswizard.c:cache_readable
Unexecuted instantiation: htshash.c:cache_readable
Unexecuted instantiation: htstools.c:cache_readable
Unexecuted instantiation: htscore.c:cache_readable
Unexecuted instantiation: htschanges.c:cache_readable
Unexecuted instantiation: htscache.c:cache_readable
Unexecuted instantiation: htsback.c:cache_readable
Unexecuted instantiation: htsftp.c:cache_readable
Unexecuted instantiation: htsname.c:cache_readable
Unexecuted instantiation: htscodec.c:cache_readable
Unexecuted instantiation: htszlib.c:cache_readable
Unexecuted instantiation: htswarc.c:cache_readable
Unexecuted instantiation: htsbundle.c:cache_readable
Unexecuted instantiation: htsbauth.c:cache_readable
Unexecuted instantiation: htspsl.c:cache_readable
Unexecuted instantiation: htscoremain.c:cache_readable
Unexecuted instantiation: htscatchurl.c:cache_readable
Unexecuted instantiation: htsproxy.c:cache_readable
Unexecuted instantiation: htsrobots.c:cache_readable
Unexecuted instantiation: htssitemap.c:cache_readable
Unexecuted instantiation: htsparse.c:cache_readable
Unexecuted instantiation: htssinglefile.c:cache_readable
Unexecuted instantiation: htsselftest.c:cache_readable
Unexecuted instantiation: htsback_selftest.c:cache_readable
Unexecuted instantiation: htsselftest_util.c:cache_readable
Unexecuted instantiation: htscache_selftest.c:cache_readable
Unexecuted instantiation: htscharset_selftest.c:cache_readable
Unexecuted instantiation: htscmdline_selftest.c:cache_readable
Unexecuted instantiation: htscookie_selftest.c:cache_readable
Unexecuted instantiation: htsdns_selftest.c:cache_readable
Unexecuted instantiation: htsfetch_selftest.c:cache_readable
Unexecuted instantiation: htspsl_selftest.c:cache_readable
Unexecuted instantiation: htsbundle_selftest.c:cache_readable
Unexecuted instantiation: htsfilters_selftest.c:cache_readable
Unexecuted instantiation: htsheader_selftest.c:cache_readable
Unexecuted instantiation: htsio_selftest.c:cache_readable
Unexecuted instantiation: htslib_selftest.c:cache_readable
Unexecuted instantiation: htslines_selftest.c:cache_readable
Unexecuted instantiation: htsmime_selftest.c:cache_readable
Unexecuted instantiation: htsname_selftest.c:cache_readable
Unexecuted instantiation: htsnet_selftest.c:cache_readable
Unexecuted instantiation: htsopt_selftest.c:cache_readable
Unexecuted instantiation: htsparse_selftest.c:cache_readable
Unexecuted instantiation: htstools_selftest.c:cache_readable
Unexecuted instantiation: htswarc_selftest.c:cache_readable
Unexecuted instantiation: htswizard_selftest.c:cache_readable
307
308
#endif
309
310
// Functions
311
312
/* Library-internal only (engine TUs). */
313
#ifdef HTS_INTERNAL_BYTECODE
314
315
char *hts_cancel_file_pop(httrackp * opt);
316
317
/* Detach the pending hts_addurl() list and give the caller ownership; NULL
318
   when none is pending. Free it with hts_addurl_free(). */
319
char **hts_addurl_take(httrackp *opt);
320
321
/* Free a list taken with hts_addurl_take(), strings included. */
322
void hts_addurl_free(char **url);
323
324
/* Detach the queued rules. Returns NULL if none. The caller frees the list
325
   with hts_addurl_free(). */
326
char **hts_addfilter_take(httrackp *opt);
327
328
/* Takes the list hts_setfilters() queued, like hts_addfilter_take(). */
329
char **hts_setfilters_take(httrackp *opt);
330
331
#endif
332
333
/* Has the -#L cap left fewer than two free slots? One parser step records
334
   robots.txt and then the link itself, so both must still fit. */
335
hts_boolean hts_maxlinks_no_room(const httrackp *opt);
336
337
/* Record a link on the heap. All strings are copied (caller keeps ownership).
338
   Returns 1 on success, 0 if the link limit (opt->maxlink) is reached. */
339
int hts_record_link(httrackp * opt,
340
                    const char *address, const char *file, const char *save,
341
                    const char *ref_address, const char *ref_file,
342
                    const char *codebase);
343
344
/* Index of the most recently recorded link. */
345
size_t hts_record_link_latest(httrackp *opt);
346
347
/* Mark link at index lpos as not to be processed (sets pass2 = -1). */
348
void hts_invalidate_link(httrackp * opt, int lpos);
349
350
/* Allocates the link heap if absent, and returns HTS_FALSE without memory. */
351
hts_boolean hts_record_init(httrackp *opt);
352
353
void hts_record_free(httrackp *opt);
354
355
/* Load the -%L file at path into *buff, NUL-terminated after its *size bytes,
356
   to be freed with freet(). Returns NULL, or why it could not be read, and then
357
   *buff is NULL. The reason may be written in errbuf, of HTS_STRERROR_SIZE
358
   bytes. */
359
const char *hts_urllist_load(const char *path, char **buff, size_t *size,
360
                             char *errbuf);
361
362
/* The size of the line buffer hts_urllist_next() fills. */
363
#define HTS_URLLIST_LINE_SIZE (HTS_URLMAXSIZE * 2)
364
365
typedef enum hts_urllist_status {
366
  HTS_URLLIST_END,  /* no line is left */
367
  HTS_URLLIST_LINE, /* line holds the next line */
368
  HTS_URLLIST_LONG, /* the line is longer than HTS_URLMAXSIZE bytes */
369
  HTS_URLLIST_NUL   /* the line holds a NUL byte */
370
} hts_urllist_status;
371
372
/* Read the next -%L line of buff at *pos, and move *pos past it. Returns how
373
   the line ended. line holds the head of a LONG or NUL line, which the crawl
374
   drops. */
375
hts_urllist_status hts_urllist_next(const char *buff, size_t size, size_t *pos,
376
                                    char line[HTS_URLLIST_LINE_SIZE]);
377
378
/* Run the mirror for the given start URL(s) under opt. Top-level engine entry.
379
   Returns 1 once the crawl loop ran, 0 or -1 for a bailout. *completed says
380
   whether it reached the end: false for a bailout, and for any stop that cut it
381
   short, however it arrived (state.stop or exit_xh). */
382
int httpmirror(char *url1, httrackp *opt, hts_boolean *completed);
383
384
/* Start the stats clock HTS_STAT.stat_timestart (seconds) and the --max-time
385
   clock hts_mirror_elapsed_ms(). */
386
void hts_mirror_clock_start(void);
387
388
/* Return the time since hts_mirror_clock_start(), in monotonic ms. */
389
TStamp hts_mirror_elapsed_ms(void);
390
391
/* Write len bytes of adr to local path s. url_adr/url_fil (may be NULL) name
392
   the source URL for logging/notification. */
393
int filesave(httrackp * opt, const char *adr, int len, const char *s,
394
             const char *url_adr /* = NULL */ ,
395
             const char *url_fil /* = NULL */ );
396
397
char *hts_cancel_file_pop(httrackp * opt);
398
399
int check_fatal_io_errno(void);
400
401
int engine_stats(void);
402
403
void host_ban(httrackp * opt, int ptr, struct_back * sback, const char *host);
404
405
/* Open local file s for writing (filecreate, truncate) or appending
406
   (fileappend), creating parent directories as needed. Return an open FILE*
407
   the caller must fclose(), or NULL on failure. */
408
FILE *filecreate(filenote_strc * strct, const char *s);
409
410
FILE *fileappend(filenote_strc * strct, const char *s);
411
412
/* Create an empty file, return 1 on success, 0 on failure. */
413
int filecreateempty(filenote_strc * strct, const char *filename);
414
415
int filenote(filenote_strc * strct, const char *s, filecreate_params * params);
416
417
/* Copy into dest (destsize bytes) the form under which the local path s is
418
   listed in new.lst: forward slashes, with the mirror `root` stripped when s
419
   sits under it. Also the change report's key, so the two must not drift. */
420
void hts_savename_listed(const char *root, const char *s, char *dest,
421
                         size_t destsize);
422
423
void file_notify(httrackp * opt, const char *adr, const char *fil,
424
                 const char *save, int create, int modify, int wasupdated);
425
426
void usercommand(httrackp * opt, int exe, const char *cmd, const char *file,
427
                 const char *adr, const char *fil);
428
429
/* usercommand_expand() verdicts; only OK may be run. */
430
0
#define USERCOMMAND_EXPAND_OK 1
431
0
#define USERCOMMAND_EXPAND_TOOLONG 0
432
0
#define USERCOMMAND_EXPAND_REFUSED (-1)
433
/* Rewrite a -V template's $0. On POSIX "file" is ignored: usercommand_exe()
434
   passes it to the shell as $1, so the rewrite does not depend on it. */
435
int usercommand_expand(char *dest, size_t size, const char *cmd,
436
                       const char *file, const char **why);
437
/* Run a -V template against a save name; returns the shell's exit status, or
438
   -1 when the command was not run at all. */
439
int usercommand_exe(httrackp *opt, const char *cmd, const char *file);
440
#ifndef _WIN32
441
/* Room for "sh", "-c", the command, the shell's $0, its $1 and the NULL. */
442
#define USERCOMMAND_ARGV_MAX 6
443
size_t usercommand_argv(char *argv[USERCOMMAND_ARGV_MAX], const char *command,
444
                        const char *file);
445
#endif
446
447
// Finish the makeindex index.html (footer + refresh meta), run usercommand.
448
// Updates *makeindex_done/*makeindex_fp in place; adr/fil are the mode strings.
449
void hts_finish_makeindex(httrackp *opt, int *makeindex_done,
450
                          FILE **makeindex_fp, int makeindex_links,
451
                          const char *makeindex_firstlink,
452
                          const char *template_footer, const char *adr,
453
                          const char *fil);
454
455
/* Re-encode 'size' bytes of UCS2 (UTF-16, BMP only) as UTF-8. 'swap' selects
456
   little-endian input, 'size' must be even. Returns a NUL-terminated buffer to
457
   release with freet(), its length (NUL excluded) in *outsize, or NULL when the
458
   result does not fit memory. */
459
char *hts_ucs2_to_utf8(const unsigned char *src, size_t size, hts_boolean swap,
460
                       size_t *outsize);
461
462
// Flush ht_buff[0..ht_len] to save on disk; *fp closed+NULLed on write.
463
// Precondition: ht_len>0.
464
void hts_finish_html_file(httrackp *opt, cache_back *cache, htsblk *r,
465
                          FILE **fp, const char *ht_buff, size_t ht_len,
466
                          const char *adr, const char *fil, const char *save);
467
468
/* Longest suffix a rule builder appends after the path (the wizard's
469
   "*[file]"), NUL included; asserted against in htswizard.c. */
470
0
#define HTS_FILTER_SUFFIX_MAX 8
471
472
/* Per-slot capacity of the filters array; filters_init() strides the slots by
473
   it. Holds the longest rule any builder emits, because truncating one changes
474
   what it matches. */
475
#define HTS_FILTER_SLOT_SIZE                                                   \
476
0
  (1 + (HTS_URLMAXSIZE * 2 - 1) + 1 + (HTS_URLMAXSIZE * 2 - 1) +               \
477
0
   HTS_FILTER_SUFFIX_MAX)
478
479
/* Largest -#F, and the largest filter list that may still grow by
480
   HTS_FILTERSINC, because the list's byte size must fit an int. */
481
0
#define HTS_FILTERS_MAX (INT_MAX / HTS_FILTER_SLOT_SIZE - HTS_FILTERSINC - 2)
482
483
int filters_init(char ***ptrfilters, int maxfilter, int filterinc);
484
485
/* Binds this crawl's filter array to `opt`, and empties the wizard block with
486
   it: opt->wizard_filters indexes into that array and outlives no crawl. */
487
void filters_bind(httrackp *opt, char ***ptrfilters, int *filptr);
488
489
/* Longest rule a slot holds and the matcher still looks at. */
490
#define HTS_FILTER_MAXLEN                                                      \
491
0
  (HTS_FILTER_SLOT_SIZE - 1 < STRJOKER_MAXLEN ? HTS_FILTER_SLOT_SIZE - 1       \
492
0
                                              : STRJOKER_MAXLEN)
493
494
/* Stores `pattern` at `pos`, shifting the rules from there up a slot. The one
495
   door into the array: a rule past HTS_FILTER_MAXLEN, or one that finds the
496
   array full, warns and returns HTS_FALSE, never stored dead (#1270). */
497
hts_boolean filters_insert(httrackp *opt, int pos, const char *pattern);
498
499
/* Remove the n rules starting at pos, shifting the rest down. */
500
void filters_remove(httrackp *opt, int pos, int n);
501
502
/* Can a filter array of maxfilter rules grow by HTS_FILTERSINC? */
503
hts_boolean filters_may_grow(int maxfilter);
504
505
/* Makes room for n more rules. Returns HTS_FALSE, having logged it, only when
506
   memory runs out. At the HTS_FILTERS_MAX cap it returns HTS_TRUE and
507
   filters_insert() drops what does not fit. */
508
hts_boolean filters_grow(httrackp *opt, int n);
509
510
/* Same as filters_grow(), but aborts when memory runs out. */
511
void filters_make_room(httrackp *opt, int n);
512
513
/* Returns the fa_strjoker_dual() verdict of the nfil filters on adr+fil, in
514
   both forms the wizard tests, and sets *depth when depth is not NULL. */
515
int filters_match_url(char **filters, int nfil, const char *adr,
516
                      const char *fil, int *depth);
517
518
/* Apply the queued list and rules to the user's rules, then drop the queued
519
   links after ptr that the change makes them refuse. Crawl thread only, as it
520
   alone reads the filters. */
521
void hts_apply_live_filters(httrackp *opt, struct_back *sback, int ptr);
522
523
int fspc(httrackp * opt, FILE * fp, const char *type);
524
/* Count one log event into opt's counters that hts_get_stats() publishes,
525
   whether or not a log file is open. "panic" counts as an error. */
526
void fspc_count(httrackp *opt, const char *type);
527
528
/* Like fil_normalized(), but first drops query keys in STRIP (comma-separated,
529
   "*" = all); STRIP NULL/empty behaves exactly like fil_normalized(). */
530
char *fil_normalized_filtered(const char *source, char *dest,
531
                              const char *strip);
532
533
/* As fil_normalized_filtered(), but DO_SLASH/DO_QUERY gate the // collapse and
534
   the query-argument sort independently (the urlhack sub-flags). */
535
char *fil_normalized_filtered_ex(const char *source, char *dest,
536
                                 const char *strip, int do_slash, int do_query);
537
538
/* For URL ADR/FIL, return (in DEST) the comma keylist to strip from the
539
   '\n'-separated "[pattern=]keys" RULES (patterns matched on host/path via
540
   strjoker, last wins); NULL if none match. Feeds fil_normalized_filtered(). */
541
const char *hts_query_strip_keys(const char *rules, const char *adr,
542
                                 const char *fil, char *dest, size_t destsize);
543
544
/* Is the key ARG[0..KEYLEN) in the comma list STRIP? Tokens are space-trimmed
545
   and case-sensitive, and "*" matches any key. */
546
hts_boolean hts_query_key_stripped(const char *arg, size_t keylen,
547
                                   const char *strip);
548
549
/* Return the canonical host (length *CANONLEN) of the last RULES entry whose
550
   aliases match HOST or FULL ("scheme://host"), or NULL. COLLAPSE_WWW ignores
551
   a "www." prefix on both sides. */
552
const char *hts_host_alias_match(const char *rules, const char *host,
553
                                 const char *full, hts_boolean collapse_www,
554
                                 size_t *canonlen);
555
556
/* The --host-alias rules of OPT, or NULL when the option was not given. */
557
const char *hts_host_alias_rules(httrackp *opt);
558
559
/* ADR with its host replaced by the canonical one, from the '\n'-separated
560
   "alias[,alias...]=canonical" RULES (aliases matched with strjoker, last
561
   wins). NOWWW matches the host with its www. prefix collapsed, as -%u keys it.
562
   Chains are followed to their end, so the result is a fixpoint. Scheme and
563
   credentials are kept. NULL when no rule applies, the mapping is a no-op, the
564
   rules loop, or the result would not fit DEST. */
565
const char *hts_host_alias(const char *rules, const char *adr,
566
                           hts_boolean collapse_www, char *dest,
567
                           size_t destsize);
568
569
/* Resolve like hts_host_alias, and set *SETTLED, when SETTLED is not NULL, to
570
   whether the chain ended within the hop limit. Exposed for the -#test=spandiff
571
   test. */
572
const char *hts_host_alias_resolve(const char *rules, const char *adr,
573
                                   hts_boolean collapse_www, char *dest,
574
                                   size_t destsize, hts_boolean *settled);
575
576
/* HTS_TRUE when OPT's url hacks collapse www.host onto host. */
577
hts_boolean hts_host_alias_collapse_www(httrackp *opt);
578
579
/* Rewrite AF's host to its --host-alias canonical form, in place, and return
580
   it. Idempotent; returns af->adr unchanged when no rule applies. */
581
const char *hts_host_alias_fold(httrackp *opt, lien_adrfil *af);
582
583
/* HTS_TRUE if ADRA and ADRB name the same host once RULES are applied. */
584
hts_boolean hts_host_same_alias(const char *rules, const char *adra,
585
                                const char *adrb, hts_boolean collapse_www);
586
587
/* First canonical host in RULES whose chain never ends ("a=b" plus "b=a"),
588
   copied into DEST, or NULL if every chain settles. Those hosts are left
589
   unaliased, so the engine reports them rather than picking a hop. */
590
const char *hts_host_alias_looping(const char *rules, hts_boolean collapse_www,
591
                                   char *dest, size_t destsize);
592
593
/* Read a whole file into a freshly malloc'd, NUL-terminated buffer; the caller
594
   owns it and must release it with freet(). Return NULL on missing/unreadable
595
   file (readfile_or substitutes defaultdata instead). The byte content is NOT
596
   transcoded except readfile_utf8, which expects a UTF-8 path. readfile2
597
   reports the byte size (excluding the NUL) via *size when non-NULL. */
598
char *readfile(const char *fil);
599
600
char *readfile2(const char *fil, LLint * size);
601
602
/* readfile2() refusing a body too large for the int indexes downstream, on the
603
   same stat that sizes the read: a caller checking the size itself would leave
604
   a window for the file to grow. NULL when it does not fit. "fil" is UTF-8,
605
   as a mirror path is. */
606
char *readfile2_inmem(const char *fil, LLint *size);
607
608
char *readfile_utf8(const char *fil);
609
610
char *readfile2_utf8(const char *fil, LLint *size);
611
612
char *readfile_or(const char *fil, const char *defaultdata);
613
614
/* Backing (download-slot) scheduler. Operate on the back[] ring (struct_back).
615
   Not thread-safe; call from the single crawl loop. */
616
617
/* True if a connecting slot should give up on the current address and try the
618
   next one: a fallback address remains (addr_index+1 < addr_count) and the
619
   candidate has been connecting for at least its deadline, min(timeout, an
620
   internal cap). elapsed/timeout in seconds. Exposed for the -#D self-test. */
621
int back_connect_fallback_due(int addr_index, int addr_count, int elapsed,
622
                              int timeout);
623
624
/* How many new sockets may be opened now, honoring maxsoc and the maxconn rate
625
   limit (>=0). _strict ignores reserved-slot headroom; the plain form leaves
626
   room for naming tests and stops at 0 when the stack is nearly full. */
627
int back_pluggable_sockets(struct_back * sback, httrackp * opt);
628
629
int back_pluggable_sockets_strict(struct_back * sback, httrackp * opt);
630
631
/* One engine-loop tick: refresh the transfer stats and run the loop callback
632
   for slot b (-1 = none). HTS_FALSE = the callback requested an abort. */
633
hts_boolean hts_loop_tick(struct_back *sback, httrackp *opt, int b, int ptr);
634
635
/* Wait until a test socket can be plugged, pumping transfers, stats and the
636
   loop callback; gives up past the -E deadline. HTS_FALSE = callback abort. */
637
hts_boolean hts_wait_available_socket(struct_back *sback, httrackp *opt,
638
                                      cache_back *cache, int ptr);
639
640
/* Randomized inter-file pause target in [min_ms,max_ms] (#185), derived from a
641
   timestamp seed so it is stable within one gap and rerolls per launch. */
642
int hts_pause_target_ms(TStamp seed, int min_ms, int max_ms);
643
644
/* Withhold every new launch for `seconds`, clipped to opt->max_retry_after.
645
   A hold already running further out is kept. */
646
void back_set_retry_after(struct_back *sback, httrackp *opt, int seconds);
647
648
/* Schedule more links from the heap into free slots. Returns the number queued,
649
   or <=0 if none could be added (no free slot / paused / stopped). */
650
int back_fill(struct_back * sback, httrackp * opt, cache_back * cache,
651
              int ptr, int numero_passe);
652
653
/* Count of links already finished (in background or served from cache). */
654
int backlinks_done(const struct_back *sback, lien_url **liens, int lien_tot,
655
                   int ptr);
656
657
/* Like back_fill, but a no-op (returns -1) when in-memory buffered data already
658
   exceeds opt->maxcache. */
659
int back_fillmax(struct_back * sback, httrackp * opt, cache_back * cache,
660
                 int ptr, int numero_passe);
661
662
/* Interactive prompt: continue an interrupted mirror? Returns nonzero to go on.
663
 */
664
int ask_continue(httrackp * opt);
665
666
/* Number of decimal digits in n. */
667
int nombre_digit(int n);
668
669
// Polling
670
#if HTS_POLL
671
int check_flot(T_SOC s);
672
673
int check_stdin(void);
674
#endif
675
/* Nonzero if the socket has a pending error. */
676
int check_sockerror(T_SOC s);
677
678
/* external modules: register a link discovered by a parser plugin. */
679
int htsAddLink(htsmoduleStruct * str, char *link);
680
681
/* Worst-case byte expansion HT_ADD_HTMLESCAPED* must reserve per escaper. */
682
0
#define HTS_HTMLESCAPE_MAXEXP 5      /* escape_for_html_print: '&'->"&amp;" */
683
0
#define HTS_HTMLESCAPE_FULL_MAXEXP 6 /* _full: high byte->"&#xHH;" */
684
685
#endif