Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Sync with trunk. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | diff-word-wrap |
| Files: | files | file ages | folders |
| SHA3-256: |
a0377ebb9d1bb4740606d9b63742c072 |
| User & Date: | florian 2025-08-21 12:07:00.000 |
Context
|
2025-09-26
| ||
| 12:57 | Sync with trunk. check-in: 779fe3e1b2 user: florian tags: diff-word-wrap | |
|
2025-08-21
| ||
| 12:07 | Sync with trunk. check-in: a0377ebb9d user: florian tags: diff-word-wrap | |
| 12:02 | Change [3710202914] to call the function to load the diff-related JS code even for blocked diffs. By default, the loader function is already a no-op if diffs are blocked, so the behavior intended by [3710202914] is retained. But other branches are patching the loader function because they rely on the JS code even if the diffs are hidden. check-in: 171127fd14 user: florian tags: trunk | |
|
2025-07-21
| ||
| 12:20 | Sync with trunk. check-in: 931e7065bb user: florian tags: diff-word-wrap | |
Changes
Changes to extsrc/shell.c.
| ︙ | ︙ | |||
120 121 122 123 124 125 126 127 128 129 130 131 132 133 | #include <math.h> #include "sqlite3.h" typedef sqlite3_int64 i64; typedef sqlite3_uint64 u64; typedef unsigned char u8; #include <ctype.h> #include <stdarg.h> #if !defined(_WIN32) && !defined(WIN32) # include <signal.h> # if !defined(__RTP__) && !defined(_WRS_KERNEL) && !defined(SQLITE_WASI) # include <pwd.h> # endif #endif | > > > | 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | #include <math.h> #include "sqlite3.h" typedef sqlite3_int64 i64; typedef sqlite3_uint64 u64; typedef unsigned char u8; #include <ctype.h> #include <stdarg.h> #ifndef _WIN32 # include <sys/time.h> #endif #if !defined(_WIN32) && !defined(WIN32) # include <signal.h> # if !defined(__RTP__) && !defined(_WRS_KERNEL) && !defined(SQLITE_WASI) # include <pwd.h> # endif #endif |
| ︙ | ︙ | |||
644 645 646 647 648 649 650 |
}
static int cli_strncmp(const char *a, const char *b, size_t n){
if( a==0 ) a = "";
if( b==0 ) b = "";
return strncmp(a,b,n);
}
| | > > < > | < > > > > > | < < | < | | < | > | 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 |
}
static int cli_strncmp(const char *a, const char *b, size_t n){
if( a==0 ) a = "";
if( b==0 ) b = "";
return strncmp(a,b,n);
}
/* Return the current wall-clock time in microseconds since the
** Unix epoch (1970-01-01T00:00:00Z)
*/
static sqlite3_int64 timeOfDay(void){
#if defined(_WIN32)
sqlite3_uint64 t;
FILETIME tm;
GetSystemTimePreciseAsFileTime(&tm);
t = ((u64)tm.dwHighDateTime<<32) | (u64)tm.dwLowDateTime;
t += 116444736000000000LL;
t /= 10;
return t;
#else
struct timeval sNow;
(void)gettimeofday(&sNow,0);
return ((i64)sNow.tv_sec)*1000000 + sNow.tv_usec;
#endif
}
#if !defined(_WIN32) && !defined(WIN32) && !defined(__minux)
#include <sys/time.h>
#include <sys/resource.h>
/* VxWorks does not support getrusage() as far as we can determine */
|
| ︙ | ︙ | |||
702 703 704 705 706 707 708 |
** Print the timing results.
*/
static void endTimer(FILE *out){
if( enableTimer ){
sqlite3_int64 iEnd = timeOfDay();
struct rusage sEnd;
getrusage(RUSAGE_SELF, &sEnd);
| | | | 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 |
** Print the timing results.
*/
static void endTimer(FILE *out){
if( enableTimer ){
sqlite3_int64 iEnd = timeOfDay();
struct rusage sEnd;
getrusage(RUSAGE_SELF, &sEnd);
sqlite3_fprintf(out, "Run Time: real %.6f user %f sys %f\n",
(iEnd - iBegin)*0.000001,
timeDiff(&sBegin.ru_utime, &sEnd.ru_utime),
timeDiff(&sBegin.ru_stime, &sEnd.ru_stime));
}
}
#define BEGIN_TIMER beginTimer()
#define END_TIMER(X) endTimer(X)
|
| ︙ | ︙ | |||
781 782 783 784 785 786 787 |
** Print the timing results.
*/
static void endTimer(FILE *out){
if( enableTimer && getProcessTimesAddr){
FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd;
sqlite3_int64 ftWallEnd = timeOfDay();
getProcessTimesAddr(hProcess,&ftCreation,&ftExit,&ftKernelEnd,&ftUserEnd);
| | | | 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 |
** Print the timing results.
*/
static void endTimer(FILE *out){
if( enableTimer && getProcessTimesAddr){
FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd;
sqlite3_int64 ftWallEnd = timeOfDay();
getProcessTimesAddr(hProcess,&ftCreation,&ftExit,&ftKernelEnd,&ftUserEnd);
sqlite3_fprintf(out, "Run Time: real %.6f user %f sys %f\n",
(ftWallEnd - ftWallBegin)*0.000001,
timeDiff(&ftUserBegin, &ftUserEnd),
timeDiff(&ftKernelBegin, &ftKernelEnd));
}
}
#define BEGIN_TIMER beginTimer()
#define END_TIMER(X) endTimer(X)
|
| ︙ | ︙ | |||
32886 32887 32888 32889 32890 32891 32892 |
home_dir = z;
}
return home_dir;
}
/*
| | > > | > > | < > > | > > > > > > > > | | | > | | | | > > | > | < | | | | | | | | | > > | > | < | > > | | < | > | > | 32892 32893 32894 32895 32896 32897 32898 32899 32900 32901 32902 32903 32904 32905 32906 32907 32908 32909 32910 32911 32912 32913 32914 32915 32916 32917 32918 32919 32920 32921 32922 32923 32924 32925 32926 32927 32928 32929 32930 32931 32932 32933 32934 32935 32936 32937 32938 32939 32940 32941 32942 32943 32944 32945 32946 32947 32948 32949 32950 32951 32952 32953 32954 32955 32956 32957 32958 32959 32960 32961 32962 32963 32964 32965 32966 32967 32968 32969 32970 32971 32972 32973 32974 32975 32976 32977 32978 32979 32980 32981 32982 32983 32984 32985 32986 32987 32988 32989 32990 32991 32992 32993 32994 32995 32996 32997 32998 32999 33000 33001 33002 33003 33004 33005 |
home_dir = z;
}
return home_dir;
}
/*
** On non-Windows platforms, look for:
**
** - ${zEnvVar}/${zBaseName}
** - ${HOME}/${zSubdir}/${zBaseName}
**
** $zEnvVar is intended to be the name of an XDG_... environment
** variable, e.g. XDG_CONFIG_HOME or XDG_STATE_HOME. If zEnvVar is
** NULL or getenv(zEnvVar) is NULL then fall back to the second
** option. If the selected option is not found in the filesystem,
** return 0.
**
** zSubdir may be NULL or empty, in which case ${HOME}/${zBaseName}
** becomes the fallback.
**
** Both zSubdir and zBaseName may contain subdirectory parts. zSubdir
** will conventionally be ".config" or ".local/state", which, not
** coincidentally, is the typical subdir of the corresponding XDG_...
** var with the XDG var's $HOME prefix.
**
** The returned string is obtained from sqlite3_malloc() and should be
** sqlite3_free()'d by the caller.
*/
static char *find_xdg_file(const char *zEnvVar, const char *zSubdir,
const char *zBaseName){
#if defined(_WIN32) || defined(WIN32) || defined(_WIN32_WCE) \
|| defined(__RTP__) || defined(_WRS_KERNEL)
return 0;
#else
char *zConfigFile = 0;
const char *zXdgDir;
zXdgDir = zEnvVar ? getenv(zEnvVar) : 0;
if( zXdgDir ){
zConfigFile = sqlite3_mprintf("%s/%s", zXdgDir, zBaseName);
}else{
const char * zHome = find_home_dir(0);
if( zHome==0 ) return 0;
zConfigFile = (zSubdir && *zSubdir)
? sqlite3_mprintf("%s/%s/%s", zHome, zSubdir, zBaseName)
: sqlite3_mprintf("%s/%s", zHome, zBaseName);
}
shell_check_oom(zConfigFile);
if( access(zConfigFile,0)!=0 ){
sqlite3_free(zConfigFile);
zConfigFile = 0;
}
return zConfigFile;
#endif
}
/*
** Read input from the file sqliterc_override. If that parameter is
** NULL, take it from find_xdg_file(), if found, or fall back to
** ~/.sqliterc.
**
** Failure to read the config is only considered a failure if
** sqliterc_override is not NULL, in which case this function may emit
** a warning or, if ::bail_on_error is true, fail fatally if the file
** named by sqliterc_override is not found.
*/
static void process_sqliterc(
ShellState *p, /* Configuration data */
const char *sqliterc_override /* Name of config file. NULL to use default */
){
char *home_dir = NULL;
char *sqliterc = (char*)sqliterc_override;
FILE *inSaved = p->in;
int savedLineno = p->lineno;
if( sqliterc == NULL ){
sqliterc = find_xdg_file("XDG_CONFIG_HOME",
".config",
"sqlite3/sqliterc");
}
if( sqliterc == NULL ){
home_dir = find_home_dir(0);
if( home_dir==0 ){
eputz("-- warning: cannot find home directory;"
" cannot read ~/.sqliterc\n");
return;
}
sqliterc = sqlite3_mprintf("%s/.sqliterc",home_dir);
shell_check_oom(sqliterc);
}
p->in = sqliterc ? sqlite3_fopen(sqliterc,"rb") : 0;
if( p->in ){
if( stdin_is_interactive ){
sqlite3_fprintf(stderr,"-- Loading resources from %s\n", sqliterc);
}
if( process_input(p) && bail_on_error ) exit(1);
fclose(p->in);
}else if( sqliterc_override!=0 ){
sqlite3_fprintf(stderr,"cannot open: \"%s\"\n", sqliterc);
if( bail_on_error ) exit(1);
}
p->in = inSaved;
p->lineno = savedLineno;
if( sqliterc != sqliterc_override ){
sqlite3_free(sqliterc);
}
}
/*
** Show available command line options
*/
static const char zOptions[] =
" -- treat no subsequent arguments as options\n"
|
| ︙ | ︙ | |||
33732 33733 33734 33735 33736 33737 33738 |
}
}else{
/* Run commands received from standard input
*/
if( stdin_is_interactive ){
char *zHome;
char *zHistory;
| < > | | | > | > | > | | 33759 33760 33761 33762 33763 33764 33765 33766 33767 33768 33769 33770 33771 33772 33773 33774 33775 33776 33777 33778 33779 33780 33781 33782 33783 33784 33785 33786 33787 33788 33789 33790 33791 33792 33793 33794 33795 33796 33797 33798 33799 33800 33801 33802 33803 33804 33805 33806 33807 33808 33809 |
}
}else{
/* Run commands received from standard input
*/
if( stdin_is_interactive ){
char *zHome;
char *zHistory;
sqlite3_fprintf(stdout,
"SQLite version %s %.19s\n" /*extra-version-info*/
"Enter \".help\" for usage hints.\n",
sqlite3_libversion(), sqlite3_sourceid());
if( warnInmemoryDb ){
sputz(stdout, "Connected to a ");
printBold("transient in-memory database");
sputz(stdout, ".\nUse \".open FILENAME\" to reopen on a"
" persistent database.\n");
}
zHistory = getenv("SQLITE_HISTORY");
if( zHistory ){
zHistory = sqlite3_mprintf("%s", zHistory);
shell_check_oom(zHistory);
}else{
zHistory = find_xdg_file("XDG_STATE_HOME",
".local/state",
"sqlite_history");
if( 0==zHistory && (zHome = find_home_dir(0))!=0 ){
zHistory = sqlite3_mprintf("%s/.sqlite_history", zHome);
shell_check_oom(zHistory);
}
}
if( zHistory ){ shell_read_history(zHistory); }
#if (HAVE_READLINE || HAVE_EDITLINE) && !defined(SQLITE_OMIT_READLINE_COMPLETION)
rl_attempted_completion_function = readline_completion;
#elif HAVE_LINENOISE==1
linenoiseSetCompletionCallback(linenoise_completion);
#elif HAVE_LINENOISE==2
linenoiseSetCompletionCallback(linenoise_completion, NULL);
#endif
data.in = 0;
rc = process_input(&data);
if( zHistory ){
shell_stifle_history(2000);
shell_write_history(zHistory);
sqlite3_free(zHistory);
}
}else{
data.in = stdin;
rc = process_input(&data);
}
}
#ifndef SQLITE_SHELL_FIDDLE
|
| ︙ | ︙ |
Changes to extsrc/sqlite3.c.
| ︙ | ︙ | |||
14 15 16 17 18 19 20 | ** the text of this file. Search for "Begin file sqlite3.h" to find the start ** of the embedded sqlite3.h header file.) Additional code files may be needed ** if you want a wrapper to interface SQLite with your choice of programming ** language. The code for the "sqlite3" command-line shell is also in a ** separate file. This file contains only code for the core SQLite library. ** ** The content in this amalgamation comes from Fossil check-in | | | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | ** the text of this file. Search for "Begin file sqlite3.h" to find the start ** of the embedded sqlite3.h header file.) Additional code files may be needed ** if you want a wrapper to interface SQLite with your choice of programming ** language. The code for the "sqlite3" command-line shell is also in a ** separate file. This file contains only code for the core SQLite library. ** ** The content in this amalgamation comes from Fossil check-in ** cf7163f82ca380958a79350473b2c5a2cebd with changes in files: ** ** */ #ifndef SQLITE_AMALGAMATION #define SQLITE_CORE 1 #define SQLITE_AMALGAMATION 1 #ifndef SQLITE_PRIVATE |
| ︙ | ︙ | |||
463 464 465 466 467 468 469 | ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.51.0" #define SQLITE_VERSION_NUMBER 3051000 | | | 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 | ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.51.0" #define SQLITE_VERSION_NUMBER 3051000 #define SQLITE_SOURCE_ID "2025-07-30 16:17:14 cf7163f82ca380958a79350473b2c5a2cebda7496d6d575fa2835c362010fea1" /* ** CAPI3REF: Run-Time Library Version Numbers ** KEYWORDS: sqlite3_version sqlite3_sourceid ** ** These interfaces provide the same information as the [SQLITE_VERSION], ** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros |
| ︙ | ︙ | |||
812 813 814 815 816 817 818 819 820 821 822 823 824 825 | ** [sqlite3_extended_result_codes()] API. Or, the extended code for ** the most recent error can be obtained using ** [sqlite3_extended_errcode()]. */ #define SQLITE_ERROR_MISSING_COLLSEQ (SQLITE_ERROR | (1<<8)) #define SQLITE_ERROR_RETRY (SQLITE_ERROR | (2<<8)) #define SQLITE_ERROR_SNAPSHOT (SQLITE_ERROR | (3<<8)) #define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8)) #define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8)) #define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3<<8)) #define SQLITE_IOERR_FSYNC (SQLITE_IOERR | (4<<8)) #define SQLITE_IOERR_DIR_FSYNC (SQLITE_IOERR | (5<<8)) #define SQLITE_IOERR_TRUNCATE (SQLITE_IOERR | (6<<8)) #define SQLITE_IOERR_FSTAT (SQLITE_IOERR | (7<<8)) | > > > | 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 | ** [sqlite3_extended_result_codes()] API. Or, the extended code for ** the most recent error can be obtained using ** [sqlite3_extended_errcode()]. */ #define SQLITE_ERROR_MISSING_COLLSEQ (SQLITE_ERROR | (1<<8)) #define SQLITE_ERROR_RETRY (SQLITE_ERROR | (2<<8)) #define SQLITE_ERROR_SNAPSHOT (SQLITE_ERROR | (3<<8)) #define SQLITE_ERROR_RESERVESIZE (SQLITE_ERROR | (4<<8)) #define SQLITE_ERROR_KEY (SQLITE_ERROR | (5<<8)) #define SQLITE_ERROR_UNABLE (SQLITE_ERROR | (6<<8)) #define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8)) #define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8)) #define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3<<8)) #define SQLITE_IOERR_FSYNC (SQLITE_IOERR | (4<<8)) #define SQLITE_IOERR_DIR_FSYNC (SQLITE_IOERR | (5<<8)) #define SQLITE_IOERR_TRUNCATE (SQLITE_IOERR | (6<<8)) #define SQLITE_IOERR_FSTAT (SQLITE_IOERR | (7<<8)) |
| ︙ | ︙ | |||
846 847 848 849 850 851 852 853 854 855 856 857 858 859 | #define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28<<8)) #define SQLITE_IOERR_BEGIN_ATOMIC (SQLITE_IOERR | (29<<8)) #define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30<<8)) #define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8)) #define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8)) #define SQLITE_IOERR_CORRUPTFS (SQLITE_IOERR | (33<<8)) #define SQLITE_IOERR_IN_PAGE (SQLITE_IOERR | (34<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) #define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) #define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8)) #define SQLITE_BUSY_TIMEOUT (SQLITE_BUSY | (3<<8)) #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) #define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8)) | > > | 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 | #define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28<<8)) #define SQLITE_IOERR_BEGIN_ATOMIC (SQLITE_IOERR | (29<<8)) #define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30<<8)) #define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8)) #define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8)) #define SQLITE_IOERR_CORRUPTFS (SQLITE_IOERR | (33<<8)) #define SQLITE_IOERR_IN_PAGE (SQLITE_IOERR | (34<<8)) #define SQLITE_IOERR_BADKEY (SQLITE_IOERR | (35<<8)) #define SQLITE_IOERR_CODEC (SQLITE_IOERR | (36<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) #define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) #define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8)) #define SQLITE_BUSY_TIMEOUT (SQLITE_BUSY | (3<<8)) #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) #define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8)) |
| ︙ | ︙ | |||
19501 19502 19503 19504 19505 19506 19507 19508 19509 19510 19511 19512 19513 19514 |
int iOfst; /* else: start of token from start of statement */
} w;
AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */
union {
Table *pTab; /* TK_COLUMN: Table containing column. Can be NULL
** for a column of an index on an expression */
Window *pWin; /* EP_WinFunc: Window/Filter defn for a function */
struct { /* TK_IN, TK_SELECT, and TK_EXISTS */
int iAddr; /* Subroutine entry address */
int regReturn; /* Register used to hold return address */
} sub;
} y;
};
| > | 19506 19507 19508 19509 19510 19511 19512 19513 19514 19515 19516 19517 19518 19519 19520 |
int iOfst; /* else: start of token from start of statement */
} w;
AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */
union {
Table *pTab; /* TK_COLUMN: Table containing column. Can be NULL
** for a column of an index on an expression */
Window *pWin; /* EP_WinFunc: Window/Filter defn for a function */
int nReg; /* TK_NULLS: Number of registers to NULL out */
struct { /* TK_IN, TK_SELECT, and TK_EXISTS */
int iAddr; /* Subroutine entry address */
int regReturn; /* Register used to hold return address */
} sub;
} y;
};
|
| ︙ | ︙ | |||
21538 21539 21540 21541 21542 21543 21544 21545 21546 21547 21548 21549 21550 21551 | SQLITE_PRIVATE void sqlite3ExprCode(Parse*, Expr*, int); #ifndef SQLITE_OMIT_GENERATED_COLUMNS SQLITE_PRIVATE void sqlite3ExprCodeGeneratedColumn(Parse*, Table*, Column*, int); #endif SQLITE_PRIVATE void sqlite3ExprCodeCopy(Parse*, Expr*, int); SQLITE_PRIVATE void sqlite3ExprCodeFactorable(Parse*, Expr*, int); SQLITE_PRIVATE int sqlite3ExprCodeRunJustOnce(Parse*, Expr*, int); SQLITE_PRIVATE int sqlite3ExprCodeTemp(Parse*, Expr*, int*); SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse*, Expr*, int); SQLITE_PRIVATE int sqlite3ExprCodeExprList(Parse*, ExprList*, int, int, u8); #define SQLITE_ECEL_DUP 0x01 /* Deep, not shallow copies */ #define SQLITE_ECEL_FACTOR 0x02 /* Factor out constant terms */ #define SQLITE_ECEL_REF 0x04 /* Use ExprList.u.x.iOrderByCol */ #define SQLITE_ECEL_OMITREF 0x08 /* Omit if ExprList.u.x.iOrderByCol */ | > | 21544 21545 21546 21547 21548 21549 21550 21551 21552 21553 21554 21555 21556 21557 21558 | SQLITE_PRIVATE void sqlite3ExprCode(Parse*, Expr*, int); #ifndef SQLITE_OMIT_GENERATED_COLUMNS SQLITE_PRIVATE void sqlite3ExprCodeGeneratedColumn(Parse*, Table*, Column*, int); #endif SQLITE_PRIVATE void sqlite3ExprCodeCopy(Parse*, Expr*, int); SQLITE_PRIVATE void sqlite3ExprCodeFactorable(Parse*, Expr*, int); SQLITE_PRIVATE int sqlite3ExprCodeRunJustOnce(Parse*, Expr*, int); SQLITE_PRIVATE void sqlite3ExprNullRegisterRange(Parse*, int, int); SQLITE_PRIVATE int sqlite3ExprCodeTemp(Parse*, Expr*, int*); SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse*, Expr*, int); SQLITE_PRIVATE int sqlite3ExprCodeExprList(Parse*, ExprList*, int, int, u8); #define SQLITE_ECEL_DUP 0x01 /* Deep, not shallow copies */ #define SQLITE_ECEL_FACTOR 0x02 /* Factor out constant terms */ #define SQLITE_ECEL_REF 0x04 /* Use ExprList.u.x.iOrderByCol */ #define SQLITE_ECEL_OMITREF 0x08 /* Omit if ExprList.u.x.iOrderByCol */ |
| ︙ | ︙ | |||
24364 24365 24366 24367 24368 24369 24370 | #ifdef SQLITE_DEBUG SQLITE_PRIVATE void sqlite3VdbeMemAboutToChange(Vdbe*,Mem*); SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem*); #endif #ifndef SQLITE_OMIT_FOREIGN_KEY | | > | > | 24371 24372 24373 24374 24375 24376 24377 24378 24379 24380 24381 24382 24383 24384 24385 24386 24387 24388 24389 | #ifdef SQLITE_DEBUG SQLITE_PRIVATE void sqlite3VdbeMemAboutToChange(Vdbe*,Mem*); SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem*); #endif #ifndef SQLITE_OMIT_FOREIGN_KEY SQLITE_PRIVATE int sqlite3VdbeCheckFkImmediate(Vdbe*); SQLITE_PRIVATE int sqlite3VdbeCheckFkDeferred(Vdbe*); #else # define sqlite3VdbeCheckFkImmediate(p) 0 # define sqlite3VdbeCheckFkDeferred(p) 0 #endif #ifdef SQLITE_DEBUG SQLITE_PRIVATE void sqlite3VdbePrintSql(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeMemPrettyPrint(Mem *pMem, StrAccum *pStr); #endif #ifndef SQLITE_OMIT_UTF16 |
| ︙ | ︙ | |||
32250 32251 32252 32253 32254 32255 32256 |
bufpt++;
}
length = sqlite3Strlen30(bufpt);
break;
}
}
if( s.sign=='-' ){
| > > > > > > > > > > > > > | > | 32259 32260 32261 32262 32263 32264 32265 32266 32267 32268 32269 32270 32271 32272 32273 32274 32275 32276 32277 32278 32279 32280 32281 32282 32283 32284 32285 32286 32287 |
bufpt++;
}
length = sqlite3Strlen30(bufpt);
break;
}
}
if( s.sign=='-' ){
if( flag_alternateform
&& !flag_prefix
&& xtype==etFLOAT
&& s.iDP<=iRound
){
/* Suppress the minus sign if all of the following are true:
** * The value displayed is zero
** * The '#' flag is used
** * The '+' flag is not used, and
** * The format is %f
*/
prefix = 0;
}else{
prefix = '-';
}
}else{
prefix = flag_prefix;
}
exp = s.iDP-1;
/*
|
| ︙ | ︙ | |||
51190 51191 51192 51193 51194 51195 51196 51197 51198 51199 51200 51201 51202 51203 | /* ** Windows will only let you create file view mappings ** on allocation size granularity boundaries. ** During sqlite3_os_init() we do a GetSystemInfo() ** to get the granularity size. */ static SYSTEM_INFO winSysInfo; #ifndef SQLITE_OMIT_WAL /* ** Helper functions to obtain and relinquish the global mutex. The ** global mutex is used to protect the winLockInfo objects used by ** this file, all of which may be shared by multiple threads. | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 51213 51214 51215 51216 51217 51218 51219 51220 51221 51222 51223 51224 51225 51226 51227 51228 51229 51230 51231 51232 51233 51234 51235 51236 51237 51238 51239 51240 51241 51242 51243 51244 51245 51246 51247 51248 51249 51250 51251 51252 51253 51254 51255 51256 51257 51258 51259 51260 51261 51262 51263 51264 51265 51266 51267 51268 51269 51270 51271 51272 51273 51274 51275 51276 51277 51278 51279 51280 51281 51282 51283 51284 51285 51286 51287 51288 51289 51290 51291 51292 51293 51294 51295 51296 51297 51298 51299 51300 51301 51302 51303 51304 51305 51306 51307 51308 51309 51310 51311 51312 51313 51314 51315 51316 51317 51318 51319 51320 51321 51322 51323 |
/*
** Windows will only let you create file view mappings
** on allocation size granularity boundaries.
** During sqlite3_os_init() we do a GetSystemInfo()
** to get the granularity size.
*/
static SYSTEM_INFO winSysInfo;
/*
** Convert a UTF-8 filename into whatever form the underlying
** operating system wants filenames in. Space to hold the result
** is obtained from malloc and must be freed by the calling
** function
**
** On Cygwin, 3 possible input forms are accepted:
** - If the filename starts with "<drive>:/" or "<drive>:\",
** it is converted to UTF-16 as-is.
** - If the filename contains '/', it is assumed to be a
** Cygwin absolute path, it is converted to a win32
** absolute path in UTF-16.
** - Otherwise it must be a filename only, the win32 filename
** is returned in UTF-16.
** Note: If the function cygwin_conv_path() fails, only
** UTF-8 -> UTF-16 conversion will be done. This can only
** happen when the file path >32k, in which case winUtf8ToUnicode()
** will fail too.
*/
static void *winConvertFromUtf8Filename(const char *zFilename){
void *zConverted = 0;
if( osIsNT() ){
#ifdef __CYGWIN__
int nChar;
LPWSTR zWideFilename;
if( osCygwin_conv_path && !(winIsDriveLetterAndColon(zFilename)
&& winIsDirSep(zFilename[2])) ){
i64 nByte;
int convertflag = CCP_POSIX_TO_WIN_W;
if( !strchr(zFilename, '/') ) convertflag |= CCP_RELATIVE;
nByte = (i64)osCygwin_conv_path(convertflag,
zFilename, 0, 0);
if( nByte>0 ){
zConverted = sqlite3MallocZero(12+(u64)nByte);
if ( zConverted==0 ){
return zConverted;
}
zWideFilename = zConverted;
/* Filenames should be prefixed, except when converted
* full path already starts with "\\?\". */
if( osCygwin_conv_path(convertflag, zFilename,
zWideFilename+4, nByte)==0 ){
if( (convertflag&CCP_RELATIVE) ){
memmove(zWideFilename, zWideFilename+4, nByte);
}else if( memcmp(zWideFilename+4, L"\\\\", 4) ){
memcpy(zWideFilename, L"\\\\?\\", 8);
}else if( zWideFilename[6]!='?' ){
memmove(zWideFilename+6, zWideFilename+4, nByte);
memcpy(zWideFilename, L"\\\\?\\UNC", 14);
}else{
memmove(zWideFilename, zWideFilename+4, nByte);
}
return zConverted;
}
sqlite3_free(zConverted);
}
}
nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0);
if( nChar==0 ){
return 0;
}
zWideFilename = sqlite3MallocZero( nChar*sizeof(WCHAR)+12 );
if( zWideFilename==0 ){
return 0;
}
nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1,
zWideFilename, nChar);
if( nChar==0 ){
sqlite3_free(zWideFilename);
zWideFilename = 0;
}else if( nChar>MAX_PATH
&& winIsDriveLetterAndColon(zFilename)
&& winIsDirSep(zFilename[2]) ){
memmove(zWideFilename+4, zWideFilename, nChar*sizeof(WCHAR));
zWideFilename[2] = '\\';
memcpy(zWideFilename, L"\\\\?\\", 8);
}else if( nChar>MAX_PATH
&& winIsDirSep(zFilename[0]) && winIsDirSep(zFilename[1])
&& zFilename[2] != '?' ){
memmove(zWideFilename+6, zWideFilename, nChar*sizeof(WCHAR));
memcpy(zWideFilename, L"\\\\?\\UNC", 14);
}
zConverted = zWideFilename;
#else
zConverted = winUtf8ToUnicode(zFilename);
#endif /* __CYGWIN__ */
}
#if defined(SQLITE_WIN32_HAS_ANSI) && defined(_WIN32)
else{
zConverted = winUtf8ToMbcs(zFilename, osAreFileApisANSI());
}
#endif
/* caller will handle out of memory */
return zConverted;
}
#ifndef SQLITE_OMIT_WAL
/*
** Helper functions to obtain and relinquish the global mutex. The
** global mutex is used to protect the winLockInfo objects used by
** this file, all of which may be shared by multiple threads.
|
| ︙ | ︙ | |||
51385 51386 51387 51388 51389 51390 51391 |
}
}
return rc;
}
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 51505 51506 51507 51508 51509 51510 51511 51512 51513 51514 51515 51516 51517 51518 |
}
}
return rc;
}
/*
** This function is used to open a handle on a *-shm file.
**
** If SQLITE_ENABLE_SETLK_TIMEOUT is defined at build time, then the file
** is opened with FILE_FLAG_OVERLAPPED specified. If not, it is not.
*/
static int winHandleOpen(
|
| ︙ | ︙ | |||
89076 89077 89078 89079 89080 89081 89082 |
** string, it means the main database is :memory: or a temp file. In
** that case we do not support atomic multi-file commits, so use the
** simple case then too.
*/
if( 0==sqlite3Strlen30(sqlite3BtreeGetFilename(db->aDb[0].pBt))
|| nTrans<=1
){
| > | | | | > > | > | 89099 89100 89101 89102 89103 89104 89105 89106 89107 89108 89109 89110 89111 89112 89113 89114 89115 89116 89117 89118 89119 89120 89121 89122 89123 89124 89125 89126 89127 89128 89129 89130 89131 |
** string, it means the main database is :memory: or a temp file. In
** that case we do not support atomic multi-file commits, so use the
** simple case then too.
*/
if( 0==sqlite3Strlen30(sqlite3BtreeGetFilename(db->aDb[0].pBt))
|| nTrans<=1
){
if( needXcommit ){
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
Btree *pBt = db->aDb[i].pBt;
if( sqlite3BtreeTxnState(pBt)>=SQLITE_TXN_WRITE ){
rc = sqlite3BtreeCommitPhaseOne(pBt, 0);
}
}
}
/* Do the commit only if all databases successfully complete phase 1.
** If one of the BtreeCommitPhaseOne() calls fails, this indicates an
** IO error while deleting or truncating a journal file. It is unlikely,
** but could happen. In this case abandon processing and return the error.
*/
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
Btree *pBt = db->aDb[i].pBt;
int txn = sqlite3BtreeTxnState(pBt);
if( txn!=SQLITE_TXN_NONE ){
assert( needXcommit || txn==SQLITE_TXN_READ );
rc = sqlite3BtreeCommitPhaseTwo(pBt, 0);
}
}
if( rc==SQLITE_OK ){
sqlite3VtabCommit(db);
}
}
|
| ︙ | ︙ | |||
89345 89346 89347 89348 89349 89350 89351 |
return vdbeCloseStatement(p, eOp);
}
return SQLITE_OK;
}
/*
| | | | | | | < < < < | | | | | | > | > > > > > > | 89372 89373 89374 89375 89376 89377 89378 89379 89380 89381 89382 89383 89384 89385 89386 89387 89388 89389 89390 89391 89392 89393 89394 89395 89396 89397 89398 89399 89400 89401 89402 89403 89404 89405 89406 89407 89408 89409 89410 |
return vdbeCloseStatement(p, eOp);
}
return SQLITE_OK;
}
/*
** These functions are called when a transaction opened by the database
** handle associated with the VM passed as an argument is about to be
** committed. If there are outstanding foreign key constraint violations
** return an error code. Otherwise, SQLITE_OK.
**
** If there are outstanding FK violations and this function returns
** non-zero, set the result of the VM to SQLITE_CONSTRAINT_FOREIGNKEY
** and write an error message to it.
*/
#ifndef SQLITE_OMIT_FOREIGN_KEY
static SQLITE_NOINLINE int vdbeFkError(Vdbe *p){
p->rc = SQLITE_CONSTRAINT_FOREIGNKEY;
p->errorAction = OE_Abort;
sqlite3VdbeError(p, "FOREIGN KEY constraint failed");
if( (p->prepFlags & SQLITE_PREPARE_SAVESQL)==0 ) return SQLITE_ERROR;
return SQLITE_CONSTRAINT_FOREIGNKEY;
}
SQLITE_PRIVATE int sqlite3VdbeCheckFkImmediate(Vdbe *p){
if( p->nFkConstraint==0 ) return SQLITE_OK;
return vdbeFkError(p);
}
SQLITE_PRIVATE int sqlite3VdbeCheckFkDeferred(Vdbe *p){
sqlite3 *db = p->db;
if( (db->nDeferredCons+db->nDeferredImmCons)==0 ) return SQLITE_OK;
return vdbeFkError(p);
}
#endif
/*
** This routine is called the when a VDBE tries to halt. If the VDBE
** has made changes and is in autocommit mode, then commit those
** changes. If a rollback is needed, then do the rollback.
|
| ︙ | ︙ | |||
89460 89461 89462 89463 89464 89465 89466 |
p->nChange = 0;
}
}
}
/* Check for immediate foreign key violations. */
if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && !isSpecialError) ){
| | | | 89490 89491 89492 89493 89494 89495 89496 89497 89498 89499 89500 89501 89502 89503 89504 89505 89506 89507 89508 89509 89510 89511 89512 89513 89514 89515 89516 89517 89518 |
p->nChange = 0;
}
}
}
/* Check for immediate foreign key violations. */
if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && !isSpecialError) ){
(void)sqlite3VdbeCheckFkImmediate(p);
}
/* If the auto-commit flag is set and this is the only active writer
** VM, then we do either a commit or rollback of the current transaction.
**
** Note: This block also runs if one of the special errors handled
** above has occurred.
*/
if( !sqlite3VtabInSync(db)
&& db->autoCommit
&& db->nVdbeWrite==(p->readOnly==0)
){
if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && !isSpecialError) ){
rc = sqlite3VdbeCheckFkDeferred(p);
if( rc!=SQLITE_OK ){
if( NEVER(p->readOnly) ){
sqlite3VdbeLeave(p);
return SQLITE_ERROR;
}
rc = SQLITE_CONSTRAINT_FOREIGNKEY;
}else if( db->flags & SQLITE_CorruptRdOnly ){
|
| ︙ | ︙ | |||
90339 90340 90341 90342 90343 90344 90345 |
pMem->enc = pKeyInfo->enc;
pMem->db = pKeyInfo->db;
/* pMem->flags = 0; // sqlite3VdbeSerialGet() will set this for us */
pMem->szMalloc = 0;
pMem->z = 0;
sqlite3VdbeSerialGet(&aKey[d], serial_type, pMem);
d += sqlite3VdbeSerialTypeLen(serial_type);
| < > | | 90369 90370 90371 90372 90373 90374 90375 90376 90377 90378 90379 90380 90381 90382 90383 90384 90385 90386 90387 90388 90389 90390 90391 |
pMem->enc = pKeyInfo->enc;
pMem->db = pKeyInfo->db;
/* pMem->flags = 0; // sqlite3VdbeSerialGet() will set this for us */
pMem->szMalloc = 0;
pMem->z = 0;
sqlite3VdbeSerialGet(&aKey[d], serial_type, pMem);
d += sqlite3VdbeSerialTypeLen(serial_type);
if( (++u)>=p->nField ) break;
pMem++;
}
if( d>(u32)nKey && u ){
assert( CORRUPT_DB );
/* In a corrupt record entry, the last pMem might have been set up using
** uninitialized memory. Overwrite its value with NULL, to prevent
** warnings from MSAN. */
sqlite3VdbeMemSetNull(pMem-(u<p->nField));
}
testcase( u == pKeyInfo->nKeyField + 1 );
testcase( u < pKeyInfo->nKeyField + 1 );
assert( u<=pKeyInfo->nKeyField + 1 );
p->nField = u;
}
|
| ︙ | ︙ | |||
90518 90519 90520 90521 90522 90523 90524 90525 90526 90527 90528 90529 90530 90531 90532 90533 90534 90535 |
/*
** Both *pMem1 and *pMem2 contain string values. Compare the two values
** using the collation sequence pColl. As usual, return a negative , zero
** or positive value if *pMem1 is less than, equal to or greater than
** *pMem2, respectively. Similar in spirit to "rc = (*pMem1) - (*pMem2);".
*/
static int vdbeCompareMemString(
const Mem *pMem1,
const Mem *pMem2,
const CollSeq *pColl,
u8 *prcErr /* If an OOM occurs, set to SQLITE_NOMEM */
){
if( pMem1->enc==pColl->enc ){
/* The strings are already in the correct encoding. Call the
** comparison function directly */
return pColl->xCmp(pColl->pUser,pMem1->n,pMem1->z,pMem2->n,pMem2->z);
}else{
| > > > > > > > > > > > > > > > > > > > > > > > > > > < < < < < < < < < < < < < < < < < < | | 90548 90549 90550 90551 90552 90553 90554 90555 90556 90557 90558 90559 90560 90561 90562 90563 90564 90565 90566 90567 90568 90569 90570 90571 90572 90573 90574 90575 90576 90577 90578 90579 90580 90581 90582 90583 90584 90585 90586 90587 90588 90589 90590 90591 90592 90593 90594 90595 90596 90597 90598 90599 |
/*
** Both *pMem1 and *pMem2 contain string values. Compare the two values
** using the collation sequence pColl. As usual, return a negative , zero
** or positive value if *pMem1 is less than, equal to or greater than
** *pMem2, respectively. Similar in spirit to "rc = (*pMem1) - (*pMem2);".
*/
static SQLITE_NOINLINE int vdbeCompareMemStringWithEncodingChange(
const Mem *pMem1,
const Mem *pMem2,
const CollSeq *pColl,
u8 *prcErr /* If an OOM occurs, set to SQLITE_NOMEM */
){
int rc;
const void *v1, *v2;
Mem c1;
Mem c2;
sqlite3VdbeMemInit(&c1, pMem1->db, MEM_Null);
sqlite3VdbeMemInit(&c2, pMem1->db, MEM_Null);
sqlite3VdbeMemShallowCopy(&c1, pMem1, MEM_Ephem);
sqlite3VdbeMemShallowCopy(&c2, pMem2, MEM_Ephem);
v1 = sqlite3ValueText((sqlite3_value*)&c1, pColl->enc);
v2 = sqlite3ValueText((sqlite3_value*)&c2, pColl->enc);
if( (v1==0 || v2==0) ){
if( prcErr ) *prcErr = SQLITE_NOMEM_BKPT;
rc = 0;
}else{
rc = pColl->xCmp(pColl->pUser, c1.n, v1, c2.n, v2);
}
sqlite3VdbeMemReleaseMalloc(&c1);
sqlite3VdbeMemReleaseMalloc(&c2);
return rc;
}
static int vdbeCompareMemString(
const Mem *pMem1,
const Mem *pMem2,
const CollSeq *pColl,
u8 *prcErr /* If an OOM occurs, set to SQLITE_NOMEM */
){
if( pMem1->enc==pColl->enc ){
/* The strings are already in the correct encoding. Call the
** comparison function directly */
return pColl->xCmp(pColl->pUser,pMem1->n,pMem1->z,pMem2->n,pMem2->z);
}else{
return vdbeCompareMemStringWithEncodingChange(pMem1,pMem2,pColl,prcErr);
}
}
/*
** The input pBlob is guaranteed to be a Blob that is not marked
** with MEM_Zero. Return true if it could be a zero-blob.
*/
|
| ︙ | ︙ | |||
96254 96255 96256 96257 96258 96259 96260 |
**
** FK constraint violations are also checked when the prepared statement
** exits. This opcode is used to raise foreign key constraint errors prior
** to returning results such as a row change count or the result of a
** RETURNING clause.
*/
case OP_FkCheck: {
| | | 96292 96293 96294 96295 96296 96297 96298 96299 96300 96301 96302 96303 96304 96305 96306 |
**
** FK constraint violations are also checked when the prepared statement
** exits. This opcode is used to raise foreign key constraint errors prior
** to returning results such as a row change count or the result of a
** RETURNING clause.
*/
case OP_FkCheck: {
if( (rc = sqlite3VdbeCheckFkImmediate(p))!=SQLITE_OK ){
goto abort_due_to_error;
}
break;
}
/* Opcode: ResultRow P1 P2 * * *
** Synopsis: output=r[P1@P2]
|
| ︙ | ︙ | |||
98438 98439 98440 98441 98442 98443 98444 |
/* Determine whether or not this is a transaction savepoint. If so,
** and this is a RELEASE command, then the current transaction
** is committed.
*/
int isTransaction = pSavepoint->pNext==0 && db->isTransactionSavepoint;
if( isTransaction && p1==SAVEPOINT_RELEASE ){
| | | 98476 98477 98478 98479 98480 98481 98482 98483 98484 98485 98486 98487 98488 98489 98490 |
/* Determine whether or not this is a transaction savepoint. If so,
** and this is a RELEASE command, then the current transaction
** is committed.
*/
int isTransaction = pSavepoint->pNext==0 && db->isTransactionSavepoint;
if( isTransaction && p1==SAVEPOINT_RELEASE ){
if( (rc = sqlite3VdbeCheckFkDeferred(p))!=SQLITE_OK ){
goto vdbe_return;
}
db->autoCommit = 1;
if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){
p->pc = (int)(pOp - aOp);
db->autoCommit = 0;
p->rc = rc = SQLITE_BUSY;
|
| ︙ | ︙ | |||
98556 98557 98558 98559 98560 98561 98562 |
/* If this instruction implements a COMMIT and other VMs are writing
** return an error indicating that the other VMs must complete first.
*/
sqlite3VdbeError(p, "cannot commit transaction - "
"SQL statements in progress");
rc = SQLITE_BUSY;
goto abort_due_to_error;
| | | 98594 98595 98596 98597 98598 98599 98600 98601 98602 98603 98604 98605 98606 98607 98608 |
/* If this instruction implements a COMMIT and other VMs are writing
** return an error indicating that the other VMs must complete first.
*/
sqlite3VdbeError(p, "cannot commit transaction - "
"SQL statements in progress");
rc = SQLITE_BUSY;
goto abort_due_to_error;
}else if( (rc = sqlite3VdbeCheckFkDeferred(p))!=SQLITE_OK ){
goto vdbe_return;
}else{
db->autoCommit = (u8)desiredAutoCommit;
}
if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){
p->pc = (int)(pOp - aOp);
db->autoCommit = (u8)(1-desiredAutoCommit);
|
| ︙ | ︙ | |||
109254 109255 109256 109257 109258 109259 109260 | } #define sqlite3ResolveNotValid(P,N,M,X,E,R) \ assert( ((X)&~(NC_IsCheck|NC_PartIdx|NC_IdxExpr|NC_GenCol))==0 ); \ if( ((N)->ncFlags & (X))!=0 ) notValidImpl(P,N,M,E,R); /* ** Expression p should encode a floating point value between 1.0 and 0.0. | | | | 109292 109293 109294 109295 109296 109297 109298 109299 109300 109301 109302 109303 109304 109305 109306 109307 |
}
#define sqlite3ResolveNotValid(P,N,M,X,E,R) \
assert( ((X)&~(NC_IsCheck|NC_PartIdx|NC_IdxExpr|NC_GenCol))==0 ); \
if( ((N)->ncFlags & (X))!=0 ) notValidImpl(P,N,M,E,R);
/*
** Expression p should encode a floating point value between 1.0 and 0.0.
** Return 134,217,728 (2^27) times this value. Or return -1 if p is not
** a floating point value between 1.0 and 0.0.
*/
static int exprProbability(Expr *p){
double r = -1.0;
if( p->op!=TK_FLOAT ) return -1;
assert( !ExprHasProperty(p, EP_IntValue) );
sqlite3AtoF(p->u.zToken, &r, sqlite3Strlen30(p->u.zToken), SQLITE_UTF8);
assert( r>=0.0 );
|
| ︙ | ︙ | |||
115631 115632 115633 115634 115635 115636 115637 115638 115639 115640 115641 115642 115643 115644 |
}
#endif
case TK_STRING: {
assert( !ExprHasProperty(pExpr, EP_IntValue) );
sqlite3VdbeLoadString(v, target, pExpr->u.zToken);
return target;
}
default: {
/* Make NULL the default case so that if a bug causes an illegal
** Expr node to be passed into this function, it will be handled
** sanely and not crash. But keep the assert() to bring the problem
** to the attention of the developers. */
assert( op==TK_NULL || op==TK_ERROR || pParse->db->mallocFailed );
sqlite3VdbeAddOp2(v, OP_Null, 0, target);
| > > > > > > | 115669 115670 115671 115672 115673 115674 115675 115676 115677 115678 115679 115680 115681 115682 115683 115684 115685 115686 115687 115688 |
}
#endif
case TK_STRING: {
assert( !ExprHasProperty(pExpr, EP_IntValue) );
sqlite3VdbeLoadString(v, target, pExpr->u.zToken);
return target;
}
case TK_NULLS: {
/* Set a range of registers to NULL. pExpr->y.nReg registers starting
** with target */
sqlite3VdbeAddOp3(v, OP_Null, 0, target, target + pExpr->y.nReg - 1);
return target;
}
default: {
/* Make NULL the default case so that if a bug causes an illegal
** Expr node to be passed into this function, it will be handled
** sanely and not crash. But keep the assert() to bring the problem
** to the attention of the developers. */
assert( op==TK_NULL || op==TK_ERROR || pParse->db->mallocFailed );
sqlite3VdbeAddOp2(v, OP_Null, 0, target);
|
| ︙ | ︙ | |||
116339 116340 116341 116342 116343 116344 116345 116346 116347 116348 116349 116350 116351 116352 |
if( regDest<0 ) regDest = ++pParse->nMem;
pItem->u.iConstExprReg = regDest;
}
pParse->pConstExpr = p;
}
return regDest;
}
/*
** Generate code to evaluate an expression and store the results
** into a register. Return the register number where the results
** are stored.
**
** If the register is a temporary register that can be deallocated,
| > > > > > > > > > > > > > > > > > > > | 116383 116384 116385 116386 116387 116388 116389 116390 116391 116392 116393 116394 116395 116396 116397 116398 116399 116400 116401 116402 116403 116404 116405 116406 116407 116408 116409 116410 116411 116412 116413 116414 116415 |
if( regDest<0 ) regDest = ++pParse->nMem;
pItem->u.iConstExprReg = regDest;
}
pParse->pConstExpr = p;
}
return regDest;
}
/*
** Make arrangements to invoke OP_Null on a range of registers
** during initialization.
*/
SQLITE_PRIVATE SQLITE_NOINLINE void sqlite3ExprNullRegisterRange(
Parse *pParse, /* Parsing context */
int iReg, /* First register to set to NULL */
int nReg /* Number of sequential registers to NULL out */
){
u8 okConstFactor = pParse->okConstFactor;
Expr t;
memset(&t, 0, sizeof(t));
t.op = TK_NULLS;
t.y.nReg = nReg;
pParse->okConstFactor = 1;
sqlite3ExprCodeRunJustOnce(pParse, &t, iReg);
pParse->okConstFactor = okConstFactor;
}
/*
** Generate code to evaluate an expression and store the results
** into a register. Return the register number where the results
** are stored.
**
** If the register is a temporary register that can be deallocated,
|
| ︙ | ︙ | |||
152744 152745 152746 152747 152748 152749 152750 152751 152752 152753 152754 152755 152756 152757 |
}
else if( pWhere->op==TK_EXISTS ){
Select *pSub = pWhere->x.pSelect;
Expr *pSubWhere = pSub->pWhere;
if( pSub->pSrc->nSrc==1
&& (pSub->selFlags & SF_Aggregate)==0
&& !pSub->pSrc->a[0].fg.isSubquery
){
memset(pWhere, 0, sizeof(*pWhere));
pWhere->op = TK_INTEGER;
pWhere->u.iValue = 1;
ExprSetProperty(pWhere, EP_IntValue);
assert( p->pWhere!=0 );
| > | 152807 152808 152809 152810 152811 152812 152813 152814 152815 152816 152817 152818 152819 152820 152821 |
}
else if( pWhere->op==TK_EXISTS ){
Select *pSub = pWhere->x.pSelect;
Expr *pSubWhere = pSub->pWhere;
if( pSub->pSrc->nSrc==1
&& (pSub->selFlags & SF_Aggregate)==0
&& !pSub->pSrc->a[0].fg.isSubquery
&& pSub->pLimit==0
){
memset(pWhere, 0, sizeof(*pWhere));
pWhere->op = TK_INTEGER;
pWhere->u.iValue = 1;
ExprSetProperty(pWhere, EP_IntValue);
assert( p->pWhere!=0 );
|
| ︙ | ︙ | |||
153764 153765 153766 153767 153768 153769 153770 153771 153772 153773 153774 153775 153776 153777 |
iAMem = pParse->nMem + 1;
pParse->nMem += pGroupBy->nExpr;
iBMem = pParse->nMem + 1;
pParse->nMem += pGroupBy->nExpr;
sqlite3VdbeAddOp2(v, OP_Integer, 0, iAbortFlag);
VdbeComment((v, "clear abort flag"));
sqlite3VdbeAddOp3(v, OP_Null, 0, iAMem, iAMem+pGroupBy->nExpr-1);
/* Begin a loop that will extract all source rows in GROUP BY order.
** This might involve two separate loops with an OP_Sort in between, or
** it might be a single loop that uses an index to extract information
** in the right order to begin with.
*/
sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset);
| > | 153828 153829 153830 153831 153832 153833 153834 153835 153836 153837 153838 153839 153840 153841 153842 |
iAMem = pParse->nMem + 1;
pParse->nMem += pGroupBy->nExpr;
iBMem = pParse->nMem + 1;
pParse->nMem += pGroupBy->nExpr;
sqlite3VdbeAddOp2(v, OP_Integer, 0, iAbortFlag);
VdbeComment((v, "clear abort flag"));
sqlite3VdbeAddOp3(v, OP_Null, 0, iAMem, iAMem+pGroupBy->nExpr-1);
sqlite3ExprNullRegisterRange(pParse, iAMem, pGroupBy->nExpr);
/* Begin a loop that will extract all source rows in GROUP BY order.
** This might involve two separate loops with an OP_Sort in between, or
** it might be a single loop that uses an index to extract information
** in the right order to begin with.
*/
sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset);
|
| ︙ | ︙ | |||
169082 169083 169084 169085 169086 169087 169088 169089 169090 169091 169092 169093 169094 169095 |
continue; /* Partial index inappropriate for this query */
}
if( pProbe->bNoQuery ) continue;
rSize = pProbe->aiRowLogEst[0];
pNew->u.btree.nEq = 0;
pNew->u.btree.nBtm = 0;
pNew->u.btree.nTop = 0;
pNew->nSkip = 0;
pNew->nLTerm = 0;
pNew->iSortIdx = 0;
pNew->rSetup = 0;
pNew->prereq = mPrereq;
pNew->nOut = rSize;
pNew->u.btree.pIndex = pProbe;
| > | 169147 169148 169149 169150 169151 169152 169153 169154 169155 169156 169157 169158 169159 169160 169161 |
continue; /* Partial index inappropriate for this query */
}
if( pProbe->bNoQuery ) continue;
rSize = pProbe->aiRowLogEst[0];
pNew->u.btree.nEq = 0;
pNew->u.btree.nBtm = 0;
pNew->u.btree.nTop = 0;
pNew->u.btree.nDistinctCol = 0;
pNew->nSkip = 0;
pNew->nLTerm = 0;
pNew->iSortIdx = 0;
pNew->rSetup = 0;
pNew->prereq = mPrereq;
pNew->nOut = rSize;
pNew->u.btree.pIndex = pProbe;
|
| ︙ | ︙ | |||
170150 170151 170152 170153 170154 170155 170156 |
if( pLoop->wsFlags & WHERE_VIRTUALTABLE ){
if( pLoop->u.vtab.isOrdered
&& ((wctrlFlags&(WHERE_DISTINCTBY|WHERE_SORTBYGROUP))!=WHERE_DISTINCTBY)
){
obSat = obDone;
}
break;
| < < | 170216 170217 170218 170219 170220 170221 170222 170223 170224 170225 170226 170227 170228 170229 |
if( pLoop->wsFlags & WHERE_VIRTUALTABLE ){
if( pLoop->u.vtab.isOrdered
&& ((wctrlFlags&(WHERE_DISTINCTBY|WHERE_SORTBYGROUP))!=WHERE_DISTINCTBY)
){
obSat = obDone;
}
break;
}
iCur = pWInfo->pTabList->a[pLoop->iTab].iCursor;
/* Mark off any ORDER BY term X that is a column in the table of
** the current loop for which there is term in the WHERE
** clause of the form X IS NULL or X=? that reference only outer
** loops.
|
| ︙ | ︙ | |||
258111 258112 258113 258114 258115 258116 258117 |
static void fts5SourceIdFunc(
sqlite3_context *pCtx, /* Function call context */
int nArg, /* Number of args */
sqlite3_value **apUnused /* Function arguments */
){
assert( nArg==0 );
UNUSED_PARAM2(nArg, apUnused);
| | | 258175 258176 258177 258178 258179 258180 258181 258182 258183 258184 258185 258186 258187 258188 258189 |
static void fts5SourceIdFunc(
sqlite3_context *pCtx, /* Function call context */
int nArg, /* Number of args */
sqlite3_value **apUnused /* Function arguments */
){
assert( nArg==0 );
UNUSED_PARAM2(nArg, apUnused);
sqlite3_result_text(pCtx, "fts5: 2025-07-30 16:17:14 cf7163f82ca380958a79350473b2c5a2cebda7496d6d575fa2835c362010fea1", -1, SQLITE_TRANSIENT);
}
/*
** Implementation of fts5_locale(LOCALE, TEXT) function.
**
** If parameter LOCALE is NULL, or a zero-length string, then a copy of
** TEXT is returned. Otherwise, both LOCALE and TEXT are interpreted as
|
| ︙ | ︙ |
Changes to extsrc/sqlite3.h.
| ︙ | ︙ | |||
144 145 146 147 148 149 150 | ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.51.0" #define SQLITE_VERSION_NUMBER 3051000 | | | 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.51.0" #define SQLITE_VERSION_NUMBER 3051000 #define SQLITE_SOURCE_ID "2025-07-30 16:17:14 cf7163f82ca380958a79350473b2c5a2cebda7496d6d575fa2835c362010fea1" /* ** CAPI3REF: Run-Time Library Version Numbers ** KEYWORDS: sqlite3_version sqlite3_sourceid ** ** These interfaces provide the same information as the [SQLITE_VERSION], ** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros |
| ︙ | ︙ | |||
493 494 495 496 497 498 499 500 501 502 503 504 505 506 | ** [sqlite3_extended_result_codes()] API. Or, the extended code for ** the most recent error can be obtained using ** [sqlite3_extended_errcode()]. */ #define SQLITE_ERROR_MISSING_COLLSEQ (SQLITE_ERROR | (1<<8)) #define SQLITE_ERROR_RETRY (SQLITE_ERROR | (2<<8)) #define SQLITE_ERROR_SNAPSHOT (SQLITE_ERROR | (3<<8)) #define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8)) #define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8)) #define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3<<8)) #define SQLITE_IOERR_FSYNC (SQLITE_IOERR | (4<<8)) #define SQLITE_IOERR_DIR_FSYNC (SQLITE_IOERR | (5<<8)) #define SQLITE_IOERR_TRUNCATE (SQLITE_IOERR | (6<<8)) #define SQLITE_IOERR_FSTAT (SQLITE_IOERR | (7<<8)) | > > > | 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 | ** [sqlite3_extended_result_codes()] API. Or, the extended code for ** the most recent error can be obtained using ** [sqlite3_extended_errcode()]. */ #define SQLITE_ERROR_MISSING_COLLSEQ (SQLITE_ERROR | (1<<8)) #define SQLITE_ERROR_RETRY (SQLITE_ERROR | (2<<8)) #define SQLITE_ERROR_SNAPSHOT (SQLITE_ERROR | (3<<8)) #define SQLITE_ERROR_RESERVESIZE (SQLITE_ERROR | (4<<8)) #define SQLITE_ERROR_KEY (SQLITE_ERROR | (5<<8)) #define SQLITE_ERROR_UNABLE (SQLITE_ERROR | (6<<8)) #define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8)) #define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8)) #define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3<<8)) #define SQLITE_IOERR_FSYNC (SQLITE_IOERR | (4<<8)) #define SQLITE_IOERR_DIR_FSYNC (SQLITE_IOERR | (5<<8)) #define SQLITE_IOERR_TRUNCATE (SQLITE_IOERR | (6<<8)) #define SQLITE_IOERR_FSTAT (SQLITE_IOERR | (7<<8)) |
| ︙ | ︙ | |||
527 528 529 530 531 532 533 534 535 536 537 538 539 540 | #define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28<<8)) #define SQLITE_IOERR_BEGIN_ATOMIC (SQLITE_IOERR | (29<<8)) #define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30<<8)) #define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8)) #define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8)) #define SQLITE_IOERR_CORRUPTFS (SQLITE_IOERR | (33<<8)) #define SQLITE_IOERR_IN_PAGE (SQLITE_IOERR | (34<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) #define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) #define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8)) #define SQLITE_BUSY_TIMEOUT (SQLITE_BUSY | (3<<8)) #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) #define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8)) | > > | 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 | #define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28<<8)) #define SQLITE_IOERR_BEGIN_ATOMIC (SQLITE_IOERR | (29<<8)) #define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30<<8)) #define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8)) #define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8)) #define SQLITE_IOERR_CORRUPTFS (SQLITE_IOERR | (33<<8)) #define SQLITE_IOERR_IN_PAGE (SQLITE_IOERR | (34<<8)) #define SQLITE_IOERR_BADKEY (SQLITE_IOERR | (35<<8)) #define SQLITE_IOERR_CODEC (SQLITE_IOERR | (36<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) #define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) #define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8)) #define SQLITE_BUSY_TIMEOUT (SQLITE_BUSY | (3<<8)) #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) #define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8)) |
| ︙ | ︙ |
Changes to src/bisect.c.
| ︙ | ︙ | |||
334 335 336 337 338 339 340 |
rid = -rid;
}
}
zUuid = db_text(0,"SELECT lower(uuid) FROM blob WHERE rid=%d", rid);
if( blob_size(&link)>0 ) blob_append(&link, "-", 1);
blob_appendf(&link, "%c%.10s", cPrefix, zUuid);
}
| | | 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 |
rid = -rid;
}
}
zUuid = db_text(0,"SELECT lower(uuid) FROM blob WHERE rid=%d", rid);
if( blob_size(&link)>0 ) blob_append(&link, "-", 1);
blob_appendf(&link, "%c%.10s", cPrefix, zUuid);
}
zResult = fossil_strdup(blob_str(&link));
blob_reset(&link);
blob_reset(&log);
blob_reset(&id);
return zResult;
}
/*
|
| ︙ | ︙ |
Changes to src/browse.c.
| ︙ | ︙ | |||
1160 1161 1162 1163 1164 1165 1166 |
const char *zNow; /* Time of check-in */
int isBranchCI; /* name= is a branch name */
int showId = PB("showid");
Stmt q1, q2;
double baseTime;
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
| < | 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 |
const char *zNow; /* Time of check-in */
int isBranchCI; /* name= is a branch name */
int showId = PB("showid");
Stmt q1, q2;
double baseTime;
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
zName = P("name");
if( zName==0 ) zName = "tip";
rid = symbolic_name_to_rid(zName, "ci");
if( rid==0 ){
fossil_fatal("not a valid check-in: %s", zName);
}
zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
|
| ︙ | ︙ |
Changes to src/captcha.c.
| ︙ | ︙ | |||
742 743 744 745 746 747 748 |
const char *zPw = P("name");
if( zPw==0 || zPw[0]==0 ){
(void)exclude_spiders(1);
@ <hr><p>The captcha is shown above. Add a name=HEX query parameter
@ to see how HEX would be rendered in the current captcha font.
@ <h2>Debug/Testing Values:</h2>
@ <ul>
| | > > > > > > > > < | < < | < | 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 |
const char *zPw = P("name");
if( zPw==0 || zPw[0]==0 ){
(void)exclude_spiders(1);
@ <hr><p>The captcha is shown above. Add a name=HEX query parameter
@ to see how HEX would be rendered in the current captcha font.
@ <h2>Debug/Testing Values:</h2>
@ <ul>
@ <li> g.isRobot = %d(g.isRobot)
@ <li> g.zLogin = %h(g.zLogin)
@ <li> login_cookie_welformed() = %d(login_cookie_wellformed())
@ <li> captcha_is_correct(1) = %d(captcha_is_correct(1)).
@ </ul>
style_finish_page();
}else{
style_set_current_feature("test");
style_header("Captcha Test");
@ <pre class="captcha">
@ %s(captcha_render(zPw))
@ </pre>
style_finish_page();
}
}
/*
** WEBPAGE: honeypot
** This page is a honeypot for spiders and bots.
*/
void honeypot_page(void){
(void)exclude_spiders(0);
}
/*
** Check to see if the current request is coming from an agent that
** self-identifies as a spider.
**
** If the agent does not claim to be a spider or if the user has logged
** in (even as anonymous), then return 0 without doing anything.
**
** But if the user agent does self-identify as a spider and there is
** no login, offer a captcha challenge to allow the user agent to prove
** that he is human and return non-zero.
**
** If the bTest argument is non-zero, then show the captcha regardless of
** how the agent identifies. This is used for testing only.
*/
int exclude_spiders(int bTest){
if( !bTest ){
if( g.zLogin!=0 ) return 0; /* Logged in. Consider them human */
if( login_cookie_wellformed() ){
/* Logged into another member of the login group */
return 0;
}
}
/* This appears to be a spider. Offer the captcha */
style_set_current_feature("captcha");
style_header("Captcha");
style_submenu_enable(0);
@ <form method='POST' action='%R/ityaar'>
@ <h2>Prove that you are human:
if( bTest ){
@ <input type="hidden" name="istest" value="1">
}
captcha_generate(3);
@ </form>
if( !bTest ){
if( P("fossil-goto")==0 ){
|
| ︙ | ︙ | |||
828 829 830 831 832 833 834 |
/* ^^^^--- Don't overwrite a valid login on another repo! */
login_set_anon_cookie(0, 0);
}
cgi_append_header("X-Robot: 0\r\n");
}
login_redirect_to_g();
}else{
| | | 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 |
/* ^^^^--- Don't overwrite a valid login on another repo! */
login_set_anon_cookie(0, 0);
}
cgi_append_header("X-Robot: 0\r\n");
}
login_redirect_to_g();
}else{
g.isRobot = 1;
(void)exclude_spiders(bTest);
if( bTest ){
@ <hr><p>Wrong code. Try again
style_finish_page();
}
}
}
|
| ︙ | ︙ |
Changes to src/cgi.c.
| ︙ | ︙ | |||
962 963 964 965 966 967 968 | ** are ignored. ** ** * it is impossible for a cookie or query parameter to ** override the value of an environment variable since ** environment variables always have uppercase names. ** ** 2018-03-29: Also ignore the entry if NAME that contains any characters | | | 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 | ** are ignored. ** ** * it is impossible for a cookie or query parameter to ** override the value of an environment variable since ** environment variables always have uppercase names. ** ** 2018-03-29: Also ignore the entry if NAME that contains any characters ** other than [-a-zA-Z0-9_]. There are no known exploits involving unusual ** names that contain characters outside that set, but it never hurts to ** be extra cautious when sanitizing inputs. ** ** Parameters are separated by the "terminator" character. Whitespace ** before the NAME is ignored. ** ** The input string "z" is modified but no copies is made. "z" |
| ︙ | ︙ | |||
1278 1279 1280 1281 1282 1283 1284 | fputs(z, pLog); } /* Forward declaration */ static NORETURN void malformed_request(const char *zMsg, ...); /* | | | | > > > > > | | | | > > > > > > > > | 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 |
fputs(z, pLog);
}
/* Forward declaration */
static NORETURN void malformed_request(const char *zMsg, ...);
/*
** Checks the QUERY_STRING environment variable, sets it up via
** add_param_list() and, if found, applies its "skin" setting. Returns
** 0 if no QUERY_STRING is set, else it returns a bitmask of:
**
** 0x01 = QUERY_STRING was set up
** 0x02 = "skin" URL param arg was processed
** 0x04 = "x-f-l-c" cookie arg was processed.
**
* In the case of the skin, the cookie may still need flushing
** by the page, via cookie_render().
*/
int cgi_setup_query_string(void){
int rc = 0;
char * z = (char*)P("QUERY_STRING");
if( z ){
rc = 0x01;
z = fossil_strdup(z);
add_param_list(z, '&');
z = (char*)P("skin");
if( z ){
char *zErr = skin_use_alternative(z, 2, SKIN_FROM_QPARAM);
rc |= 0x02;
if( !zErr && P("once")==0 ){
cookie_write_parameter("skin","skin",z);
/* Per /chat discussion, passing ?skin=... without "once"
** implies the "udc" argument, so we force that into the
** environment here. */
cgi_set_parameter_nocopy("udc", "1", 1);
}
fossil_free(zErr);
}
}
if( !g.syncInfo.zLoginCard && 0!=(z=(char*)P("x-f-l-c")) ){
/* x-f-l-c (X-Fossil-Login-Card card transmitted via cookie
** instead of in the sync payload. */
rc |= 0x04;
g.syncInfo.zLoginCard = fossil_strdup(z);
g.syncInfo.fLoginCardMode |= 0x02;
cgi_delete_parameter("x-f-l-c");
}
return rc;
}
/*
** Initialize the query parameter database. Information is pulled from
** the QUERY_STRING environment variable (if it exists), from standard
|
| ︙ | ︙ | |||
1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 |
CGIDEBUG(("env-match [%s] = [%s]\n", zName, zValue));
return zValue;
}
}
CGIDEBUG(("no-match [%s]\n", zName));
return zDefault;
}
/*
** Renders the "begone, spider" page and exits.
*/
static void cgi_begone_spider(const char *zName){
Blob content = empty_blob;
cgi_set_content(&content);
| > > > > > > > > > > > > > > > | 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 |
CGIDEBUG(("env-match [%s] = [%s]\n", zName, zValue));
return zValue;
}
}
CGIDEBUG(("no-match [%s]\n", zName));
return zDefault;
}
/*
** Return TRUE if the specific parameter exists and is a query parameter.
** Return FALSE if the parameter is a cookie or environment variable.
*/
int cgi_is_qp(const char *zName){
int i;
if( zName==0 || fossil_isupper(zName[0]) ) return 0;
for(i=0; i<nUsedQP; i++){
if( fossil_strcmp(aParamQP[i].zName,zName)==0 ){
return aParamQP[i].isQP;
}
}
return 0;
}
/*
** Renders the "begone, spider" page and exits.
*/
static void cgi_begone_spider(const char *zName){
Blob content = empty_blob;
cgi_set_content(&content);
|
| ︙ | ︙ | |||
2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 |
void cgi_handle_http_request(const char *zIpAddr){
char *z, *zToken;
int i;
const char *zScheme = "http";
char zLine[2000]; /* A single line of input. */
g.fullHttpReply = 1;
g.zReqType = "HTTP";
if( cgi_fgets(zLine, sizeof(zLine))==0 ){
malformed_request("missing header");
}
blob_append(&g.httpHeader, zLine, -1);
cgi_trace(zLine);
zToken = extract_token(zLine, &z);
if( zToken==0 ){
| > | 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 |
void cgi_handle_http_request(const char *zIpAddr){
char *z, *zToken;
int i;
const char *zScheme = "http";
char zLine[2000]; /* A single line of input. */
g.fullHttpReply = 1;
g.zReqType = "HTTP";
if( cgi_fgets(zLine, sizeof(zLine))==0 ){
malformed_request("missing header");
}
blob_append(&g.httpHeader, zLine, -1);
cgi_trace(zLine);
zToken = extract_token(zLine, &z);
if( zToken==0 ){
|
| ︙ | ︙ | |||
2158 2159 2160 2161 2162 2163 2164 |
if( zIpAddr==0 ){
zIpAddr = cgi_remote_ip(fossil_fileno(g.httpIn));
}
if( zIpAddr ){
cgi_setenv("REMOTE_ADDR", zIpAddr);
g.zIpAddr = fossil_strdup(zIpAddr);
}
| < | 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 |
if( zIpAddr==0 ){
zIpAddr = cgi_remote_ip(fossil_fileno(g.httpIn));
}
if( zIpAddr ){
cgi_setenv("REMOTE_ADDR", zIpAddr);
g.zIpAddr = fossil_strdup(zIpAddr);
}
/* Get all the optional fields that follow the first line.
*/
while( cgi_fgets(zLine,sizeof(zLine)) ){
char *zFieldName;
char *zVal;
|
| ︙ | ︙ |
Changes to src/chat.c.
| ︙ | ︙ | |||
1319 1320 1321 1322 1323 1324 1325 |
"\r\n%z\r\n%s", obscure(zPw), zBoundary);
}
if( zMsg && zMsg[0] ){
blob_appendf(&up,"\r\nContent-Disposition: form-data; name=\"msg\"\r\n"
"\r\n%s\r\n%s", zMsg, zBoundary);
}
if( zFilename && blob_read_from_file(&fcontent, zFilename, ExtFILE)>0 ){
| | | 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 |
"\r\n%z\r\n%s", obscure(zPw), zBoundary);
}
if( zMsg && zMsg[0] ){
blob_appendf(&up,"\r\nContent-Disposition: form-data; name=\"msg\"\r\n"
"\r\n%s\r\n%s", zMsg, zBoundary);
}
if( zFilename && blob_read_from_file(&fcontent, zFilename, ExtFILE)>0 ){
char *zFN = fossil_strdup(file_tail(zAs ? zAs : zFilename));
int i;
const char *zMime = mimetype_from_name(zFN);
for(i=0; zFN[i]; i++){
char c = zFN[i];
if( fossil_isalnum(c) ) continue;
if( c=='.' ) continue;
if( c=='-' ) continue;
|
| ︙ | ︙ |
Changes to src/checkin.c.
| ︙ | ︙ | |||
1384 1385 1386 1387 1388 1389 1390 |
blob_zero(&fname);
if( g.zLocalRoot!=0 ){
file_relative_name(g.zLocalRoot, &fname, 1);
zFile = db_text(0, "SELECT '%qci-comment-'||hex(randomblob(6))||'.txt'",
blob_str(&fname));
}else{
file_tempname(&fname, "ci-comment",0);
| | | 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 |
blob_zero(&fname);
if( g.zLocalRoot!=0 ){
file_relative_name(g.zLocalRoot, &fname, 1);
zFile = db_text(0, "SELECT '%qci-comment-'||hex(randomblob(6))||'.txt'",
blob_str(&fname));
}else{
file_tempname(&fname, "ci-comment",0);
zFile = fossil_strdup(blob_str(&fname));
}
blob_reset(&fname);
}
#if defined(_WIN32)
blob_add_cr(pPrompt);
#endif
if( blob_size(pPrompt)>0 ) blob_write_to_file(pPrompt, zFile);
|
| ︙ | ︙ | |||
1500 1501 1502 1503 1504 1505 1506 |
}
blob_append(&prompt,
"# * All other text will be displayed as written\n", -1);
}else{
blob_append(&prompt,
"# * Hyperlinks: [target] or [target|display-text]\n"
"# * Blank lines cause a paragraph break\n"
| | | 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 |
}
blob_append(&prompt,
"# * All other text will be displayed as written\n", -1);
}else{
blob_append(&prompt,
"# * Hyperlinks: [target] or [target|display-text]\n"
"# * Blank lines cause a paragraph break\n"
"# * Other text rendered as if it were HTML\n", -1
);
}
blob_append(&prompt, "#\n", 2);
if( dryRunFlag ){
blob_appendf(&prompt, "# DRY-RUN: This is a test commit. No changes "
"will be made to the repository\n#\n");
|
| ︙ | ︙ |
Changes to src/clearsign.c.
| ︙ | ︙ | |||
63 64 65 66 67 68 69 |
blob_read_from_file(&tmpBlob, zOut, ExtFILE);
/* Add armor header line and manifest */
blob_appendf(pOut, "%s", "-----BEGIN SSH SIGNED MESSAGE-----\n\n");
blob_appendf(pOut, "%s", blob_str(&tmpBlob));
blob_zero(&tmpBlob);
blob_read_from_file(&tmpBlob, zIn, ExtFILE);
/* Add signature - already armored by SSH */
| | | 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
blob_read_from_file(&tmpBlob, zOut, ExtFILE);
/* Add armor header line and manifest */
blob_appendf(pOut, "%s", "-----BEGIN SSH SIGNED MESSAGE-----\n\n");
blob_appendf(pOut, "%s", blob_str(&tmpBlob));
blob_zero(&tmpBlob);
blob_read_from_file(&tmpBlob, zIn, ExtFILE);
/* Add signature - already armored by SSH */
blob_appendb(pOut, &tmpBlob);
}else{
/* Assume that the external command creates non-detached signatures */
blob_read_from_file(pOut, zIn, ExtFILE);
}
}else{
if( pOut!=pIn ){
blob_copy(pOut, pIn);
|
| ︙ | ︙ |
Changes to src/clone.c.
| ︙ | ︙ | |||
346 347 348 349 350 351 352 |
*/
void remember_or_get_http_auth(
const char *zHttpAuth, /* Credentials in the form "user:password" */
int fRemember, /* True to remember credentials for later reuse */
const char *zUrl /* URL for which these credentials apply */
){
if( zHttpAuth && zHttpAuth[0] ){
| | | 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 |
*/
void remember_or_get_http_auth(
const char *zHttpAuth, /* Credentials in the form "user:password" */
int fRemember, /* True to remember credentials for later reuse */
const char *zUrl /* URL for which these credentials apply */
){
if( zHttpAuth && zHttpAuth[0] ){
g.zHttpAuth = fossil_strdup(zHttpAuth);
}
if( fRemember ){
if( g.zHttpAuth && g.zHttpAuth[0] ){
set_httpauth(g.zHttpAuth);
}else if( zUrl && zUrl[0] ){
db_unset_mprintf(0, "http-auth:%s", g.url.canonical);
}else{
|
| ︙ | ︙ | |||
386 387 388 389 390 391 392 |
** Look for SSH clone command line options and setup in globals.
*/
void clone_ssh_find_options(void){
const char *zSshCmd; /* SSH command string */
zSshCmd = find_option("ssh-command","c",1);
if( zSshCmd && zSshCmd[0] ){
| | | 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 |
** Look for SSH clone command line options and setup in globals.
*/
void clone_ssh_find_options(void){
const char *zSshCmd; /* SSH command string */
zSshCmd = find_option("ssh-command","c",1);
if( zSshCmd && zSshCmd[0] ){
g.zSshCmd = fossil_strdup(zSshCmd);
}
}
/*
** Set SSH options discovered in global variables (set from command line
** options).
*/
|
| ︙ | ︙ |
Changes to src/comformat.c.
| ︙ | ︙ | |||
805 806 807 808 809 810 811 |
indent = -1; /* automatic */
}
verify_all_options();
zPrefix = zText = zOrigText = 0;
if( fromFile ){
Blob fileData;
blob_read_from_file(&fileData, fromFile, ExtFILE);
| | | | 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 |
indent = -1; /* automatic */
}
verify_all_options();
zPrefix = zText = zOrigText = 0;
if( fromFile ){
Blob fileData;
blob_read_from_file(&fileData, fromFile, ExtFILE);
zText = fossil_strdup(blob_str(&fileData));
blob_reset(&fileData);
}
if( fromOrig ){
Blob fileData;
blob_read_from_file(&fileData, fromOrig, ExtFILE);
zOrigText = fossil_strdup(blob_str(&fileData));
blob_reset(&fileData);
}
for(i=2; i<g.argc; i++){
if( zText==0 ){
zText = g.argv[i];
continue;
}
|
| ︙ | ︙ |
Changes to src/content.c.
| ︙ | ︙ | |||
598 599 600 601 602 603 604 605 606 607 608 609 610 611 |
"VALUES(%d,%d,'%q',:data)",
g.rcvid, size, blob_str(&hash)
);
db_bind_blob(&s1, ":data", &cmpr);
db_exec(&s1);
rid = db_last_insert_rowid();
if( !pBlob ){
db_multi_exec("INSERT OR IGNORE INTO phantom VALUES(%d)", rid);
}
}
if( g.markPrivate || isPrivate ){
db_multi_exec("INSERT OR IGNORE INTO private VALUES(%d)", rid);
markAsUnclustered = 0;
}
| > | 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 |
"VALUES(%d,%d,'%q',:data)",
g.rcvid, size, blob_str(&hash)
);
db_bind_blob(&s1, ":data", &cmpr);
db_exec(&s1);
rid = db_last_insert_rowid();
if( !pBlob ){
assert(!"cannot happen: pBlob is always non-NULL");
db_multi_exec("INSERT OR IGNORE INTO phantom VALUES(%d)", rid);
}
}
if( g.markPrivate || isPrivate ){
db_multi_exec("INSERT OR IGNORE INTO private VALUES(%d)", rid);
markAsUnclustered = 0;
}
|
| ︙ | ︙ |
Changes to src/cookies.c.
| ︙ | ︙ | |||
84 85 86 87 88 89 90 |
** by DISPLAY_SETTINGS_COOKIE
*/
void cookie_parse(void){
char *z;
if( cookies.bIsInit ) return;
z = (char*)P(DISPLAY_SETTINGS_COOKIE);
if( z==0 ) z = "";
| | | 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
** by DISPLAY_SETTINGS_COOKIE
*/
void cookie_parse(void){
char *z;
if( cookies.bIsInit ) return;
z = (char*)P(DISPLAY_SETTINGS_COOKIE);
if( z==0 ) z = "";
cookies.zCookieValue = z = fossil_strdup(z);
cookies.bIsInit = 1;
while( cookies.nParam<COOKIE_NPARAM ){
while( fossil_isspace(z[0]) ) z++;
if( z[0]==0 ) break;
cookies.aParam[cookies.nParam].zPName = z;
while( *z && *z!='=' && *z!=',' ){ z++; }
if( *z=='=' ){
|
| ︙ | ︙ | |||
280 281 282 283 284 285 286 287 288 289 290 291 292 293 |
if( fossil_strncmp(zName, "fossil-", 7)==0
&& strlen(zName)==23
&& hex_prefix_length(&zName[7])==16
&& hex_prefix_length(zValue)>24
){
@ <p>This appears to be a login cookie for another Fossil repository
@ in the same website.
}
else {
@ <p>This cookie was not generated by Fossil. It might be something
@ from another program on the same website.
}
fossil_free(zDel);
}
| > > > > | 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 |
if( fossil_strncmp(zName, "fossil-", 7)==0
&& strlen(zName)==23
&& hex_prefix_length(&zName[7])==16
&& hex_prefix_length(zValue)>24
){
@ <p>This appears to be a login cookie for another Fossil repository
@ in the same website.
}else
if( fossil_strcmp(zName, ROBOT_COOKIE)==0 ){
@ <p>This cookie shows that your web-browser has been tested is
@ believed to be operated by a human, not a robot.
}
else {
@ <p>This cookie was not generated by Fossil. It might be something
@ from another program on the same website.
}
fossil_free(zDel);
}
|
| ︙ | ︙ |
Changes to src/copybtn.js.
1 2 3 | /* Manage "Copy Buttons" linked to target elements, to copy the text (or, parts ** thereof) of the target elements to the clipboard. ** | | | | < < < < | > > > > | | > > | < < > > > > > | < < < < < < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
/* Manage "Copy Buttons" linked to target elements, to copy the text (or, parts
** thereof) of the target elements to the clipboard.
**
** Newly created buttons are <button> elements plus a nested <span> element with
** an SVG background icon, defined by the "copy-button" class in the default CSS
** style sheet, and are assigned the element ID "copy-<idTarget>".
**
** For HTML-defined buttons, either initCopyButtonById(), or initCopyButton(),
** needs to be called to attach the "onclick" handler (done automatically from
** a handler attached to the "DOMContentLoaded" event). These functions create
** the nested <span> element if the <button> element has no child nodes. Using
** static HTML for the <span> element ensures the buttons are visible if there
** are script errors, which may be useful for Fossil JS hackers (as good parts
** of the Fossil web UI come down on JS errors, anyway).
**
** The initialization functions do not overwrite the "data-copytarget" and
** "data-copylength" attributes with empty or null values for <idTarget> and
** <cchLength>, respectively. Set <cchLength> to "-1" to explicitly remove the
** previous copy length limit.
**
** HTML snippet for statically created buttons:
**
** <button class="copy-button" id="copy-<idTarget>"
** data-copytarget="<idTarget>" data-copylength="<cchLength>">
** <span></span>
** </button>
*/
function makeCopyButton(idTarget,bFlipped,cchLength){
var elButton = document.createElement("button");
elButton.className = "copy-button";
if( bFlipped ) elButton.className += " copy-button-flipped";
elButton.id = "copy-" + idTarget;
initCopyButton(elButton,idTarget,cchLength);
return elButton;
}
function initCopyButtonById(idButton,idTarget,cchLength){
idButton = idButton || "copy-" + idTarget;
var elButton = document.getElementById(idButton);
if( elButton ) initCopyButton(elButton,idTarget,cchLength);
return elButton;
}
function initCopyButton(elButton,idTarget,cchLength){
if( idTarget ) elButton.setAttribute("data-copytarget",idTarget);
if( cchLength ) elButton.setAttribute("data-copylength",cchLength);
elButton.onclick = clickCopyButton;
/* Make sure the <button> contains a single nested <span>. */
if( elButton.childElementCount!=1 || elButton.firstChild.tagName!="SPAN" ){
while( elButton.firstChild ) elButton.removeChild(elButton.lastChild);
elButton.appendChild(document.createElement("span"));
}
return elButton;
}
setTimeout(function(){
var elButtons = document.getElementsByClassName("copy-button");
for ( var i=0; i<elButtons.length; i++ ){
initCopyButton(elButtons[i],0,0);
}
},1);
/* The onclick handler for the "Copy Button". */
function clickCopyButton(e){
e.preventDefault(); /* Mandatory for <a> and <button>. */
e.stopPropagation();
if( this.disabled ) return; /* This check is probably redundant. */
var idTarget = this.getAttribute("data-copytarget");
var elTarget = document.getElementById(idTarget);
if( elTarget ){
var text = elTarget.innerText.replace(/^\s+|\s+$/g,"");
var cchLength = parseInt(this.getAttribute("data-copylength"));
if( !isNaN(cchLength) && cchLength>0 ){
text = text.slice(0,cchLength); /* Assume single-byte chars. */
}
copyTextToClipboard(text);
}
}
/* Create a temporary <textarea> element and copy the contents to clipboard. */
function copyTextToClipboard(text){
if( window.clipboardData && window.clipboardData.setData ){
window.clipboardData.setData("Text",text);
}else{
var elTextarea = document.createElement("textarea");
|
| ︙ | ︙ |
Changes to src/db.c.
| ︙ | ︙ | |||
123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
}
else
#endif /* FOSSIL_ENABLE_JSON */
if( g.xferPanic && g.cgiOutput==1 ){
cgi_reset_content();
@ error Database\serror:\s%F(z)
cgi_reply();
}
fossil_fatal("Database error: %s", z);
}
/*
** Check a result code. If it is not SQLITE_OK, print the
** corresponding error message and exit.
| > > > > > > > > > > | 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
}
else
#endif /* FOSSIL_ENABLE_JSON */
if( g.xferPanic && g.cgiOutput==1 ){
cgi_reset_content();
@ error Database\serror:\s%F(z)
cgi_reply();
}
if( strstr(z,"attempt to write a readonly database") ){
static const char *azDbNames[] = { "repository", "localdb", "configdb" };
int i;
for(i=0; i<3; i++){
if( sqlite3_db_readonly(g.db, azDbNames[i])==1 ){
z = mprintf("\"%s\" is readonly.\n%s",
sqlite3_db_filename(g.db,azDbNames[i]), z);
}
}
}
fossil_fatal("Database error: %s", z);
}
/*
** Check a result code. If it is not SQLITE_OK, print the
** corresponding error message and exit.
|
| ︙ | ︙ |
Changes to src/default.css.
1 2 3 4 5 6 7 8 9 10 11 12 |
/* This CSS file holds the default implementations for all of fossil's
CSS classes. When /style.css is requested, the rules in this file
are emitted first, followed by (1) page-specific CSS (if any) and
(2) skin-specific CSS.
*/
div.sidebox {
float: right;
background-color: white;
border-width: medium;
border-style: double;
margin: 10px;
}
| > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
/* This CSS file holds the default implementations for all of fossil's
CSS classes. When /style.css is requested, the rules in this file
are emitted first, followed by (1) page-specific CSS (if any) and
(2) skin-specific CSS.
*/
body {
z-index: 0 /* Used by robot.c:robot_proofofwork() and href.js */;
}
div.sidebox {
float: right;
background-color: white;
border-width: medium;
border-style: double;
margin: 10px;
}
|
| ︙ | ︙ | |||
1096 1097 1098 1099 1100 1101 1102 |
}
label {
white-space: nowrap;
}
label[for] {
cursor: pointer;
}
| | | > > > > > > > > > > > > > > > > > > > > > > > > | < < < < < | 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 |
}
label {
white-space: nowrap;
}
label[for] {
cursor: pointer;
}
button.copy-button,
button.copy-button:hover,
button.copy-button:focus,
button.copy-button:active {
width: 14px;
height: 14px;
/*Note: .24em is slightly smaller than the average width of a normal space.*/
margin: -2px .24em 0 0;
padding: 0;
border: 0;
outline: 0;
background: none;
font-size: inherit; /* Required for horizontal spacing. */
vertical-align: middle;
user-select: none;
cursor: pointer;
}
button.copy-button-flipped,
button.copy-button-flipped:hover,
button.copy-button-flipped:focus,
button.copy-button-flipped:active {
margin: -2px 0 0 .24em;
}
button.copy-button span {
display: block;
width: 100%;
height: 100%;
margin: 0;
padding: 0;
border: 0;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' \
viewBox='0,0,14,14'%3E%3Cpath style='fill:black;opacity:0' \
d='M14,14H0V0h14v14z'/%3E%3Cpath style='fill:rgb(240,240,240)' \
d='M1,0h6.6l2,2h1l3.4,3.4v8.6h-10v-2h-3z'/%3E%3Cpath style='fill:rgb(64,64,64)' \
d='M2,1h5l3,3v7h-8z'/%3E%3Cpath style='fill:rgb(248,248,248)' \
d='M3,2h3.6l2.4,2.4v5.6h-6z'/%3E%3Cpath style='fill:rgb(80,128,208)' \
d='M4,5h4v1h-4zm0,2h4v1h-4z'/%3E%3Cpath style='fill:rgb(64,64,64)' \
d='M5,3h5l3,3v7h-8z'/%3E%3Cpath style='fill:rgb(248,248,248)' \
d='M10,4.4v1.6h1.6zm-4,-0.6h3v3h-3zm0,3h6v5.4h-6z'/%3E%3Cpath style='fill:rgb(80,128,208)' \
d='M7,8h4v1h-4zm0,2h4v1h-4z'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: center;
cursor: pointer;
}
button.copy-button:enabled:active span {
background-size: 90%;
}
button.copy-button:disabled span {
filter: grayscale(1);
opacity: 0.4;
}
.nobr {
white-space: nowrap;
}
.accordion {
cursor: pointer;
}
.accordion_btn {
|
| ︙ | ︙ |
Changes to src/diff.c.
| ︙ | ︙ | |||
2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 |
Blob *pA_Blob, /* FROM file */
Blob *pB_Blob, /* TO file */
Blob *pOut, /* Write diff here if not NULL */
DiffConfig *pCfg /* Configuration options */
){
int ignoreWs; /* Ignore whitespace */
DContext c;
if( pCfg->diffFlags & DIFF_INVERT ){
Blob *pTemp = pA_Blob;
pA_Blob = pB_Blob;
pB_Blob = pTemp;
}
ignoreWs = (pCfg->diffFlags & DIFF_IGNORE_ALLWS)!=0;
| > | 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 |
Blob *pA_Blob, /* FROM file */
Blob *pB_Blob, /* TO file */
Blob *pOut, /* Write diff here if not NULL */
DiffConfig *pCfg /* Configuration options */
){
int ignoreWs; /* Ignore whitespace */
DContext c;
int nDel = 0, nIns = 0;
if( pCfg->diffFlags & DIFF_INVERT ){
Blob *pTemp = pA_Blob;
pA_Blob = pB_Blob;
pB_Blob = pTemp;
}
ignoreWs = (pCfg->diffFlags & DIFF_IGNORE_ALLWS)!=0;
|
| ︙ | ︙ | |||
3046 3047 3048 3049 3050 3051 3052 3053 |
c.aEdit[i] = sum;
for(k=0, sum=0; k<c.aEdit[i+1]; k++) sum += c.aFrom[iA++].n;
c.aEdit[i+1] = sum;
for(k=0, sum=0; k<c.aEdit[i+2]; k++) sum += c.aTo[iB++].n;
c.aEdit[i+2] = sum;
}
}
| < | | | | | | | | | | > > > > > > | 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 |
c.aEdit[i] = sum;
for(k=0, sum=0; k<c.aEdit[i+1]; k++) sum += c.aFrom[iA++].n;
c.aEdit[i+1] = sum;
for(k=0, sum=0; k<c.aEdit[i+2]; k++) sum += c.aTo[iB++].n;
c.aEdit[i+2] = sum;
}
}
if( pCfg->diffFlags & DIFF_NUMSTAT ){
int i;
for(i=0; c.aEdit[i] || c.aEdit[i+1] || c.aEdit[i+2]; i+=3){
nDel += c.aEdit[i+1];
nIns += c.aEdit[i+2];
}
g.diffCnt[1] += nIns;
g.diffCnt[2] += nDel;
if( nIns+nDel ){
g.diffCnt[0]++;
}
}
if( pOut ){
if( pCfg->diffFlags & DIFF_NUMSTAT && !(pCfg->diffFlags & DIFF_HTML)){
if( nIns+nDel ){
if( !(pCfg->diffFlags & DIFF_BRIEF) ){
blob_appendf(pOut, "%10d %10d", nIns, nDel);
}
}
}else if( pCfg->diffFlags & (DIFF_RAW|DIFF_BY_TOKEN) ){
const int *R = c.aEdit;
unsigned int r;
|
| ︙ | ︙ | |||
3664 3665 3666 3667 3668 3669 3670 | HQuery url; struct AnnVers *p; unsigned clr1, clr2, clr; int bBlame = g.zPath[0]!='a';/* True for BLAME output. False for ANNOTATE. */ /* Gather query parameters */ login_check_credentials(); | | | | 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 |
HQuery url;
struct AnnVers *p;
unsigned clr1, clr2, clr;
int bBlame = g.zPath[0]!='a';/* True for BLAME output. False for ANNOTATE. */
/* Gather query parameters */
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
if( robot_restrict("annotate") ) return;
fossil_nice_default();
zFilename = P("filename");
zRevision = PD("checkin",0);
zOrigin = P("origin");
zLimit = P("limit");
showLog = PB("log");
fileVers = PB("filevers");
|
| ︙ | ︙ |
Changes to src/diff.tcl.
| ︙ | ︙ | |||
279 280 281 282 283 284 285 |
foreach c [cols] {
set type [colType $c]
if {$type ne "txt"} {
$c config -width $widths($type)
}
$c config -state disabled
}
| < | > | 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 |
foreach c [cols] {
set type [colType $c]
if {$type ne "txt"} {
$c config -width $widths($type)
}
$c config -state disabled
}
.wfiles.lb config -height $nDiffs
if {$nDiffs <= [.wfiles.lb cget -height]} {
grid remove .wfiles.sb
}
return $nDiffs
}
proc viewDiff {idx} {
|
| ︙ | ︙ |
Changes to src/diffcmd.c.
| ︙ | ︙ | |||
1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 |
const char *zFrom = P("from");
const char *zTo = P("to");
DiffConfig DCfg;
cgi_check_for_malice();
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
if( zFrom==0 || zTo==0 ) fossil_redirect_home();
fossil_nice_default();
cgi_set_content_type("text/plain");
diff_config_init(&DCfg, DIFF_VERBOSE);
diff_two_versions(zFrom, zTo, &DCfg, 0);
}
| > | 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 |
const char *zFrom = P("from");
const char *zTo = P("to");
DiffConfig DCfg;
cgi_check_for_malice();
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
if( zFrom==0 || zTo==0 ) fossil_redirect_home();
if( robot_restrict("diff") ) return;
fossil_nice_default();
cgi_set_content_type("text/plain");
diff_config_init(&DCfg, DIFF_VERBOSE);
diff_two_versions(zFrom, zTo, &DCfg, 0);
}
|
Changes to src/event.c.
| ︙ | ︙ | |||
380 381 382 383 384 385 386 |
const char *zTags = P("g"); /* Tags added to this technote */
const char *zClrFlag = ""; /* "checked" for bg color */
const char *zClr; /* Name of the background color */
const char *zMimetype = P("mimetype"); /* Mimetype of zBody */
int isNew = 0;
if( zBody ){
| | | 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 |
const char *zTags = P("g"); /* Tags added to this technote */
const char *zClrFlag = ""; /* "checked" for bg color */
const char *zClr; /* Name of the background color */
const char *zMimetype = P("mimetype"); /* Mimetype of zBody */
int isNew = 0;
if( zBody ){
zBody = fossil_strdup(zBody);
}
login_check_credentials();
zId = P("name");
if( zId==0 ){
zId = db_text(0, "SELECT lower(hex(randomblob(20)))");
isNew = 1;
}else{
|
| ︙ | ︙ |
Changes to src/export.c.
| ︙ | ︙ | |||
56 57 58 59 60 61 62 |
printf(" <unknown>");
return;
}
db_static_prepare(&q, "SELECT info FROM user WHERE login=:user");
db_bind_text(&q, ":user", zUser);
if( db_step(&q)!=SQLITE_ROW ){
db_reset(&q);
| | | 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
printf(" <unknown>");
return;
}
db_static_prepare(&q, "SELECT info FROM user WHERE login=:user");
db_bind_text(&q, ":user", zUser);
if( db_step(&q)!=SQLITE_ROW ){
db_reset(&q);
zName = fossil_strdup(zUser);
for(i=j=0; zName[i]; i++){
if( zName[i]!='<' && zName[i]!='>' && zName[i]!='"' ){
zName[j++] = zName[i];
}
}
zName[j] = 0;
printf(" %s <%s>", zName, zName);
|
| ︙ | ︙ | |||
100 101 102 103 104 105 106 |
}
else if( zContact[i]==' ' && !isBracketed ){
atEmailFirst = i+1;
}
}
if( zContact[i]==0 ){
/* No email address found. Take as user info if not empty */
| | | 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
}
else if( zContact[i]==' ' && !isBracketed ){
atEmailFirst = i+1;
}
}
if( zContact[i]==0 ){
/* No email address found. Take as user info if not empty */
zName = fossil_strdup(zContact[0] ? zContact : zUser);
for(i=j=0; zName[i]; i++){
if( zName[i]!='<' && zName[i]!='>' && zName[i]!='"' ){
zName[j++] = zName[i];
}
}
zName[j] = 0;
|
| ︙ | ︙ | |||
147 148 149 150 151 152 153 |
for(i=atEmailFirst-2; i>=0 && zContact[i] && zContact[i]==' '; i--){}
if( i>=0 ){
for(j=0; j<i && zContact[j] && zContact[j]==' '; j++){}
zName = mprintf("%.*s", i-j+1, &zContact[j]);
}
}
| | | 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
for(i=atEmailFirst-2; i>=0 && zContact[i] && zContact[i]==' '; i--){}
if( i>=0 ){
for(j=0; j<i && zContact[j] && zContact[j]==' '; j++){}
zName = mprintf("%.*s", i-j+1, &zContact[j]);
}
}
if( zName==NULL ) zName = fossil_strdup(zUser);
for(i=j=0; zName[i]; i++){
if( zName[i]!='<' && zName[i]!='>' && zName[i]!='"' ){
zName[j++] = zName[i];
}
}
zName[j] = 0;
|
| ︙ | ︙ | |||
170 171 172 173 174 175 176 |
/*
** Output a sanitized git named reference.
** https://git-scm.com/docs/git-check-ref-format
** This implementation assumes we are only printing
** the branch or tag part of the reference.
*/
static void print_ref(const char *zRef){
| | | 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
/*
** Output a sanitized git named reference.
** https://git-scm.com/docs/git-check-ref-format
** This implementation assumes we are only printing
** the branch or tag part of the reference.
*/
static void print_ref(const char *zRef){
char *zEncoded = fossil_strdup(zRef);
int i, w;
if (zEncoded[0]=='@' && zEncoded[1]=='\0'){
putchar(REFREPLACEMENT);
return;
}
for(i=0, w=0; zEncoded[i]; i++, w++){
if( i!=0 ){ /* Two letter tests */
|
| ︙ | ︙ | |||
1150 1151 1152 1153 1154 1155 1156 |
zBranch = db_text(0,
"SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0 AND rid=%d",
TAG_BRANCH, rid
);
if( fossil_strcmp(zBranch,"trunk")==0 ){
assert( gitmirror_mainbranch!=0 );
fossil_free(zBranch);
| | | 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 |
zBranch = db_text(0,
"SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0 AND rid=%d",
TAG_BRANCH, rid
);
if( fossil_strcmp(zBranch,"trunk")==0 ){
assert( gitmirror_mainbranch!=0 );
fossil_free(zBranch);
zBranch = fossil_strdup(gitmirror_mainbranch);
}else if( zBranch==0 ){
zBranch = mprintf("unknown");
}else{
gitmirror_sanitize_name(zBranch);
}
/* Export the check-in */
|
| ︙ | ︙ |
Changes to src/extcgi.c.
| ︙ | ︙ | |||
227 228 229 230 231 232 233 |
}
if( nScript==0 ){
zFailReason = "path does not match any file or script";
goto ext_not_found;
}
assert( nScript>=nRoot+1 );
style_set_current_page("ext/%s", &zScript[nRoot+1]);
| > | | 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 |
}
if( nScript==0 ){
zFailReason = "path does not match any file or script";
goto ext_not_found;
}
assert( nScript>=nRoot+1 );
style_set_current_page("ext/%s", &zScript[nRoot+1]);
zMime = P("mimetype");
if( zMime==0 ) zMime = mimetype_from_name(zScript);
if( zMime==0 ) zMime = "application/octet-stream";
if( !file_isexe(zScript, ExtFILE) ){
/* File is not executable. Must be a regular file. In that case,
** disallow extra path elements */
if( zPath[nScript]!=0 ){
zFailReason = "extra path elements after filename";
goto ext_not_found;
|
| ︙ | ︙ |
Changes to src/file.c.
| ︙ | ︙ | |||
258 259 260 261 262 263 264 |
#if !defined(_WIN32)
if( db_allow_symlinks() ){
int i, nName;
char *zName, zBuf[1000];
nName = strlen(zLinkFile);
if( nName>=(int)sizeof(zBuf) ){
| | | 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 |
#if !defined(_WIN32)
if( db_allow_symlinks() ){
int i, nName;
char *zName, zBuf[1000];
nName = strlen(zLinkFile);
if( nName>=(int)sizeof(zBuf) ){
zName = fossil_strdup(zLinkFile);
}else{
zName = zBuf;
memcpy(zName, zLinkFile, nName+1);
}
nName = file_simplify_name(zName, nName, 0);
for(i=1; i<nName; i++){
if( zName[i]=='/' ){
|
| ︙ | ︙ | |||
423 424 425 426 427 428 429 |
** does not exist. Return 2 if zFilename exists but is something
** other than a directory.
*/
int file_isdir(const char *zFilename, int eFType){
int rc;
char *zFN;
| | | 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 |
** does not exist. Return 2 if zFilename exists but is something
** other than a directory.
*/
int file_isdir(const char *zFilename, int eFType){
int rc;
char *zFN;
zFN = fossil_strdup(zFilename);
file_simplify_name(zFN, -1, 0);
rc = getStat(zFN, eFType);
if( rc ){
rc = 0; /* It does not exist at all. */
}else if( S_ISDIR(fx.fileStat.st_mode) ){
rc = 1; /* It exists and is a real directory. */
}else{
|
| ︙ | ︙ | |||
902 903 904 905 906 907 908 |
int forceFlag, /* Delete non-directory objects in the way */
int errorReturn /* What to do when an error is seen */
){
int nName, rc = 0;
char *zName;
nName = strlen(zFilename);
| | | 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 |
int forceFlag, /* Delete non-directory objects in the way */
int errorReturn /* What to do when an error is seen */
){
int nName, rc = 0;
char *zName;
nName = strlen(zFilename);
zName = fossil_strdup(zFilename);
nName = file_simplify_name(zName, nName, 0);
while( nName>0 && zName[nName-1]!='/' ){ nName--; }
if( nName>1 ){
zName[nName-1] = 0;
if( file_isdir(zName, eFType)!=1 ){
rc = file_mkfolder(zName, eFType, forceFlag, errorReturn);
if( rc==0 ){
|
| ︙ | ︙ | |||
1275 1276 1277 1278 1279 1280 1281 |
int i;
char *z;
const char *zTail;
for(i=2; i<g.argc; i++){
zTail = file_skip_userhost(g.argv[i]);
if( zTail ){
fossil_print("... ON REMOTE: %.*s\n", (int)(zTail-g.argv[i]), g.argv[i]);
| | | | 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 |
int i;
char *z;
const char *zTail;
for(i=2; i<g.argc; i++){
zTail = file_skip_userhost(g.argv[i]);
if( zTail ){
fossil_print("... ON REMOTE: %.*s\n", (int)(zTail-g.argv[i]), g.argv[i]);
z = fossil_strdup(zTail);
}else{
z = fossil_strdup(g.argv[i]);
}
fossil_print("[%s] -> ", z);
file_simplify_name(z, -1, 0);
fossil_print("[%s]\n", z);
fossil_free(z);
}
}
|
| ︙ | ︙ |
Changes to src/fileedit.c.
| ︙ | ︙ | |||
823 824 825 826 827 828 829 |
fossil_fatal("Non-empty check-in comment is required.");
}
}
db_begin_transaction();
zFilename = g.argv[2];
cimi.zFilename = mprintf("%/", zAsFilename ? zAsFilename : zFilename);
cimi.filePerm = file_perm(zFilename, ExtFILE);
| | | | 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 |
fossil_fatal("Non-empty check-in comment is required.");
}
}
db_begin_transaction();
zFilename = g.argv[2];
cimi.zFilename = mprintf("%/", zAsFilename ? zAsFilename : zFilename);
cimi.filePerm = file_perm(zFilename, ExtFILE);
cimi.zUser = fossil_strdup(zUser ? zUser : login_name());
if(zDate){
cimi.zDate = fossil_strdup(zDate);
}
if(zRevision==0 || zRevision[0]==0){
if(g.localOpen/*check-out*/){
zRevision = db_lget("checkout-hash", 0)/*leak*/;
}else{
zRevision = "trunk";
}
|
| ︙ | ︙ | |||
926 927 928 929 930 931 932 |
int vid, int *pFilePerm){
Stmt stmt = empty_Stmt;
char * zFileUuid = 0;
db_prepare(&stmt, "SELECT uuid, perm FROM files_of_checkin "
"WHERE filename=%Q %s AND checkinID=%d",
zFilename, filename_collation(), vid);
if(SQLITE_ROW==db_step(&stmt)){
| | | 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 |
int vid, int *pFilePerm){
Stmt stmt = empty_Stmt;
char * zFileUuid = 0;
db_prepare(&stmt, "SELECT uuid, perm FROM files_of_checkin "
"WHERE filename=%Q %s AND checkinID=%d",
zFilename, filename_collation(), vid);
if(SQLITE_ROW==db_step(&stmt)){
zFileUuid = fossil_strdup(db_column_text(&stmt, 0));
if(pFilePerm){
*pFilePerm = mfile_permstr_int(db_column_text(&stmt, 1));
}
}
db_finalize(&stmt);
return zFileUuid;
}
|
| ︙ | ︙ | |||
1185 1186 1187 1188 1189 1190 1191 |
if(zFlag==0 || !*zFlag){
rc = 400;
if(bIsMissingArg){
*bIsMissingArg = 1;
}
fail((pErr,"Missing required 'filename' parameter."));
}
| | | 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 |
if(zFlag==0 || !*zFlag){
rc = 400;
if(bIsMissingArg){
*bIsMissingArg = 1;
}
fail((pErr,"Missing required 'filename' parameter."));
}
p->zFilename = fossil_strdup(zFlag);
if(0==fileedit_is_editable(p->zFilename)){
rc = 403;
fail((pErr,"Filename [%h] is disallowed "
"by the [fileedit-glob] repository "
"setting.",
p->zFilename));
|
| ︙ | ︙ | |||
1246 1247 1248 1249 1250 1251 1252 |
zFlag = PT("comment");
if(zFlag!=0 && *zFlag!=0){
blob_append(&p->comment, zFlag, -1);
}
zFlag = P("comment_mimetype");
if(zFlag){
| | | 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 |
zFlag = PT("comment");
if(zFlag!=0 && *zFlag!=0){
blob_append(&p->comment, zFlag, -1);
}
zFlag = P("comment_mimetype");
if(zFlag){
p->zCommentMimetype = fossil_strdup(zFlag);
zFlag = 0;
}
#define p_int(K) atoi(PD(K,"0"))
if(p_int("dry_run")!=0){
p->flags |= CIMINI_DRY_RUN;
}
if(p_int("allow_fork")!=0){
|
| ︙ | ︙ | |||
1282 1283 1284 1285 1286 1287 1288 |
default: p->flags |= CIMINI_CONVERT_EOL_INHERIT; break;
}
#undef p_int
/*
** TODO?: date-override date selection field. Maybe use
** an input[type=datetime-local].
*/
| | | 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 |
default: p->flags |= CIMINI_CONVERT_EOL_INHERIT; break;
}
#undef p_int
/*
** TODO?: date-override date selection field. Maybe use
** an input[type=datetime-local].
*/
p->zUser = fossil_strdup(g.zLogin);
return 0;
end_fail:
#undef fail
fossil_free(zFileUuid);
return rc ? rc : 500;
}
|
| ︙ | ︙ |
Changes to src/fossil.copybutton.js.
| ︙ | ︙ | |||
40 41 42 43 44 45 46 |
.style: optional object of properties to copy directly into
e.style.
.oncopy: an optional callback function which is added as an event
listener for the 'text-copied' event (see below). There is
functionally no difference from setting this option or adding a
'text-copied' event listener to the element, and this option is
| | < < | | < < < < | 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
.style: optional object of properties to copy directly into
e.style.
.oncopy: an optional callback function which is added as an event
listener for the 'text-copied' event (see below). There is
functionally no difference from setting this option or adding a
'text-copied' event listener to the element, and this option is
considered to be a convenience form of that.
Note that this function's own defaultOptions object holds default
values for some options. Any changes made to that object affect
any future calls to this function.
Be aware that clipboard functionality might or might not be
available in any given environment. If this button appears to
have no effect, that may be because it is not enabled/available
in the current platform.
The copy button emits custom event 'text-copied' after it has
successfully copied text to the clipboard. The event's "detail"
member is an object with a "text" property holding the copied
text. Other properties may be added in the future. The event is
not fired if copying to the clipboard fails (e.g. is not
available in the current environment).
The copy button's click handler is suppressed (becomes a no-op)
for as long as the element has the "disabled" attribute.
Returns the copy-initialized element.
Example:
const button = fossil.copyButton('#my-copy-button', {
copyFromId: 'some-other-element-id'
});
button.addEventListener('text-copied',function(ev){
console.debug("Copied text:",ev.detail.text);
});
*/
F.copyButton = function f(e, opt){
if('string'===typeof e){
e = document.querySelector(e);
}
|
| ︙ | ︙ | |||
101 102 103 104 105 106 107 |
);
D.copyStyle(e, opt.style);
e.addEventListener(
'click',
function(ev){
ev.preventDefault();
ev.stopPropagation();
| | > > > > | | 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
);
D.copyStyle(e, opt.style);
e.addEventListener(
'click',
function(ev){
ev.preventDefault();
ev.stopPropagation();
if(e.disabled) return; /* This check is probably redundant. */
const txt = extract.call(opt);
if(txt && D.copyTextToClipboard(txt)){
e.dispatchEvent(new CustomEvent('text-copied',{
detail: {text: txt}
}));
}
},
false
);
if('function' === typeof opt.oncopy){
e.addEventListener('text-copied', opt.oncopy, false);
}
/* Make sure the <button> contains a single nested <span>. */
if(e.childElementCount!=1 || e.firstChild.tagName!='SPAN'){
D.append(D.clearElement(e), D.span());
}
return e;
};
F.copyButton.defaultOptions = {
cssClass: 'copy-button',
oncopy: undefined,
style: {/*properties copied as-is into element.style*/}
};
})(window.fossil);
|
Changes to src/fossil.numbered-lines.js.
| ︙ | ︙ | |||
21 22 23 24 25 26 27 |
const tdLn = tbl.querySelector('td.line-numbers');
const urlArgsRaw = (window.location.search||'?')
.replace(/&?\budc=[^&]*/,'') /* "update display prefs cookie" */
.replace(/&?\bln=[^&]*/,'') /* inbound line number/range */
.replace('?&','?');
const lineState = { urlArgs: urlArgsRaw, start: 0, end: 0 };
const lineTip = new F.PopupWidget({
| < < < | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
const tdLn = tbl.querySelector('td.line-numbers');
const urlArgsRaw = (window.location.search||'?')
.replace(/&?\budc=[^&]*/,'') /* "update display prefs cookie" */
.replace(/&?\bln=[^&]*/,'') /* inbound line number/range */
.replace('?&','?');
const lineState = { urlArgs: urlArgsRaw, start: 0, end: 0 };
const lineTip = new F.PopupWidget({
refresh: function(){
const link = this.state.link;
D.clearElement(link);
if(lineState.start){
const ls = [lineState.start];
if(lineState.end) ls.push(lineState.end);
link.dataset.url = (
|
| ︙ | ︙ | |||
46 47 48 49 50 51 52 |
);
}else{
D.append(link, "No lines selected.");
}
},
init: function(){
const e = this.e;
| | | | < | | 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
);
}else{
D.append(link, "No lines selected.");
}
},
init: function(){
const e = this.e;
const btnCopy = D.attr(D.button(), 'id', 'linenum-copy-button');
link = D.label('linenum-copy-button');
this.state = {link};
F.copyButton(btnCopy,{
copyFromElement: link,
extractText: ()=>link.dataset.url,
oncopy: (ev)=>{
setTimeout(()=>lineTip.hide(), 400);
// arguably too snazzy: F.toast.message("Copied link to clipboard.");
}
});
D.append(this.e, btnCopy, link);
}
});
tbl.addEventListener('click', ()=>lineTip.hide(), true);
tdLn.addEventListener('click', function f(ev){
if('SPAN'!==ev.target.tagName) return;
|
| ︙ | ︙ |
Changes to src/fossil.page.chat.js.
| ︙ | ︙ | |||
899 900 901 902 903 904 905 |
mouse-copying from that field collecting twice as many
newlines as it should (for unknown reasons). */
const cpId = 'copy-to-clipboard-'+id;
/* ^^^ copy button element ID, needed for LABEL element
pairing. Recall that we destroy all child elements of
`content` each time we hit this block, so we can reuse
that element ID on subsequent toggles. */
| | < | 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 |
mouse-copying from that field collecting twice as many
newlines as it should (for unknown reasons). */
const cpId = 'copy-to-clipboard-'+id;
/* ^^^ copy button element ID, needed for LABEL element
pairing. Recall that we destroy all child elements of
`content` each time we hit this block, so we can reuse
that element ID on subsequent toggles. */
const btnCp = D.attr(D.addClass(D.button(),'copy-button'), 'id', cpId);
F.copyButton(btnCp, {extractText: ()=>child._xmsgRaw});
const lblCp = D.label(cpId, "Copy unformatted text");
D.append(content, D.append(D.addClass(D.span(), 'nobr'), btnCp, lblCp));
}
delete e.$isToggling;
D.append(content, child);
return;
}
// We need to fetch the plain-text version...
|
| ︙ | ︙ | |||
1159 1160 1161 1162 1163 1164 1165 |
const iframe = msgObj.e.iframe;
const body = iframe.contentWindow.document.querySelector('body');
if(body && !body.style.fontSize){
/** _Attempt_ to force the iframe to inherit the message's text size
if the body has no explicit size set. On desktop systems
the size is apparently being inherited in that case, but on mobile
not. */
| | | 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 |
const iframe = msgObj.e.iframe;
const body = iframe.contentWindow.document.querySelector('body');
if(body && !body.style.fontSize){
/** _Attempt_ to force the iframe to inherit the message's text size
if the body has no explicit size set. On desktop systems
the size is apparently being inherited in that case, but on mobile
not. */
body.style.fontSize = window.getComputedStyle(msgObj.e.content).fontSize;
}
if('' === iframe.style.maxHeight){
/* Resize iframe height to fit the content. Workaround: if we
adjust the iframe height while it's hidden then its height
is 0, so we must briefly unhide it. */
const isHidden = iframe.classList.contains('hidden');
if(isHidden) D.removeClass(iframe, 'hidden');
|
| ︙ | ︙ | |||
1734 1735 1736 1737 1738 1739 1740 |
};
['drop','dragenter','dragleave','dragend'].forEach(
(k)=>Chat.e.inputX.addEventListener(k, noDragDropEvents, false)
);
return bxs;
})()/*drag/drop/paste*/;
| < < < < | 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 |
};
['drop','dragenter','dragleave','dragend'].forEach(
(k)=>Chat.e.inputX.addEventListener(k, noDragDropEvents, false)
);
return bxs;
})()/*drag/drop/paste*/;
const localTime8601 = function(d){
return [
d.getYear()+1900, '-', pad2(d.getMonth()+1), '-', pad2(d.getDate()),
'T', pad2(d.getHours()),':', pad2(d.getMinutes()),':',pad2(d.getSeconds())
].join('');
};
|
| ︙ | ︙ |
Changes to src/fossil.page.pikchrshow.js.
| ︙ | ︙ | |||
45 46 47 48 49 50 51 |
F.onPageLoad(function() {
document.body.classList.add('pikchrshow');
P.e = { /* various DOM elements we work with... */
previewTarget: E('#pikchrshow-output'),
previewLegend: E('#pikchrshow-output-wrapper > legend'),
previewCopyButton: D.attr(
| | | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
F.onPageLoad(function() {
document.body.classList.add('pikchrshow');
P.e = { /* various DOM elements we work with... */
previewTarget: E('#pikchrshow-output'),
previewLegend: E('#pikchrshow-output-wrapper > legend'),
previewCopyButton: D.attr(
D.addClass(D.button(),'copy-button'),
'id','preview-copy-button'
),
previewModeLabel: D.label('preview-copy-button'),
btnSubmit: E('#pikchr-submit-preview'),
btnStash: E('#pikchr-stash'),
btnUnstash: E('#pikchr-unstash'),
btnClearStash: E('#pikchr-clear-stash'),
|
| ︙ | ︙ | |||
117 118 119 120 121 122 123 |
return false;
}
}, false);
////////////////////////////////////////////////////////////
// Setup clipboard-copy of markup/SVG...
F.copyButton(P.e.previewCopyButton, {copyFromElement: P.e.taPreviewText});
| < | 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
return false;
}
}, false);
////////////////////////////////////////////////////////////
// Setup clipboard-copy of markup/SVG...
F.copyButton(P.e.previewCopyButton, {copyFromElement: P.e.taPreviewText});
////////////////////////////////////////////////////////////
// Set up dark mode simulator...
P.e.cbDarkMode.addEventListener('change', function(ev){
if(ev.target.checked) D.addClass(P.e.previewTarget, 'dark-mode');
else D.removeClass(P.e.previewTarget, 'dark-mode');
}, false);
|
| ︙ | ︙ | |||
346 347 348 349 350 351 352 |
if(this.response.isError){
D.append(D.clearElement(preTgt), D.parseHtml(P.response.raw));
D.addClass(preTgt, 'error');
this.e.previewModeLabel.innerText = "Error";
return;
}
D.removeClass(preTgt, 'error');
| | | 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 |
if(this.response.isError){
D.append(D.clearElement(preTgt), D.parseHtml(P.response.raw));
D.addClass(preTgt, 'error');
this.e.previewModeLabel.innerText = "Error";
return;
}
D.removeClass(preTgt, 'error');
this.e.previewCopyButton.disabled = false;
D.removeClass(this.e.markupAlignWrapper, 'hidden');
D.enable(this.e.previewModeToggle, this.e.markupAlignRadios);
let label, svg;
switch(this.previewMode){
case 0:
label = "SVG";
f.showMarkupAlignment(false);
|
| ︙ | ︙ | |||
425 426 427 428 429 430 431 |
P.response.isError = isError;
D.enable(fp.toDisable);
P.renderPreview();
};
}
D.disable(fp.toDisable, this.e.previewModeToggle, this.e.markupAlignRadios);
D.addClass(this.e.markupAlignWrapper, 'hidden');
| | | 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 |
P.response.isError = isError;
D.enable(fp.toDisable);
P.renderPreview();
};
}
D.disable(fp.toDisable, this.e.previewModeToggle, this.e.markupAlignRadios);
D.addClass(this.e.markupAlignWrapper, 'hidden');
this.e.previewCopyButton.disabled = true;
const content = this.e.taContent.value.trim();
this.response.raw = this.response.rawSvg = undefined;
this.response.inputText = content;
const sampleScript = fp.$_sampleScript;
delete fp.$_sampleScript;
if(sampleScript && sampleScript.cached){
fp.updateView(sampleScript.cached, false);
|
| ︙ | ︙ |
Changes to src/fossil.page.pikchrshowasm.js.
| ︙ | ︙ | |||
310 311 312 313 314 315 316 |
modes.selectedIndex = (modes.selectedIndex + 1) % modes.length;
this.e.previewModeLabel.innerText = this.renderModeLabels[modes[modes.selectedIndex]];
if(this.e.pikOut.dataset.pikchr){
this.render(this.e.pikOut.dataset.pikchr);
}
}.bind(PS));
F.copyButton(PS.e.previewCopyButton, {copyFromElement: PS.e.outText});
| < | 310 311 312 313 314 315 316 317 318 319 320 321 322 323 |
modes.selectedIndex = (modes.selectedIndex + 1) % modes.length;
this.e.previewModeLabel.innerText = this.renderModeLabels[modes[modes.selectedIndex]];
if(this.e.pikOut.dataset.pikchr){
this.render(this.e.pikOut.dataset.pikchr);
}
}.bind(PS));
F.copyButton(PS.e.previewCopyButton, {copyFromElement: PS.e.outText});
PS.addMsgHandler('working',function f(ev){
switch(ev.data){
case 'start': /* See notes in preStartWork(). */; return;
case 'end':
//preStartWork._.pageTitle.innerText = preStartWork._.pageTitleOrig;
this.e.btnRender.removeAttribute('disabled');
|
| ︙ | ︙ |
Changes to src/fossil.page.wikiedit.js.
| ︙ | ︙ | |||
1232 1233 1234 1235 1236 1237 1238 |
encodeURIComponent(wi.name),
"&file=",
encodeURIComponent(a.filename)
].join(''),
"raw/"+a.src
].forEach(function(url){
const imgUrl = D.append(D.addClass(D.span(), 'monospace'), url);
| | | | 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 |
encodeURIComponent(wi.name),
"&file=",
encodeURIComponent(a.filename)
].join(''),
"raw/"+a.src
].forEach(function(url){
const imgUrl = D.append(D.addClass(D.span(), 'monospace'), url);
const urlCopy = D.button();
const li = D.li(ul);
D.append(li, urlCopy, imgUrl);
F.copyButton(urlCopy, {copyFromElement: imgUrl});
});
});
return this;
};
/** Updates the in-tab title/edit status information */
|
| ︙ | ︙ |
Changes to src/graph.c.
| ︙ | ︙ | |||
224 225 226 227 228 229 230 |
static char *persistBranchName(GraphContext *p, const char *zBranch){
int i;
for(i=0; i<p->nBranch; i++){
if( fossil_strcmp(zBranch, p->azBranch[i])==0 ) return p->azBranch[i];
}
p->nBranch++;
p->azBranch = fossil_realloc(p->azBranch, sizeof(char*)*p->nBranch);
| | | 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 |
static char *persistBranchName(GraphContext *p, const char *zBranch){
int i;
for(i=0; i<p->nBranch; i++){
if( fossil_strcmp(zBranch, p->azBranch[i])==0 ) return p->azBranch[i];
}
p->nBranch++;
p->azBranch = fossil_realloc(p->azBranch, sizeof(char*)*p->nBranch);
p->azBranch[p->nBranch-1] = fossil_strdup(zBranch);
return p->azBranch[p->nBranch-1];
}
/*
** Add a new row to the graph context. Rows are added from top to bottom.
*/
int graph_add_row(
|
| ︙ | ︙ |
Changes to src/href.js.
1 2 3 4 5 | /* As an anti-robot defense, <a> elements are initially coded with the ** href= set to the honeypot, and <form> elements are initialized with ** action= set to the login page. The real values for href= and action= ** are held in data-href= and data-action=. The following code moves ** data-href= into href= and data-action= into action= for all | | | > > | | | | | | | | | | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
/* As an anti-robot defense, <a> elements are initially coded with the
** href= set to the honeypot, and <form> elements are initialized with
** action= set to the login page. The real values for href= and action=
** are held in data-href= and data-action=. The following code moves
** data-href= into href= and data-action= into action= for all
** <a> and <form> elements, after CSS has been loaded, and after a delay,
** and maybe also after mouse movement is seen.
**
** Before sourcing this script, create a separate <script> element
** (with type='application/json' to avoid Content Security Policy issues)
** containing:
**
** {"delay":MILLISECONDS, "mouseover":BOOLEAN}
**
** The <script> must have an id='href-data'. DELAY is the number
** milliseconds delay prior to populating href= and action=. If the
** mouseover boolean is true, then the href= rewrite is further delayed
** until the first mousedown event that occurs after the timer expires.
*/
var antiRobot = 0;
function antiRobotGo(){
if( antiRobot!=3 ) return;
var z = window.getComputedStyle(document.body).zIndex;
if( z==='0' || z===0 ){
antiRobot = 7;
var anchors = document.getElementsByTagName("a");
for(var i=0; i<anchors.length; i++){
var j = anchors[i];
if(j.hasAttribute("data-href")) j.href=j.getAttribute("data-href");
}
var forms = document.getElementsByTagName("form");
for(var i=0; i<forms.length; i++){
var j = forms[i];
if(j.hasAttribute("data-action")) j.action=j.getAttribute("data-action");
}
}
}
function antiRobotDefense(){
var x = document.getElementById("href-data");
var jx = x.textContent || x.innerText;
var g = JSON.parse(jx);
if( g.mouseover ){
|
| ︙ | ︙ | |||
54 55 56 57 58 59 60 61 62 63 |
setTimeout(function(){
antiRobot |= 1;
antiRobotGo();
}, g.delay)
}else{
antiRobot |= 1;
}
antiRobotGo();
}
antiRobotDefense();
| > | 57 58 59 60 61 62 63 64 65 66 67 |
setTimeout(function(){
antiRobot |= 1;
antiRobotGo();
}, g.delay)
}else{
antiRobot |= 1;
}
window.addEventListener('load',antiRobotGo);
antiRobotGo();
}
antiRobotDefense();
|
Changes to src/http.c.
| ︙ | ︙ | |||
50 51 52 53 54 55 56 | /* ** Construct the "login" card with the client credentials. ** ** login LOGIN NONCE SIGNATURE ** ** The LOGIN is the user id of the client. NONCE is the sha1 checksum | | | > | > | > | | | | | 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
/*
** Construct the "login" card with the client credentials.
**
** login LOGIN NONCE SIGNATURE
**
** The LOGIN is the user id of the client. NONCE is the sha1 checksum
** of all payload that follows the login card. Randomness for the
** NONCE must be provided in the payload (in xfer.c) (e.g. by
** appending a timestamp or random bytes as a comment line to the
** payload). SIGNATURE is the sha1 checksum of the nonce followed by
** the fossil-hashed version of the user's password.
**
** Write the constructed login card into pLogin. The result does not
** have an EOL added to it because which type of EOL it needs has to
** be determined later. pLogin is initialized by this routine.
*/
static void http_build_login_card(Blob * const pPayload, Blob * const pLogin){
Blob nonce; /* The nonce */
const char *zLogin; /* The user login name */
const char *zPw; /* The user password */
Blob pw; /* The nonce with user password appended */
Blob sig; /* The signature field */
blob_zero(pLogin);
if( g.url.user==0 || fossil_strcmp(g.url.user, "anonymous")==0 ){
return; /* No login card for users "nobody" and "anonymous" */
}
if( g.url.isSsh ){
return; /* No login card for SSH: */
}
blob_zero(&nonce);
blob_zero(&pw);
sha1sum_blob(pPayload, &nonce);
blob_copy(&pw, &nonce);
zLogin = g.url.user;
if( g.url.passwd ){
|
| ︙ | ︙ | |||
117 118 119 120 121 122 123 |
}
fossil_free(g.url.passwd);
g.url.passwd = fossil_strdup(zPw);
}
blob_append(&pw, zPw, -1);
sha1sum_blob(&pw, &sig);
| | | > > | | | > > > > > > | 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
}
fossil_free(g.url.passwd);
g.url.passwd = fossil_strdup(zPw);
}
blob_append(&pw, zPw, -1);
sha1sum_blob(&pw, &sig);
blob_appendf(pLogin, "login %F %b %b", zLogin, &nonce, &sig);
blob_reset(&pw);
blob_reset(&sig);
blob_reset(&nonce);
}
/*
** Construct an appropriate HTTP request header. Write the header
** into pHdr. This routine initializes the pHdr blob. pPayload is
** the complete payload (including the login card if pLogin is NULL or
** empty) already compressed.
*/
static void http_build_header(
Blob *pPayload, /* the payload that will be sent */
Blob *pHdr, /* construct the header here */
Blob *pLogin, /* Login card header value or NULL */
const char *zAltMimetype /* Alternative mimetype */
){
int nPayload = pPayload ? blob_size(pPayload) : 0;
blob_zero(pHdr);
blob_appendf(pHdr, "%s %s HTTP/1.0\r\n",
nPayload>0 ? "POST" : "GET",
(g.url.path && g.url.path[0]) ? g.url.path : "/");
if( g.url.proxyAuth ){
blob_appendf(pHdr, "Proxy-Authorization: %s\r\n", g.url.proxyAuth);
}
if( g.zHttpAuth && g.zHttpAuth[0] ){
const char *zCredentials = g.zHttpAuth;
char *zEncoded = encode64(zCredentials, -1);
blob_appendf(pHdr, "Authorization: Basic %s\r\n", zEncoded);
fossil_free(zEncoded);
}
blob_appendf(pHdr, "Host: %s\r\n", g.url.hostname);
blob_appendf(pHdr, "User-Agent: %s\r\n", get_user_agent());
if( g.url.isSsh ) blob_appendf(pHdr, "X-Fossil-Transport: SSH\r\n");
if( g.syncInfo.fLoginCardMode>0
&& nPayload>0 && pLogin && blob_size(pLogin) ){
/* Add sync login card via a transient cookie. We can only do this
if we know the remote supports it. */
blob_appendf(pHdr, "Cookie: x-f-l-c=%T\r\n", blob_str(pLogin));
}
if( nPayload ){
if( zAltMimetype ){
blob_appendf(pHdr, "Content-Type: %s\r\n", zAltMimetype);
}else if( g.fHttpTrace ){
blob_appendf(pHdr, "Content-Type: application/x-fossil-debug\r\n");
}else{
blob_appendf(pHdr, "Content-Type: application/x-fossil\r\n");
|
| ︙ | ︙ | |||
384 385 386 387 388 389 390 |
**
** * The ssh_needs_path_argument() function above.
** * The test-ssh-needs-path command that shows the settings
** that cache whether or not a PATH= is needed for a particular
** HOSTNAME.
*/
void ssh_add_path_argument(Blob *pCmd){
| | | 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 |
**
** * The ssh_needs_path_argument() function above.
** * The test-ssh-needs-path command that shows the settings
** that cache whether or not a PATH= is needed for a particular
** HOSTNAME.
*/
void ssh_add_path_argument(Blob *pCmd){
blob_append_escaped_arg(pCmd,
"PATH=$HOME/bin:/usr/local/bin:/opt/homebrew/bin:$PATH", 1);
}
/*
** Return the complete text of the last HTTP reply as saved in the
** http-reply-N.txt file. This only works if run using --httptrace.
** Without the --httptrace option, this routine returns a NULL pointer.
|
| ︙ | ︙ | |||
455 456 457 458 459 460 461 |
g.url.flags |= URL_SSH_PATH;
}
if( transport_open(&g.url) ){
fossil_warning("%s", transport_errmsg(&g.url));
return 1;
}
| < > < > > | > > > > > > > > > > > > > > > | > | | | | > | | 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 |
g.url.flags |= URL_SSH_PATH;
}
if( transport_open(&g.url) ){
fossil_warning("%s", transport_errmsg(&g.url));
return 1;
}
/* Construct the login card and prepare the complete payload */
blob_zero(&login);
if( blob_size(pSend)==0 ){
blob_zero(&payload);
}else{
if( mHttpFlags & HTTP_USE_LOGIN ) http_build_login_card(pSend, &login);
if( g.syncInfo.fLoginCardMode ){
/* The login card will be sent via an HTTP header and/or URL flag. */
if( g.fHttpTrace || (mHttpFlags & HTTP_NOCOMPRESS)!=0 ){
/* Maintenance note: we cannot blob_swap(pSend,&payload) here
** because the HTTP 401 and redirect response handling below
** needs pSend unmodified. payload won't be modified after
** this point, so we can make it a proxy for pSend for
** zero heap memory. */
blob_init(&payload, blob_buffer(pSend), blob_size(pSend));
}else{
blob_compress(pSend, &payload);
}
}else{
/* Prepend the login card (if set) to the payload */
if( blob_size(&login) ){
blob_append_char(&login, '\n');
}
if( g.fHttpTrace || (mHttpFlags & HTTP_NOCOMPRESS)!=0 ){
payload = login;
login = empty_blob/*transfer ownership*/;
blob_append(&payload, blob_buffer(pSend), blob_size(pSend));
}else{
blob_compress2(&login, pSend, &payload);
blob_reset(&login);
}
}
}
/* Construct the HTTP request header */
http_build_header(&payload, &hdr, &login, zAltMimetype);
/* When tracing, write the transmitted HTTP message both to standard
** output and into a file. The file can then be used to drive the
** server-side like this:
**
** ./fossil test-http <http-request-1.txt
*/
|
| ︙ | ︙ |
Changes to src/http_socket.c.
| ︙ | ︙ | |||
173 174 175 176 177 178 179 |
}
rc = getnameinfo(p->ai_addr, p->ai_addrlen, zRemote, sizeof(zRemote),
0, 0, NI_NUMERICHOST);
if( rc ){
socket_set_errmsg("getnameinfo() failed: %s", gai_strerror(rc));
goto end_socket_open;
}
| | | 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
}
rc = getnameinfo(p->ai_addr, p->ai_addrlen, zRemote, sizeof(zRemote),
0, 0, NI_NUMERICHOST);
if( rc ){
socket_set_errmsg("getnameinfo() failed: %s", gai_strerror(rc));
goto end_socket_open;
}
g.zIpAddr = fossil_strdup(zRemote);
break;
}
if( p==0 ){
socket_set_errmsg("cannot connect to host %s:%d", pUrlData->name,
pUrlData->port);
rc = 1;
}
|
| ︙ | ︙ |
Changes to src/http_ssl.c.
| ︙ | ︙ | |||
636 637 638 639 640 641 642 |
/* As soon as libressl implements
** BIO_ADDR_hostname_string/BIO_get_conn_address.
** check here for the correct LIBRESSL_VERSION_NUMBER too. For now: disable
*/
#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000L \
&& !defined(LIBRESSL_VERSION_NUMBER)
char *ip = BIO_ADDR_hostname_string(BIO_get_conn_address(iBio),1);
| | | 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 |
/* As soon as libressl implements
** BIO_ADDR_hostname_string/BIO_get_conn_address.
** check here for the correct LIBRESSL_VERSION_NUMBER too. For now: disable
*/
#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000L \
&& !defined(LIBRESSL_VERSION_NUMBER)
char *ip = BIO_ADDR_hostname_string(BIO_get_conn_address(iBio),1);
g.zIpAddr = fossil_strdup(ip);
OPENSSL_free(ip);
#else
/* IPv4 only code */
const unsigned char *ip;
ip = (const unsigned char*)BIO_ptr_ctrl(iBio,BIO_C_GET_CONNECT,2);
g.zIpAddr = mprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
#endif
|
| ︙ | ︙ |
Changes to src/http_transport.c.
| ︙ | ︙ | |||
119 120 121 122 123 124 125 | /* For SSH we need to create and run SSH fossil http ** to talk to the remote machine. */ Blob zCmd; /* The SSH command */ char *zHost; /* The host name to contact */ fossil_free(g.zIpAddr); | | | | 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
/* For SSH we need to create and run SSH fossil http
** to talk to the remote machine.
*/
Blob zCmd; /* The SSH command */
char *zHost; /* The host name to contact */
fossil_free(g.zIpAddr);
g.zIpAddr = fossil_strdup(pUrlData->name);
transport_ssh_command(&zCmd);
if( pUrlData->port!=pUrlData->dfltPort && pUrlData->port ){
blob_appendf(&zCmd, " -p %d", pUrlData->port);
}
blob_appendf(&zCmd, " -T --"); /* End of switches */
if( pUrlData->user && pUrlData->user[0] ){
zHost = mprintf("%s@%s", pUrlData->user, pUrlData->name);
blob_append_escaped_arg(&zCmd, zHost, 0);
fossil_free(zHost);
}else{
blob_append_escaped_arg(&zCmd, pUrlData->name, 0);
}
if( (pUrlData->flags & URL_SSH_EXE)!=0
&& !is_safe_fossil_command(pUrlData->fossil)
){
fossil_fatal("the ssh:// URL is asking to run an unsafe command [%s] on "
"the server.", pUrlData->fossil);
}
if( (pUrlData->flags & URL_SSH_EXE)==0
&& (pUrlData->flags & URL_SSH_PATH)!=0
){
ssh_add_path_argument(&zCmd);
}
blob_append_escaped_arg(&zCmd, pUrlData->fossil, 1);
blob_append(&zCmd, " test-http", 10);
if( pUrlData->path && pUrlData->path[0] ){
blob_append_escaped_arg(&zCmd, pUrlData->path, 1);
|
| ︙ | ︙ | |||
243 244 245 246 247 248 249 |
transport.isOpen = 0;
}
}
/*
** Send content over the wire.
*/
| | | 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 |
transport.isOpen = 0;
}
}
/*
** Send content over the wire.
*/
void transport_send(UrlData const *pUrlData, const Blob *toSend){
char *z = blob_buffer(toSend);
int n = blob_size(toSend);
transport.nSent += n;
if( pUrlData->isSsh ){
fwrite(z, 1, n, sshOut);
fflush(sshOut);
}else if( pUrlData->isHttps ){
|
| ︙ | ︙ |
Changes to src/import.c.
| ︙ | ︙ | |||
893 894 895 896 897 898 899 |
if( feof(pIn) ) return 0;
do{
char *sep;
if( zLine[0]=='\n' ) break;
rec->nHeaders += 1;
rec->aHeaders = fossil_realloc(rec->aHeaders,
sizeof(rec->aHeaders[0])*rec->nHeaders);
| | | 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 |
if( feof(pIn) ) return 0;
do{
char *sep;
if( zLine[0]=='\n' ) break;
rec->nHeaders += 1;
rec->aHeaders = fossil_realloc(rec->aHeaders,
sizeof(rec->aHeaders[0])*rec->nHeaders);
rec->aHeaders[rec->nHeaders-1].zKey = fossil_strdup(zLine);
sep = strchr(rec->aHeaders[rec->nHeaders-1].zKey, ':');
if( !sep ){
trim_newline(zLine);
fossil_fatal("bad header line: [%s]", zLine);
}
*sep = 0;
rec->aHeaders[rec->nHeaders-1].zVal = sep+1;
|
| ︙ | ︙ | |||
1424 1425 1426 1427 1428 1429 1430 |
fossil_free(gsvn.zUser);
fossil_free(gsvn.zComment);
fossil_free(gsvn.zDate);
bag_clear(&gsvn.newBranches);
}
/* start new revision */
gsvn.rev = atoi(zTemp);
| | | | 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 |
fossil_free(gsvn.zUser);
fossil_free(gsvn.zComment);
fossil_free(gsvn.zDate);
bag_clear(&gsvn.newBranches);
}
/* start new revision */
gsvn.rev = atoi(zTemp);
gsvn.zUser = fossil_strdup(svn_find_prop(rec, "svn:author"));
gsvn.zComment = fossil_strdup(svn_find_prop(rec, "svn:log"));
zDate = svn_find_prop(rec, "svn:date");
if( zDate ){
gsvn.zDate = date_in_standard_format(zDate);
}else{
gsvn.zDate = date_in_standard_format("now");
}
db_bind_int(&addRev, ":rev", gsvn.rev);
|
| ︙ | ︙ |
Changes to src/info.c.
| ︙ | ︙ | |||
1165 1166 1167 1168 1169 1170 1171 |
if( !PB("nowiki") ){
wiki_render_associated("checkin", zUuid, 0);
}
render_backlink_graph(zUuid,
"<div class=\"section accordion\">References</div>\n");
@ <div class="section accordion">Context</div><div class="accordion_panel">
render_checkin_context(rid, 0, 0, 0);
| | > | 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 |
if( !PB("nowiki") ){
wiki_render_associated("checkin", zUuid, 0);
}
render_backlink_graph(zUuid,
"<div class=\"section accordion\">References</div>\n");
@ <div class="section accordion">Context</div><div class="accordion_panel">
render_checkin_context(rid, 0, 0, 0);
@ </div><div class="section accordion" id="changes_section">Changes</div>
@ <div class="accordion_panel">
@ <div class="sectionmenu info-changes-menu">
/* ^^^ .info-changes-menu is used by diff scroll sync */
pCfg = construct_diff_flags(diffType, &DCfg);
DCfg.diffFlags |= DIFF_NUMSTAT; /* Show stats in the 'Changes' section */
DCfg.pRe = pRe;
zW = (DCfg.diffFlags&DIFF_IGNORE_ALLWS)?"&w":"";
if( diffType!=1 ){
@ %z(chref("button","%R/%s/%T?diff=1%s",zPage,zName,zW))\
@ Unified Diff</a>
}
if( diffType!=2 ){
|
| ︙ | ︙ | |||
1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 |
const char *zNew = db_column_text(&q3,3);
const char *zOldName = db_column_text(&q3, 4);
append_file_change_line(zUuid, zName, zOld, zNew, zOldName,
pCfg,mperm);
}
db_finalize(&q3);
@ </div>
append_diff_javascript(diffType);
style_finish_page();
}
/*
** WEBPAGE: winfo
** URL: /winfo?name=HASH
| > > > > > > > > | 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 |
const char *zNew = db_column_text(&q3,3);
const char *zOldName = db_column_text(&q3, 4);
append_file_change_line(zUuid, zName, zOld, zNew, zOldName,
pCfg,mperm);
}
db_finalize(&q3);
@ </div>
if( diffType!=0 ){
@ <script nonce='%h(style_nonce())'>;/* info.c:%d(__LINE__) */
@ document.getElementById('changes_section').textContent = 'Changes ' +
@ '(%d(g.diffCnt[0]) file' + (%d(g.diffCnt[0])===1 ? '' : 's') + ': ' +
@ '+%d(g.diffCnt[1]) ' +
@ '−%d(g.diffCnt[2]))'
@ </script>
}
append_diff_javascript(diffType);
style_finish_page();
}
/*
** WEBPAGE: winfo
** URL: /winfo?name=HASH
|
| ︙ | ︙ | |||
1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 |
int graphFlags = 0;
Blob qp; /* non-glob= query parameters for generated links */
Blob qpGlob; /* glob= query parameter for generated links */
int bInvert = PB("inv");
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
login_anonymous_available();
fossil_nice_default();
blob_init(&qp, 0, 0);
blob_init(&qpGlob, 0, 0);
diffType = preferred_diff_type();
zRe = P("regex");
if( zRe ) re_compile(&pRe, zRe, 0);
| > | 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 |
int graphFlags = 0;
Blob qp; /* non-glob= query parameters for generated links */
Blob qpGlob; /* glob= query parameter for generated links */
int bInvert = PB("inv");
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
if( robot_restrict("diff") ) return;
login_anonymous_available();
fossil_nice_default();
blob_init(&qp, 0, 0);
blob_init(&qpGlob, 0, 0);
diffType = preferred_diff_type();
zRe = P("regex");
if( zRe ) re_compile(&pRe, zRe, 0);
|
| ︙ | ︙ | |||
1916 1917 1918 1919 1920 1921 1922 1923 1924 |
** * The "diff" query parameter
** * The "diff" field of the user display cookie
** * The "preferred-diff-type" setting
** * 1 for mobile and 2 for desktop, based on the UserAgent
*/
int preferred_diff_type(void){
int dflt;
static char zDflt[2]
/*static b/c cookie_link_parameter() does not copy it!*/;
| > > > > > > | | > > | > > > > > | 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 |
** * The "diff" query parameter
** * The "diff" field of the user display cookie
** * The "preferred-diff-type" setting
** * 1 for mobile and 2 for desktop, based on the UserAgent
*/
int preferred_diff_type(void){
int dflt;
int res;
int isBot;
static char zDflt[2]
/*static b/c cookie_link_parameter() does not copy it!*/;
if( client_might_be_a_robot() ){
dflt = 0;
isBot = 1;
}else{
dflt = db_get_int("preferred-diff-type",-99);
if( dflt<=0 ) dflt = user_agent_is_likely_mobile() ? 1 : 2;
isBot = 0;
}
zDflt[0] = dflt + '0';
zDflt[1] = 0;
cookie_link_parameter("diff","diff", zDflt);
res = atoi(PD_NoBot("diff",zDflt));
if( isBot && res>0 && robot_restrict("diff") ){
cgi_reply();
fossil_exit(0);
}
return res;
}
/*
** WEBPAGE: fdiff
** URL: fdiff?v1=HASH&v2=HASH
**
|
| ︙ | ︙ | |||
1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 |
ReCompiled *pRe = 0;
u32 objdescFlags = 0;
int verbose = PB("verbose");
DiffConfig DCfg;
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
diff_config_init(&DCfg, 0);
diffType = preferred_diff_type();
if( P("from") && P("to") ){
v1 = artifact_from_ci_and_filename("from");
v2 = artifact_from_ci_and_filename("to");
if( v1==0 || v2==0 ) fossil_redirect_home();
}else{
| > | 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 |
ReCompiled *pRe = 0;
u32 objdescFlags = 0;
int verbose = PB("verbose");
DiffConfig DCfg;
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
if( robot_restrict("diff") ) return;
diff_config_init(&DCfg, 0);
diffType = preferred_diff_type();
if( P("from") && P("to") ){
v1 = artifact_from_ci_and_filename("from");
v2 = artifact_from_ci_and_filename("to");
if( v1==0 || v2==0 ) fossil_redirect_home();
}else{
|
| ︙ | ︙ | |||
2405 2406 2407 2408 2409 2410 2411 |
blob_zero(&downloadName);
if( P("verbose")!=0 ) objdescFlags |= OBJDESC_DETAIL;
object_description(rid, objdescFlags, 0, &downloadName);
style_submenu_element("Download", "%R/raw/%s?at=%T",
zUuid, file_tail(blob_str(&downloadName)));
@ <hr>
content_get(rid, &content);
| | | | 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 |
blob_zero(&downloadName);
if( P("verbose")!=0 ) objdescFlags |= OBJDESC_DETAIL;
object_description(rid, objdescFlags, 0, &downloadName);
style_submenu_element("Download", "%R/raw/%s?at=%T",
zUuid, file_tail(blob_str(&downloadName)));
@ <hr>
content_get(rid, &content);
if( blob_size(&content)>100000 ){
/* Prevent robots from running hexdump on megabyte-sized source files
** and there by eating up lots of CPU time and bandwidth. There is
** no good reason for a robot to need a hexdump. */
@ <p>A hex dump of this file is not available because it is too large.
@ Please download the raw binary file and generate a hex dump yourself.</p>
}else{
@ <blockquote><pre>
hexdump(&content);
@ </pre></blockquote>
}
style_finish_page();
|
| ︙ | ︙ | |||
2884 2885 2886 2887 2888 2889 2890 |
if( isSymbolicCI ){
zHeader = mprintf("%s at %s", file_tail(zName), zCI);
style_set_current_page("doc/%t/%T", zCI, zName);
}else if( zCIUuid && zCIUuid[0] ){
zHeader = mprintf("%s at [%S]", file_tail(zName), zCIUuid);
style_set_current_page("doc/%S/%T", zCIUuid, zName);
}else{
| | | 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 |
if( isSymbolicCI ){
zHeader = mprintf("%s at %s", file_tail(zName), zCI);
style_set_current_page("doc/%t/%T", zCI, zName);
}else if( zCIUuid && zCIUuid[0] ){
zHeader = mprintf("%s at [%S]", file_tail(zName), zCIUuid);
style_set_current_page("doc/%S/%T", zCIUuid, zName);
}else{
zHeader = fossil_strdup(file_tail(zName));
style_set_current_page("doc/tip/%T", zName);
}
}else if( descOnly ){
zHeader = mprintf("Artifact Description [%S]", zUuid);
}else{
zHeader = mprintf("Artifact [%S]", zUuid);
}
|
| ︙ | ︙ | |||
4238 4239 4240 4241 4242 4243 4244 |
descr->nCommitsSince = -1;
descr->zCommitHash = mprintf("");
descr->isDirty = -1;
return (rid-1);
}
zUuid = rid_to_uuid(rid);
| | | 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 |
descr->nCommitsSince = -1;
descr->zCommitHash = mprintf("");
descr->isDirty = -1;
return (rid-1);
}
zUuid = rid_to_uuid(rid);
descr->zCommitHash = fossil_strdup(zUuid);
descr->isDirty = unsaved_changes(0);
db_multi_exec(
"DROP TABLE IF EXISTS temp.singletonTag;"
"CREATE TEMP TABLE singletonTag("
" rid INT,"
" tagname TEXT,"
|
| ︙ | ︙ | |||
4287 4288 4289 4290 4291 4292 4293 |
" WHERE tagname IS NOT NULL"
" ORDER BY n LIMIT 1;",
rid, rid
);
if( db_step(&q)==SQLITE_ROW ){
const char *lastTag = db_column_text(&q, 0);
| | | 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 |
" WHERE tagname IS NOT NULL"
" ORDER BY n LIMIT 1;",
rid, rid
);
if( db_step(&q)==SQLITE_ROW ){
const char *lastTag = db_column_text(&q, 0);
descr->zRelTagname = fossil_strdup(lastTag);
descr->nCommitsSince = db_column_int(&q, 1);
nRet = 0;
}else{
/* no ancestor commit with a fitting singleton tag found */
descr->zRelTagname = mprintf("");
descr->nCommitsSince = -1;
nRet = -3;
|
| ︙ | ︙ |
Changes to src/json.c.
| ︙ | ︙ | |||
1641 1642 1643 1644 1645 1646 1647 |
** code must be in the inclusive range 1000..9999.
*/
int json_set_err( int code, char const * fmt, ... ){
assert( (code>=1000) && (code<=9999) );
fossil_free(g.zErrMsg);
g.json.resultCode = code;
if(!fmt || !*fmt){
| | | 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 |
** code must be in the inclusive range 1000..9999.
*/
int json_set_err( int code, char const * fmt, ... ){
assert( (code>=1000) && (code<=9999) );
fossil_free(g.zErrMsg);
g.json.resultCode = code;
if(!fmt || !*fmt){
g.zErrMsg = fossil_strdup(json_err_cstr(code));
}else{
va_list vargs;
char * msg;
va_start(vargs,fmt);
msg = vmprintf(fmt, vargs);
va_end(vargs);
g.zErrMsg = msg;
|
| ︙ | ︙ | |||
1959 1960 1961 1962 1963 1964 1965 | cson_object_set( obj, "permissionFlags", sub ); obj = cson_value_get_object(sub); #define ADD(X,K) cson_object_set(obj, K, cson_value_new_bool(g.perm.X)) ADD(Setup,"setup"); ADD(Admin,"admin"); ADD(Password,"password"); | < | 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 | cson_object_set( obj, "permissionFlags", sub ); obj = cson_value_get_object(sub); #define ADD(X,K) cson_object_set(obj, K, cson_value_new_bool(g.perm.X)) ADD(Setup,"setup"); ADD(Admin,"admin"); ADD(Password,"password"); ADD(Write,"checkin"); ADD(Read,"checkout"); ADD(Hyperlink,"history"); ADD(Clone,"clone"); ADD(RdWiki,"readWiki"); ADD(NewWiki,"createWiki"); ADD(ApndWiki,"appendWiki"); |
| ︙ | ︙ |
Changes to src/json_report.c.
| ︙ | ︙ | |||
200 201 202 203 204 205 206 |
}
limit = json_find_option_int("limit",NULL,"n",-1);
/* Copy over report's SQL...*/
blob_append(&sql, db_column_text(&q,0), -1);
| | | 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 |
}
limit = json_find_option_int("limit",NULL,"n",-1);
/* Copy over report's SQL...*/
blob_append(&sql, db_column_text(&q,0), -1);
zTitle = fossil_strdup(db_column_text(&q,1));
db_finalize(&q);
db_prepare(&q, "%s", blob_sql_text(&sql));
/** Build the response... */
pay = cson_new_object();
cson_object_set(pay, "report", json_new_int(nReport));
|
| ︙ | ︙ |
Changes to src/login.c.
| ︙ | ︙ | |||
158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
int uid; /* The user ID of anonymous */
int n = 0; /* Counter of captcha-secrets */
if( zUsername==0 ) return 0;
else if( zPassword==0 ) return 0;
else if( zCS==0 ) return 0;
else if( fossil_strcmp(zUsername,"anonymous")!=0 ) return 0;
while( 1/*exit-by-break*/ ){
zPw = captcha_decode((unsigned int)atoi(zCS), n);
if( zPw==0 ) return 0;
if( fossil_stricmp(zPw, zPassword)==0 ) break;
n++;
}
uid = db_int(0, "SELECT uid FROM user WHERE login='anonymous'"
| > | 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
int uid; /* The user ID of anonymous */
int n = 0; /* Counter of captcha-secrets */
if( zUsername==0 ) return 0;
else if( zPassword==0 ) return 0;
else if( zCS==0 ) return 0;
else if( fossil_strcmp(zUsername,"anonymous")!=0 ) return 0;
else if( anon_cookie_lifespan()==0 ) return 0;
while( 1/*exit-by-break*/ ){
zPw = captcha_decode((unsigned int)atoi(zCS), n);
if( zPw==0 ) return 0;
if( fossil_stricmp(zPw, zPassword)==0 ) break;
n++;
}
uid = db_int(0, "SELECT uid FROM user WHERE login='anonymous'"
|
| ︙ | ︙ | |||
336 337 338 339 340 341 342 343 344 345 346 347 |
fossil_free(zHash);
if( zDest ){
*zDest = zCookie;
}else{
free(zCookie);
}
}
/* Sets a cookie for an anonymous user login, which looks like this:
**
** HASH/TIME/anonymous
**
| > > > > > > > > > > > > > > > > > > > > > > > > | > > > > | > | | 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 |
fossil_free(zHash);
if( zDest ){
*zDest = zCookie;
}else{
free(zCookie);
}
}
/*
** SETTING: anon-cookie-lifespan width=10 default=480
** The number of minutes for which an anonymous login cookie is
** valid. Anonymous logins are prohibited if this value is zero.
*/
/*
** The default lifetime of an anoymous cookie, in minutes.
*/
#define ANONYMOUS_COOKIE_LIFESPAN (8*60)
/*
** Return the lifetime of an anonymous cookie, in minutes.
*/
int anon_cookie_lifespan(void){
static int lifespan = -1;
if( lifespan<0 ){
lifespan = db_get_int("anon-cookie-lifespan", ANONYMOUS_COOKIE_LIFESPAN);
if( lifespan<0 ) lifespan = 0;
}
return lifespan;
}
/* Sets a cookie for an anonymous user login, which looks like this:
**
** HASH/TIME/anonymous
**
** Where HASH is the sha1sum of TIME/USERAGENT/SECRET, in which SECRET
** is captcha-secret and USERAGENT is the HTTP_USER_AGENT value.
**
** If zCookieDest is not NULL then the generated cookie is assigned to
** *zCookieDest and the caller must eventually free() it.
**
** If bSessionCookie is true, the cookie will be a session cookie.
**
** Search for tag-20250817a to find the code that recognizes this cookie.
*/
void login_set_anon_cookie(char **zCookieDest, int bSessionCookie){
char *zNow; /* Current time (julian day number) */
char *zCookie; /* The login cookie */
const char *zUserAgent; /* The user agent */
const char *zCookieName; /* Name of the login cookie */
Blob b; /* Blob used during cookie construction */
int expires = bSessionCookie ? 0 : anon_cookie_lifespan();
zCookieName = login_cookie_name();
zNow = db_text("0", "SELECT julianday('now')");
assert( zCookieName && zNow );
blob_init(&b, zNow, -1);
zUserAgent = PD("HTTP_USER_AGENT","nil");
blob_appendf(&b, "/%s/%z", zUserAgent, captcha_secret(0));
sha1sum_blob(&b, &b);
zCookie = mprintf("%s/%s/anonymous", blob_buffer(&b), zNow);
blob_reset(&b);
cgi_set_cookie(zCookieName, zCookie, login_cookie_path(), expires);
if( zCookieDest ){
*zCookieDest = zCookie;
}else{
|
| ︙ | ︙ | |||
579 580 581 582 583 584 585 |
if( P("pwreset")!=0 && login_self_password_reset_available() ){
/* If the "Reset Password" button in the form was pressed, render
** the Request Password Reset page in place of this one. */
login_reqpwreset_page();
return;
}
| > > > > > > > > > > > > > > > | > > > | | 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 |
if( P("pwreset")!=0 && login_self_password_reset_available() ){
/* If the "Reset Password" button in the form was pressed, render
** the Request Password Reset page in place of this one. */
login_reqpwreset_page();
return;
}
/* If the "anon" query parameter is 1 or 2, that means rework the web-page
** to make it a more user-friendly captcha. Extraneous text and boxes
** are omitted. The user has just the captcha image and an entry box
** and a "Verify" button. Underneath is the same login page for user
** "anonymous", just displayed in an easier to digest format for one-time
** visitors.
**
** anon=1 is advisory and only has effect if there is not some other login
** cookie. anon=2 means always show the captcha.
*/
anonFlag = anon_cookie_lifespan()>0 ? atoi(PD("anon","0")) : 0;
if( anonFlag==2 ){
g.zLogin = 0;
}else{
login_check_credentials();
if( g.zLogin!=0 ) anonFlag = 0;
}
fossil_redirect_to_https_if_needed(1);
sqlite3_create_function(g.db, "constant_time_cmp", 2, SQLITE_UTF8, 0,
constant_time_cmp_function, 0, 0);
zUsername = P("u");
zPasswd = P("p");
/* Handle log-out requests */
if( P("out") && cgi_csrf_safe(2) ){
login_clear_login_data();
login_redirect_to_g();
return;
}
|
| ︙ | ︙ | |||
715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 |
*/
login_set_user_cookie(zUsername, uid, NULL, rememberMe?0:1);
login_redirect_to_g();
}
}
style_set_current_feature("login");
style_header("Login/Logout");
style_adunit_config(ADUNIT_OFF);
@ %s(zErrMsg)
if( zGoto && !noAnon ){
char *zAbbrev = fossil_strdup(zGoto);
int i;
for(i=0; zAbbrev[i] && zAbbrev[i]!='?'; i++){}
zAbbrev[i] = 0;
if( g.zLogin ){
@ <p>Use a different login with greater privilege than <b>%h(g.zLogin)</b>
@ to access <b>%h(zAbbrev)</b>.
}else if( anonFlag ){
| > | | > | | > | | | | | > | > > > > > | > | | | | | | | | | | > > > > > > | | > | | > | | > | | | | | > > | 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 |
*/
login_set_user_cookie(zUsername, uid, NULL, rememberMe?0:1);
login_redirect_to_g();
}
}
style_set_current_feature("login");
style_header("Login/Logout");
if( anonFlag==2 ) g.zLogin = 0;
style_adunit_config(ADUNIT_OFF);
@ %s(zErrMsg)
if( zGoto && !noAnon ){
char *zAbbrev = fossil_strdup(zGoto);
int i;
for(i=0; zAbbrev[i] && zAbbrev[i]!='?'; i++){}
zAbbrev[i] = 0;
if( g.zLogin ){
@ <p>Use a different login with greater privilege than <b>%h(g.zLogin)</b>
@ to access <b>%h(zAbbrev)</b>.
}else if( anonFlag ){
@ <p><b>Verify that you are human by typing in the 8-character text
@ password shown below.</b></p>
}else{
@ <p>Login as a named user to access page <b>%h(zAbbrev)</b>.
}
fossil_free(zAbbrev);
}
if( g.sslNotAvailable==0
&& strncmp(g.zBaseURL,"https:",6)!=0
&& db_get_boolean("https-login",0)
){
form_begin(0, "https:%s/login", g.zBaseURL+5);
}else{
form_begin(0, "%R/login");
}
if( zGoto ){
@ <input type="hidden" name="g" value="%h(zGoto)">
}
if( anonFlag ){
@ <input type="hidden" name="anon" value="1">
@ <input type="hidden" name="u" value="anonymous">
}
if( g.zLogin ){
@ <p>Currently logged in as <b>%h(g.zLogin)</b>.
@ <input type="submit" name="out" value="Logout" autofocus></p>
@ </form>
}else{
unsigned int uSeed = captcha_seed();
if( g.zLogin==0 && (anonFlag || zGoto==0) && anon_cookie_lifespan()>0 ){
zAnonPw = db_text(0, "SELECT pw FROM user"
" WHERE login='anonymous'"
" AND cap!=''");
}else{
zAnonPw = 0;
}
@ <table class="login_out">
if( P("HTTPS")==0 && !anonFlag ){
@ <tr><td class="form_label">Warning:</td>
@ <td><span class='securityWarning'>
@ Login information, including the password,
@ will be sent in the clear over an unencrypted connection.
if( !g.sslNotAvailable ){
@ Consider logging in at
@ <a href='%s(g.zHttpsURL)'>%h(g.zHttpsURL)</a> instead.
}
@ </span></td></tr>
}
if( !anonFlag ){
@ <tr>
@ <td class="form_label" id="userlabel1">User ID:</td>
@ <td><input type="text" id="u" aria-labelledby="userlabel1" name="u" \
@ size="30" value="" autofocus></td>
@ </tr>
}
@ <tr>
@ <td class="form_label" id="pswdlabel">Password:</td>
@ <td><input aria-labelledby="pswdlabel" type="password" id="p" \
@ name="p" value="" size="30"%s(anonFlag ? " autofocus" : "")>
if( anonFlag ){
@ </td></tr>
@ <tr>
@ <td></td><td>\
captcha_speakit_button(uSeed, "Read the password out loud");
}else if( zAnonPw && !noAnon ){
captcha_speakit_button(uSeed, "Speak password for \"anonymous\"");
}
@ </td>
@ </tr>
if( !anonFlag ){
@ <tr>
@ <td></td>
@ <td><input type="checkbox" name="remember" value="1" \
@ id="remember-me" %s(rememberMe ? "checked=\"checked\"" : "")>
@ <label for="remember-me">Remember me?</label></td>
@ </tr>
@ <tr>
@ <td></td>
@ <td><input type="submit" name="in" value="Login">
@ </tr>
}else{
@ <tr>
@ <td></td>
@ <td><input type="submit" name="in" value="Verify that I am human">
@ </tr>
}
if( !anonFlag && !noAnon && login_self_register_available(0) ){
@ <tr>
@ <td></td>
@ <td><input type="submit" name="self" value="Create A New Account">
@ </tr>
}
if( !anonFlag && login_self_password_reset_available() ){
@ <tr>
@ <td></td>
@ <td><input type="submit" name="pwreset" value="Reset My Password">
@ </tr>
}
@ </table>
if( zAnonPw && !noAnon ){
const char *zDecoded = captcha_decode(uSeed, 0);
int bAutoCaptcha = db_get_boolean("auto-captcha", 0);
char *zCaptcha = captcha_render(zDecoded);
@ <p><input type="hidden" name="cs" value="%u(uSeed)">
if( !anonFlag ){
@ Visitors may enter <b>anonymous</b> as the user-ID with
@ the 8-character hexadecimal password shown below:</p>
}
@ <div class="captcha"><table class="captcha"><tr><td>\
@ <pre class="captcha">
@ %h(zCaptcha)
@ </pre></td></tr></table>
if( bAutoCaptcha && !anonFlag ) {
@ <input type="button" value="Fill out captcha" id='autofillButton' \
@ data-af='%s(zDecoded)'>
builtin_request_js("login.js");
}
@ </div>
free(zCaptcha);
}
@ </form>
}
if( login_is_individual() && !anonFlag ){
if( g.perm.EmailAlert && alert_enabled() ){
@ <hr>
@ <p>Configure <a href="%R/alerts">Email Alerts</a>
@ for user <b>%h(g.zLogin)</b></p>
}
if( db_table_exists("repository","forumpost") ){
@ <hr><p>
@ <a href="%R/timeline?ss=v&y=f&vfx&u=%t(g.zLogin)">Forum
@ post timeline</a> for user <b>%h(g.zLogin)</b></p>
}
}
if( !anonFlag ){
@ <hr><p>
@ Select your preferred <a href="%R/skins">site skin</a>.
@ </p>
@ <hr><p>
@ Manage your <a href="%R/cookies">cookies</a> or your
@ <a href="%R/tokens">access tokens</a>.</p>
}
if( login_is_individual() ){
if( g.perm.Password ){
char *zRPW = fossil_random_password(12);
@ <hr>
@ <p>Change Password for user <b>%h(g.zLogin)</b>:</p>
form_begin(0, "%R/login");
@ <table>
|
| ︙ | ︙ | |||
1260 1261 1262 1263 1264 1265 1266 |
fossil_exit(0);
}
}
fossil_free(zDecode);
return uid;
}
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 |
fossil_exit(0);
}
}
fossil_free(zDecode);
return uid;
}
/*
** When this routine is called, we know that the request does not
** have a login on the present repository. This routine checks to
** see if their login cookie might be for another member of the
** login-group.
**
** If this repository is not a part of any login group, then this
|
| ︙ | ︙ | |||
1386 1387 1388 1389 1390 1391 1392 | ** is valid. If the login cookie checks out, it then sets global ** variables appropriately. ** ** g.userUid Database USER.UID value. Might be -1 for "nobody" ** g.zLogin Database USER.LOGIN value. NULL for user "nobody" ** g.perm Permissions granted to this user ** g.anon Permissions that would be available to anonymous | | | 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 |
** is valid. If the login cookie checks out, it then sets global
** variables appropriately.
**
** g.userUid Database USER.UID value. Might be -1 for "nobody"
** g.zLogin Database USER.LOGIN value. NULL for user "nobody"
** g.perm Permissions granted to this user
** g.anon Permissions that would be available to anonymous
** g.isRobot True if the client is known to be a spider or robot
** g.perm Populated based on user account's capabilities
**
*/
void login_check_credentials(void){
int uid = 0; /* User id */
const char *zCookie; /* Text of the login cookie */
const char *zIpAddr; /* Raw IP address of the requestor */
|
| ︙ | ︙ | |||
1427 1428 1429 1430 1431 1432 1433 |
uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", zLogin);
}else{
uid = db_int(0, "SELECT uid FROM user WHERE cap LIKE '%%s%%'");
}
g.zLogin = db_text("?", "SELECT login FROM user WHERE uid=%d", uid);
zCap = "sxy";
g.noPswd = 1;
| | | 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 |
uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", zLogin);
}else{
uid = db_int(0, "SELECT uid FROM user WHERE cap LIKE '%%s%%'");
}
g.zLogin = db_text("?", "SELECT login FROM user WHERE uid=%d", uid);
zCap = "sxy";
g.noPswd = 1;
g.isRobot = 0;
zSeed = db_text("??", "SELECT uid||quote(login)||quote(pw)||quote(cookie)"
" FROM user WHERE uid=%d", uid);
login_create_csrf_secret(zSeed);
fossil_free(zSeed);
}
/* Check the login cookie to see if it matches a known valid user.
|
| ︙ | ︙ | |||
1455 1456 1457 1458 1459 1460 1461 |
zUser = &zHash[i];
break;
}
}
}
if( zUser==0 ){
/* Invalid cookie */
| | > | > | > | > > | | | | 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 |
zUser = &zHash[i];
break;
}
}
}
if( zUser==0 ){
/* Invalid cookie */
}else if( fossil_strcmp(zUser, "anonymous")==0
&& anon_cookie_lifespan()>0 ){
/* Cookies of the form "HASH/TIME/anonymous". The TIME must
** not be more than ANONYMOUS_COOKIE_LIFESPAN seconds ago and
** the sha1 hash of TIME/USERAGENT/SECRET must match HASH. USERAGENT
** is the HTTP_USER_AGENT of the client and SECRET is the
** "captcha-secret" value in the repository. See tag-20250817a
** for the code the creates this cookie.
*/
double rTime = atof(zArg);
const char *zUserAgent = PD("HTTP_USER_AGENT","nil");
Blob b;
char *zSecret;
int n = 0;
do{
blob_zero(&b);
zSecret = captcha_secret(n++);
if( zSecret==0 ) break;
blob_appendf(&b, "%s/%s/%s", zArg, zUserAgent, zSecret);
sha1sum_blob(&b, &b);
if( fossil_strcmp(zHash, blob_str(&b))==0 ){
uid = db_int(0,
"SELECT uid FROM user WHERE login='anonymous'"
" AND octet_length(cap)>0"
" AND octet_length(pw)>0"
" AND %.17g>julianday('now')",
rTime+anon_cookie_lifespan()/1440.0
);
}
}while( uid==0 );
blob_reset(&b);
}else{
/* Cookies of the form "HASH/CODE/USER". Search first in the
** local user table, then the user table for project CODE if we
|
| ︙ | ︙ | |||
1557 1558 1559 1560 1561 1562 1563 |
zCap = "";
}
login_create_csrf_secret("none");
}
login_set_uid(uid, zCap);
| | | > > > | 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 |
zCap = "";
}
login_create_csrf_secret("none");
}
login_set_uid(uid, zCap);
/* Maybe restrict access by robots */
if( g.zLogin==0 && robot_restrict(g.zPath) ){
cgi_reply();
fossil_exit(0);
}
}
/*
** Set the current logged in user to be uid. zCap is precomputed
** (override) capabilities. If zCap==0, then look up the capabilities
** in the USER table.
*/
|
| ︙ | ︙ | |||
1597 1598 1599 1600 1601 1602 1603 |
** "nobody" user is a special case in that g.zLogin==0.
*/
g.userUid = uid;
if( fossil_strcmp(g.zLogin,"nobody")==0 ){
g.zLogin = 0;
}
if( PB("isrobot") ){
| | | | | | 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 |
** "nobody" user is a special case in that g.zLogin==0.
*/
g.userUid = uid;
if( fossil_strcmp(g.zLogin,"nobody")==0 ){
g.zLogin = 0;
}
if( PB("isrobot") ){
g.isRobot = 1;
}else if( g.zLogin==0 ){
g.isRobot = !isHuman(P("HTTP_USER_AGENT"));
}else{
g.isRobot = 0;
}
/* Set the capabilities */
login_replace_capabilities(zCap, 0);
/* The auto-hyperlink setting allows hyperlinks to be displayed for users
** who do not have the "h" permission as long as their UserAgent string
** makes it appear that they are human. Check to see if auto-hyperlink is
** enabled for this repository and make appropriate adjustments to the
** permission flags if it is. This should be done before the permissions
** are (potentially) copied to the anonymous permission set; otherwise,
** those will be out-of-sync.
*/
if( zCap[0] && !g.perm.Hyperlink && !g.isRobot ){
int autoLink = db_get_int("auto-hyperlink",1);
if( autoLink==1 ){
g.jsHref = 1;
g.perm.Hyperlink = 1;
}else if( autoLink==2 ){
g.perm.Hyperlink = 1;
}
|
| ︙ | ︙ | |||
1925 1926 1927 1928 1929 1930 1931 |
blob_appendf(&redir, "%s/login?g=%T", g.zHttpsURL, zPathInfo);
}else{
blob_appendf(&redir, "%R/login?g=%T", zPathInfo);
}
if( zQS && zQS[0] ){
blob_appendf(&redir, "%%3f%T", zQS);
}
| | | | 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 |
blob_appendf(&redir, "%s/login?g=%T", g.zHttpsURL, zPathInfo);
}else{
blob_appendf(&redir, "%R/login?g=%T", zPathInfo);
}
if( zQS && zQS[0] ){
blob_appendf(&redir, "%%3f%T", zQS);
}
if( anonOk ) blob_append(&redir, "&anon=1", 7);
cgi_redirect(blob_str(&redir));
/* NOTREACHED */
assert(0);
}
}
/*
** Call this routine if the user lacks g.perm.Hyperlink permission. If
** the anonymous user has Hyperlink permission, then paint a mesage
** to inform the user that much more information is available by
** logging in as anonymous.
*/
void login_anonymous_available(void){
if( !g.perm.Hyperlink && g.anon.Hyperlink && anon_cookie_lifespan()>0 ){
const char *zUrl = PD("PATH_INFO", "");
@ <p>Many <span class="disabled">hyperlinks are disabled.</span><br>
@ Use <a href="%R/login?anon=1&g=%T(zUrl)">anonymous login</a>
@ to enable hyperlinks.</p>
}
}
|
| ︙ | ︙ |
Changes to src/main.c.
| ︙ | ︙ | |||
81 82 83 84 85 86 87 |
/*
** Holds flags for fossil user permissions.
*/
struct FossilUserPerms {
char Setup; /* s: use Setup screens on web interface */
char Admin; /* a: administrative permission */
char Password; /* p: change password */
| < | 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
/*
** Holds flags for fossil user permissions.
*/
struct FossilUserPerms {
char Setup; /* s: use Setup screens on web interface */
char Admin; /* a: administrative permission */
char Password; /* p: change password */
char Write; /* i: xfer inbound. check-in */
char Read; /* o: xfer outbound. check-out */
char Hyperlink; /* h: enable the display of hyperlinks */
char Clone; /* g: clone */
char RdWiki; /* j: view wiki via web */
char NewWiki; /* f: create new wiki via web */
char ApndWiki; /* m: append to wiki via web */
|
| ︙ | ︙ | |||
232 233 234 235 236 237 238 |
#if USE_SEE
const char *zPidKey; /* Saved value of the --usepidkey option. Only
* applicable when using SEE on Windows or Linux. */
#endif
int useLocalauth; /* No login required if from 127.0.0.1 */
int noPswd; /* Logged in without password (on 127.0.0.1) */
int userUid; /* Integer user id */
| | > | 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 |
#if USE_SEE
const char *zPidKey; /* Saved value of the --usepidkey option. Only
* applicable when using SEE on Windows or Linux. */
#endif
int useLocalauth; /* No login required if from 127.0.0.1 */
int noPswd; /* Logged in without password (on 127.0.0.1) */
int userUid; /* Integer user id */
int isRobot; /* True if the client is definitely a robot. False
** negatives are common for this flag */
int comFmtFlags; /* Zero or more "COMMENT_PRINT_*" bit flags, should be
** accessed through get_comment_format(). */
const char *zSockName; /* Name of the unix-domain socket file */
const char *zSockMode; /* File permissions for unix-domain socket */
const char *zSockOwner; /* Owner, or owner:group for unix-domain socket */
/* Information used to populate the RCVFROM table */
|
| ︙ | ︙ | |||
287 288 289 290 291 292 293 294 295 296 297 298 299 300 |
const char **azAuxOpt[MX_AUX]; /* Options of each option() value */
int anAuxCols[MX_AUX]; /* Number of columns for option() values */
int allowSymlinks; /* Cached "allow-symlinks" option */
int mainTimerId; /* Set to fossil_timer_start() */
int nPendingRequest; /* # of HTTP requests in "fossil server" */
int nRequest; /* Total # of HTTP request */
int bAvoidDeltaManifests; /* Avoid using delta manifests if true */
#ifdef FOSSIL_ENABLE_JSON
struct FossilJsonBits {
int isJsonMode; /* True if running in JSON mode, else
false. This changes how errors are
reported. In JSON mode we try to
always output JSON-form error
responses and always (in CGI mode)
| > > > > > > > > > > > > > > > > > | 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 |
const char **azAuxOpt[MX_AUX]; /* Options of each option() value */
int anAuxCols[MX_AUX]; /* Number of columns for option() values */
int allowSymlinks; /* Cached "allow-symlinks" option */
int mainTimerId; /* Set to fossil_timer_start() */
int nPendingRequest; /* # of HTTP requests in "fossil server" */
int nRequest; /* Total # of HTTP request */
int bAvoidDeltaManifests; /* Avoid using delta manifests if true */
/* State for communicating specific details between the inbound HTTP
** header parser (cgi.c), xfer.c, and http.c. */
struct {
char *zLoginCard; /* Inbound "x-f-l-c" Cookie header. */
int fLoginCardMode; /* If non-0, emit login cards in outbound
** requests as a HTTP cookie instead of as
** part of the payload. Gets activated
** on-demand based on xfer traffic
** contents. Values, for
** diagnostic/debugging purposes: 0x01=CLI
** --flag, 0x02=cgi_setup_query_string(),
** 0x04=page_xfer(),
** 0x08=client_sync(). */
int remoteVersion; /* Remote fossil version. Used for negotiating
** how to handle the login card. */
} syncInfo;
#ifdef FOSSIL_ENABLE_JSON
struct FossilJsonBits {
int isJsonMode; /* True if running in JSON mode, else
false. This changes how errors are
reported. In JSON mode we try to
always output JSON-form error
responses and always (in CGI mode)
|
| ︙ | ︙ | |||
757 758 759 760 761 762 763 764 765 766 767 768 769 770 |
#ifdef FOSSIL_ENABLE_TCL
memset(&g.tcl, 0, sizeof(TclContext));
g.tcl.argc = g.argc;
g.tcl.argv = copy_args(g.argc, g.argv); /* save full arguments */
#endif
g.mainTimerId = fossil_timer_start();
capture_case_sensitive_option();
g.zVfsName = find_option("vfs",0,1);
if( g.zVfsName==0 ){
g.zVfsName = fossil_getenv("FOSSIL_VFS");
}
if( g.zVfsName ){
sqlite3_vfs *pVfs = sqlite3_vfs_find(g.zVfsName);
if( pVfs ){
| > > > > > > > | 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 |
#ifdef FOSSIL_ENABLE_TCL
memset(&g.tcl, 0, sizeof(TclContext));
g.tcl.argc = g.argc;
g.tcl.argv = copy_args(g.argc, g.argv); /* save full arguments */
#endif
g.mainTimerId = fossil_timer_start();
capture_case_sensitive_option();
g.syncInfo.fLoginCardMode =
/* The undocumented/unsupported --login-card-header provides a way
** to force use of the feature added by the xfer-login-card branch
** in 2025-07, intended for assisting in debugging any related
** issues. It can be removed once we reach the level of "implicit
** trust" in that feature. */
find_option("login-card-header",0,0) ? 0x01 : 0;
g.zVfsName = find_option("vfs",0,1);
if( g.zVfsName==0 ){
g.zVfsName = fossil_getenv("FOSSIL_VFS");
}
if( g.zVfsName ){
sqlite3_vfs *pVfs = sqlite3_vfs_find(g.zVfsName);
if( pVfs ){
|
| ︙ | ︙ | |||
1138 1139 1140 1141 1142 1143 1144 |
** the global state and return the new pointer, freeing any previous value.
** If absent and there is no cached value, return NULL.
*/
const char *find_repository_option(){
const char *zRepository = find_option("repository", "R", 1);
if( zRepository ){
if( g.zRepositoryOption ) fossil_free(g.zRepositoryOption);
| | | 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 |
** the global state and return the new pointer, freeing any previous value.
** If absent and there is no cached value, return NULL.
*/
const char *find_repository_option(){
const char *zRepository = find_option("repository", "R", 1);
if( zRepository ){
if( g.zRepositoryOption ) fossil_free(g.zRepositoryOption);
g.zRepositoryOption = fossil_strdup(zRepository);
}
return g.zRepositoryOption;
}
/*
** Verify that there are no unprocessed command-line options. If
** Any remaining command-line argument begins with "-" print
|
| ︙ | ︙ | |||
1384 1385 1386 1387 1388 1389 1390 |
const char *zHost;
const char *zMode;
const char *zCur;
if( g.zBaseURL!=0 ) return;
if( zAltBase ){
int i, n, c;
| | | | 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 |
const char *zHost;
const char *zMode;
const char *zCur;
if( g.zBaseURL!=0 ) return;
if( zAltBase ){
int i, n, c;
g.zTop = g.zBaseURL = fossil_strdup(zAltBase);
i = (int)strlen(g.zBaseURL);
while( i>3 && g.zBaseURL[i-1]=='/' ){ i--; }
g.zBaseURL[i] = 0;
if( strncmp(g.zTop, "http://", 7)==0 ){
/* it is HTTP, replace prefix with HTTPS. */
g.zHttpsURL = mprintf("https://%s", &g.zTop[7]);
}else if( strncmp(g.zTop, "https://", 8)==0 ){
/* it is already HTTPS, use it. */
g.zHttpsURL = fossil_strdup(g.zTop);
}else{
fossil_fatal("argument to --baseurl should be 'http://host/path'"
" or 'https://host/path'");
}
for(i=n=0; (c = g.zTop[i])!=0; i++){
if( c=='/' ){
n++;
|
| ︙ | ︙ | |||
1489 1490 1491 1492 1493 1494 1495 |
*/
NORETURN void fossil_redirect_home(void){
/* In order for ?skin=... to work when visiting the site from
** a typical external link, we have to process it here, as
** that parameter gets lost during the redirect. We "could"
** pass the whole query string along instead, but that seems
** unnecessary. */
| | | 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 |
*/
NORETURN void fossil_redirect_home(void){
/* In order for ?skin=... to work when visiting the site from
** a typical external link, we have to process it here, as
** that parameter gets lost during the redirect. We "could"
** pass the whole query string along instead, but that seems
** unnecessary. */
if(cgi_setup_query_string() & 0x02){
cookie_render();
}
cgi_redirectf("%R%s", db_get("index-page", "/index"));
}
/*
** If running as root, chroot to the directory containing the
|
| ︙ | ︙ | |||
1793 1794 1795 1796 1797 1798 1799 |
@ <!-- Looking for repository named "%h(zRepo)" -->
fprintf(stderr, "# looking for repository named \"%s\"\n", zRepo);
}
/* Restrictions on the URI for security:
**
| | | | | 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 |
@ <!-- Looking for repository named "%h(zRepo)" -->
fprintf(stderr, "# looking for repository named \"%s\"\n", zRepo);
}
/* Restrictions on the URI for security:
**
** 1. Reject characters that are not ASCII alphanumerics,
** "-", "_", ".", "/", or unicode (above ASCII).
** In other words: No ASCII punctuation or control characters
** other than "-", "_", "." and "/".
** 2. Exception to rule 1: Allow /X:/ where X is any ASCII
** alphabetic character at the beginning of the name on windows.
** 3. "-" may not occur immediately after "/"
** 4. "." may not be adjacent to another "." or to "/"
**
** Any character does not satisfy these constraints a Not Found
** error is returned.
*/
szFile = 0;
for(j=nBase+1, k=0; zRepo[j] && k<i-1; j++, k++){
char c = zRepo[j];
if( c>='a' && c<='z' ) continue;
if( c>='A' && c<='Z' ) continue;
if( c>='0' && c<='9' ) continue;
if( (c&0x80)==0x80 ) continue;
|
| ︙ | ︙ | |||
2070 2071 2072 2073 2074 2075 2076 |
#endif
if( g.useLocalauth && g.localOpen ){
cgi_redirectf("%R/ckout");
}else{
fossil_redirect_home() /*does not return*/;
}
}else{
| | | 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 |
#endif
if( g.useLocalauth && g.localOpen ){
cgi_redirectf("%R/ckout");
}else{
fossil_redirect_home() /*does not return*/;
}
}else{
zPath = fossil_strdup(zPathInfo);
}
/* Make g.zPath point to the first element of the path. Make
** g.zExtra point to everything past that point.
*/
g.zPath = &zPath[1];
for(i=1; zPath[i] && zPath[i]!='/'; i++){}
|
| ︙ | ︙ | |||
2481 2482 2483 2484 2485 2486 2487 |
/* directory: DIRECTORY
**
** If repository: is omitted, then terms of the PATH_INFO cgi parameter
** are appended to DIRECTORY looking for a repository (whose name ends
** in ".fossil") or a file in "files:".
*/
db_close(1);
| | | | 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 |
/* directory: DIRECTORY
**
** If repository: is omitted, then terms of the PATH_INFO cgi parameter
** are appended to DIRECTORY looking for a repository (whose name ends
** in ".fossil") or a file in "files:".
*/
db_close(1);
g.zRepositoryName = fossil_strdup(blob_str(&value));
blob_reset(&value);
continue;
}
if( blob_eq(&key, "notfound:") && blob_token(&line, &value) ){
/* notfound: URL
**
** If using directory: and no suitable repository or file is found,
** then redirect to URL.
*/
zNotFound = fossil_strdup(blob_str(&value));
blob_reset(&value);
continue;
}
if( blob_eq(&key, "localauth") ){
/* localauth
**
** Grant "administrator" privileges to users connecting with HTTP
|
| ︙ | ︙ | |||
2535 2536 2537 2538 2539 2540 2541 |
}
if( blob_eq(&key, "redirect:") && blob_token(&line, &value)
&& blob_token(&line, &value2) ){
/* See the header comment on the redirect_web_page() function
** above for details. */
nRedirect++;
azRedirect = fossil_realloc(azRedirect, 2*nRedirect*sizeof(char*));
| | | | 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 |
}
if( blob_eq(&key, "redirect:") && blob_token(&line, &value)
&& blob_token(&line, &value2) ){
/* See the header comment on the redirect_web_page() function
** above for details. */
nRedirect++;
azRedirect = fossil_realloc(azRedirect, 2*nRedirect*sizeof(char*));
azRedirect[nRedirect*2-2] = fossil_strdup(blob_str(&value));
azRedirect[nRedirect*2-1] = fossil_strdup(blob_str(&value2));
blob_reset(&value);
blob_reset(&value2);
continue;
}
if( blob_eq(&key, "files:") && blob_token(&line, &value) ){
/* files: GLOBLIST
**
|
| ︙ | ︙ | |||
2579 2580 2581 2582 2583 2584 2585 |
}
if( blob_eq(&key, "errorlog:") && blob_token(&line, &value) ){
/* errorlog: FILENAME
**
** Causes messages from warnings, errors, and panics to be appended
** to FILENAME.
*/
| | | | 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 |
}
if( blob_eq(&key, "errorlog:") && blob_token(&line, &value) ){
/* errorlog: FILENAME
**
** Causes messages from warnings, errors, and panics to be appended
** to FILENAME.
*/
g.zErrlog = fossil_strdup(blob_str(&value));
blob_reset(&value);
continue;
}
if( blob_eq(&key, "extroot:") && blob_token(&line, &value) ){
/* extroot: DIRECTORY
**
** Enables the /ext webpage to use sub-cgi rooted at DIRECTORY
*/
g.zExtRoot = fossil_strdup(blob_str(&value));
blob_reset(&value);
continue;
}
if( blob_eq(&key, "timeout:") && blob_token(&line, &value) ){
/* timeout: SECONDS
**
** Set an alarm() that kills the process after SECONDS. The
|
| ︙ | ︙ | |||
2649 2650 2651 2652 2653 2654 2655 |
if( blob_eq(&key, "mainmenu:") && blob_token(&line, &value) ){
/* mainmenu: FILENAME
**
** Use the contents of FILENAME as the value of the site's
** "mainmenu" setting, overriding the contents (for this
** request) of the db-side setting or the hard-coded default.
*/
| | | 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 |
if( blob_eq(&key, "mainmenu:") && blob_token(&line, &value) ){
/* mainmenu: FILENAME
**
** Use the contents of FILENAME as the value of the site's
** "mainmenu" setting, overriding the contents (for this
** request) of the db-side setting or the hard-coded default.
*/
g.zMainMenuFile = fossil_strdup(blob_str(&value));
blob_reset(&value);
continue;
}
if( blob_eq(&key, "cgi-debug:") && blob_token(&line, &value) ){
/* cgi-debug: FILENAME
**
** Causes output from cgi_debug() and CGIDEBUG(()) calls to go
|
| ︙ | ︙ | |||
2706 2707 2708 2709 2710 2711 2712 |
static void find_server_repository(int arg, int fCreate){
if( g.argc<=arg ){
db_must_be_within_tree();
}else{
const char *zRepo = g.argv[arg];
int isDir = file_isdir(zRepo, ExtFILE);
if( isDir==1 ){
| | | 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 |
static void find_server_repository(int arg, int fCreate){
if( g.argc<=arg ){
db_must_be_within_tree();
}else{
const char *zRepo = g.argv[arg];
int isDir = file_isdir(zRepo, ExtFILE);
if( isDir==1 ){
g.zRepositoryName = fossil_strdup(zRepo);
file_simplify_name(g.zRepositoryName, -1, 0);
}else{
if( isDir==0 && fCreate ){
const char *zPassword;
db_create_repository(zRepo);
db_open_repository(zRepo);
db_begin_transaction();
|
| ︙ | ︙ | |||
2918 2919 2920 2921 2922 2923 2924 |
/* The winhttp module passes the --files option as --files-urlenc with
** the argument being URL encoded, to avoid wildcard expansion in the
** shell. This option is for internal use and is undocumented.
*/
zFileGlob = find_option("files-urlenc",0,1);
if( zFileGlob ){
| | | 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 |
/* The winhttp module passes the --files option as --files-urlenc with
** the argument being URL encoded, to avoid wildcard expansion in the
** shell. This option is for internal use and is undocumented.
*/
zFileGlob = find_option("files-urlenc",0,1);
if( zFileGlob ){
char *z = fossil_strdup(zFileGlob);
dehttpize(z);
zFileGlob = z;
}else{
zFileGlob = find_option("files",0,1);
}
skin_override();
zNotFound = find_option("notfound", 0, 1);
|
| ︙ | ︙ | |||
3328 3329 3330 3331 3332 3333 3334 |
g.zErrlog = "-";
}
g.zExtRoot = find_option("extroot",0,1);
zJsMode = find_option("jsmode",0,1);
builtin_set_js_delivery_mode(zJsMode,0);
zFileGlob = find_option("files-urlenc",0,1);
if( zFileGlob ){
| | | 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 |
g.zErrlog = "-";
}
g.zExtRoot = find_option("extroot",0,1);
zJsMode = find_option("jsmode",0,1);
builtin_set_js_delivery_mode(zJsMode,0);
zFileGlob = find_option("files-urlenc",0,1);
if( zFileGlob ){
char *z = fossil_strdup(zFileGlob);
dehttpize(z);
zFileGlob = z;
}else{
zFileGlob = find_option("files",0,1);
}
skin_override();
#if !defined(_WIN32)
|
| ︙ | ︙ | |||
3509 3510 3511 3512 3513 3514 3515 |
if( zRemote ){
/* If a USER@HOST:REPO argument is supplied, then use SSH to run
** "fossil ui --nobrowser" on the remote system and to set up a
** tunnel from the local machine to the remote. */
FILE *sshIn;
Blob ssh;
int bRunning = 0; /* True when fossil starts up on the remote */
| | | 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 |
if( zRemote ){
/* If a USER@HOST:REPO argument is supplied, then use SSH to run
** "fossil ui --nobrowser" on the remote system and to set up a
** tunnel from the local machine to the remote. */
FILE *sshIn;
Blob ssh;
int bRunning = 0; /* True when fossil starts up on the remote */
int isRetry; /* True if on the second attempt */
char zLine[1000];
blob_init(&ssh, 0, 0);
for(isRetry=0; isRetry<2 && !bRunning; isRetry++){
blob_reset(&ssh);
transport_ssh_command(&ssh);
blob_appendf(&ssh,
|
| ︙ | ︙ | |||
3548 3549 3550 3551 3552 3553 3554 |
if( skin_in_use() ) blob_appendf(&ssh, " --skin %s", skin_in_use());
if( zJsMode ) blob_appendf(&ssh, " --jsmode %s", zJsMode);
if( fCreate ) blob_appendf(&ssh, " --create");
blob_appendf(&ssh, " %$", g.argv[2]);
if( isRetry ){
fossil_print("First attempt to run \"fossil\" on %s failed\n"
"Retry: ", zRemote);
| | | 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 |
if( skin_in_use() ) blob_appendf(&ssh, " --skin %s", skin_in_use());
if( zJsMode ) blob_appendf(&ssh, " --jsmode %s", zJsMode);
if( fCreate ) blob_appendf(&ssh, " --create");
blob_appendf(&ssh, " %$", g.argv[2]);
if( isRetry ){
fossil_print("First attempt to run \"fossil\" on %s failed\n"
"Retry: ", zRemote);
}
fossil_print("%s\n", blob_str(&ssh));
sshIn = popen(blob_str(&ssh), "r");
if( sshIn==0 ){
fossil_fatal("unable to %s", blob_str(&ssh));
}
while( fgets(zLine, sizeof(zLine), sshIn) ){
fputs(zLine, stdout);
|
| ︙ | ︙ |
Changes to src/main.mk.
| ︙ | ︙ | |||
117 118 119 120 121 122 123 124 125 126 127 128 129 130 | $(SRCDIR)/printf.c \ $(SRCDIR)/publish.c \ $(SRCDIR)/purge.c \ $(SRCDIR)/rebuild.c \ $(SRCDIR)/regexp.c \ $(SRCDIR)/repolist.c \ $(SRCDIR)/report.c \ $(SRCDIR)/rss.c \ $(SRCDIR)/schema.c \ $(SRCDIR)/search.c \ $(SRCDIR)/security_audit.c \ $(SRCDIR)/setup.c \ $(SRCDIR)/setupuser.c \ $(SRCDIR)/sha1.c \ | > | 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | $(SRCDIR)/printf.c \ $(SRCDIR)/publish.c \ $(SRCDIR)/purge.c \ $(SRCDIR)/rebuild.c \ $(SRCDIR)/regexp.c \ $(SRCDIR)/repolist.c \ $(SRCDIR)/report.c \ $(SRCDIR)/robot.c \ $(SRCDIR)/rss.c \ $(SRCDIR)/schema.c \ $(SRCDIR)/search.c \ $(SRCDIR)/security_audit.c \ $(SRCDIR)/setup.c \ $(SRCDIR)/setupuser.c \ $(SRCDIR)/sha1.c \ |
| ︙ | ︙ | |||
383 384 385 386 387 388 389 390 391 392 393 394 395 396 | $(OBJDIR)/printf_.c \ $(OBJDIR)/publish_.c \ $(OBJDIR)/purge_.c \ $(OBJDIR)/rebuild_.c \ $(OBJDIR)/regexp_.c \ $(OBJDIR)/repolist_.c \ $(OBJDIR)/report_.c \ $(OBJDIR)/rss_.c \ $(OBJDIR)/schema_.c \ $(OBJDIR)/search_.c \ $(OBJDIR)/security_audit_.c \ $(OBJDIR)/setup_.c \ $(OBJDIR)/setupuser_.c \ $(OBJDIR)/sha1_.c \ | > | 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 | $(OBJDIR)/printf_.c \ $(OBJDIR)/publish_.c \ $(OBJDIR)/purge_.c \ $(OBJDIR)/rebuild_.c \ $(OBJDIR)/regexp_.c \ $(OBJDIR)/repolist_.c \ $(OBJDIR)/report_.c \ $(OBJDIR)/robot_.c \ $(OBJDIR)/rss_.c \ $(OBJDIR)/schema_.c \ $(OBJDIR)/search_.c \ $(OBJDIR)/security_audit_.c \ $(OBJDIR)/setup_.c \ $(OBJDIR)/setupuser_.c \ $(OBJDIR)/sha1_.c \ |
| ︙ | ︙ | |||
533 534 535 536 537 538 539 540 541 542 543 544 545 546 | $(OBJDIR)/printf.o \ $(OBJDIR)/publish.o \ $(OBJDIR)/purge.o \ $(OBJDIR)/rebuild.o \ $(OBJDIR)/regexp.o \ $(OBJDIR)/repolist.o \ $(OBJDIR)/report.o \ $(OBJDIR)/rss.o \ $(OBJDIR)/schema.o \ $(OBJDIR)/search.o \ $(OBJDIR)/security_audit.o \ $(OBJDIR)/setup.o \ $(OBJDIR)/setupuser.o \ $(OBJDIR)/sha1.o \ | > | 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 | $(OBJDIR)/printf.o \ $(OBJDIR)/publish.o \ $(OBJDIR)/purge.o \ $(OBJDIR)/rebuild.o \ $(OBJDIR)/regexp.o \ $(OBJDIR)/repolist.o \ $(OBJDIR)/report.o \ $(OBJDIR)/robot.o \ $(OBJDIR)/rss.o \ $(OBJDIR)/schema.o \ $(OBJDIR)/search.o \ $(OBJDIR)/security_audit.o \ $(OBJDIR)/setup.o \ $(OBJDIR)/setupuser.o \ $(OBJDIR)/sha1.o \ |
| ︙ | ︙ | |||
876 877 878 879 880 881 882 883 884 885 886 887 888 889 | $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h \ $(OBJDIR)/publish_.c:$(OBJDIR)/publish.h \ $(OBJDIR)/purge_.c:$(OBJDIR)/purge.h \ $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h \ $(OBJDIR)/regexp_.c:$(OBJDIR)/regexp.h \ $(OBJDIR)/repolist_.c:$(OBJDIR)/repolist.h \ $(OBJDIR)/report_.c:$(OBJDIR)/report.h \ $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h \ $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h \ $(OBJDIR)/search_.c:$(OBJDIR)/search.h \ $(OBJDIR)/security_audit_.c:$(OBJDIR)/security_audit.h \ $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h \ $(OBJDIR)/setupuser_.c:$(OBJDIR)/setupuser.h \ $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h \ | > | 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 | $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h \ $(OBJDIR)/publish_.c:$(OBJDIR)/publish.h \ $(OBJDIR)/purge_.c:$(OBJDIR)/purge.h \ $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h \ $(OBJDIR)/regexp_.c:$(OBJDIR)/regexp.h \ $(OBJDIR)/repolist_.c:$(OBJDIR)/repolist.h \ $(OBJDIR)/report_.c:$(OBJDIR)/report.h \ $(OBJDIR)/robot_.c:$(OBJDIR)/robot.h \ $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h \ $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h \ $(OBJDIR)/search_.c:$(OBJDIR)/search.h \ $(OBJDIR)/security_audit_.c:$(OBJDIR)/security_audit.h \ $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h \ $(OBJDIR)/setupuser_.c:$(OBJDIR)/setupuser.h \ $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h \ |
| ︙ | ︙ | |||
1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 | $(OBJDIR)/report_.c: $(SRCDIR)/report.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/report.c >$@ $(OBJDIR)/report.o: $(OBJDIR)/report_.c $(OBJDIR)/report.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/report.o -c $(OBJDIR)/report_.c $(OBJDIR)/report.h: $(OBJDIR)/headers $(OBJDIR)/rss_.c: $(SRCDIR)/rss.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/rss.c >$@ $(OBJDIR)/rss.o: $(OBJDIR)/rss_.c $(OBJDIR)/rss.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/rss.o -c $(OBJDIR)/rss_.c | > > > > > > > > | 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 | $(OBJDIR)/report_.c: $(SRCDIR)/report.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/report.c >$@ $(OBJDIR)/report.o: $(OBJDIR)/report_.c $(OBJDIR)/report.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/report.o -c $(OBJDIR)/report_.c $(OBJDIR)/report.h: $(OBJDIR)/headers $(OBJDIR)/robot_.c: $(SRCDIR)/robot.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/robot.c >$@ $(OBJDIR)/robot.o: $(OBJDIR)/robot_.c $(OBJDIR)/robot.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/robot.o -c $(OBJDIR)/robot_.c $(OBJDIR)/robot.h: $(OBJDIR)/headers $(OBJDIR)/rss_.c: $(SRCDIR)/rss.c $(OBJDIR)/translate $(OBJDIR)/translate $(SRCDIR)/rss.c >$@ $(OBJDIR)/rss.o: $(OBJDIR)/rss_.c $(OBJDIR)/rss.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/rss.o -c $(OBJDIR)/rss_.c |
| ︙ | ︙ |
Changes to src/merge.c.
| ︙ | ︙ | |||
479 480 481 482 483 484 485 |
" FROM event WHERE objid=%d", rid, rid, rid);
if( db_step(&q)==SQLITE_ROW ){
const char *zTagList = db_column_text(&q, 4);
char *zCom;
if( zTagList && zTagList[0] ){
zCom = mprintf("%s (%s)", db_column_text(&q, 2), zTagList);
}else{
| | | 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 |
" FROM event WHERE objid=%d", rid, rid, rid);
if( db_step(&q)==SQLITE_ROW ){
const char *zTagList = db_column_text(&q, 4);
char *zCom;
if( zTagList && zTagList[0] ){
zCom = mprintf("%s (%s)", db_column_text(&q, 2), zTagList);
}else{
zCom = fossil_strdup(db_column_text(&q,2));
}
fossil_print("%-*s [%S] by %s on %s\n%*s",
indent-1, zLabel,
db_column_text(&q, 3),
db_column_text(&q, 1),
db_column_text(&q, 0),
indent, "");
|
| ︙ | ︙ |
Changes to src/name.c.
| ︙ | ︙ | |||
579 580 581 582 583 584 585 |
/* symbolic-name ":" date-time */
nTag = strlen(zTag);
for(i=0; i<nTag-8 && zTag[i]!=':'; i++){}
if( zTag[i]==':'
&& (fossil_isdate(&zTag[i+1]) || fossil_expand_datetime(&zTag[i+1],0,0)!=0)
){
| | | 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 |
/* symbolic-name ":" date-time */
nTag = strlen(zTag);
for(i=0; i<nTag-8 && zTag[i]!=':'; i++){}
if( zTag[i]==':'
&& (fossil_isdate(&zTag[i+1]) || fossil_expand_datetime(&zTag[i+1],0,0)!=0)
){
char *zDate = fossil_strdup(&zTag[i+1]);
char *zTagBase = mprintf("%.*s", i, zTag);
char *zXDate;
int nDate = strlen(zDate);
if( sqlite3_strnicmp(&zDate[nDate-3],"utc",3)==0 ){
zDate[nDate-3] = 'z';
zDate[nDate-2] = 0;
}
|
| ︙ | ︙ | |||
984 985 986 987 988 989 990 |
if( zName==0 || zName[0]==0 || zSrc==0 || zSrc[0]==0 ){
fossil_redirect_home();
}
style_header("Ambiguous Artifact ID");
@ <p>The artifact hash prefix <b>%h(zName)</b> is ambiguous and might
@ mean any of the following:
@ <ol>
| | | 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 |
if( zName==0 || zName[0]==0 || zSrc==0 || zSrc[0]==0 ){
fossil_redirect_home();
}
style_header("Ambiguous Artifact ID");
@ <p>The artifact hash prefix <b>%h(zName)</b> is ambiguous and might
@ mean any of the following:
@ <ol>
z = fossil_strdup(zName);
canonical16(z, strlen(z));
db_prepare(&q, "SELECT uuid, rid FROM blob WHERE uuid GLOB '%q*'", z);
while( db_step(&q)==SQLITE_ROW ){
const char *zUuid = db_column_text(&q, 0);
int rid = db_column_int(&q, 1);
@ <li><p><a href="%R/%T(zSrc)/%!S(zUuid)">
@ %s(zUuid)</a> -
|
| ︙ | ︙ |
Changes to src/pikchrshow.c.
| ︙ | ︙ | |||
460 461 462 463 464 465 466 |
CX(" selected, only that part is evaluated.\n*/\n");
CX("%s</textarea></div>",zContent/*safe-for-%s*/);
} CX("</fieldset><!-- .zone-wrapper.input -->");
CX("<fieldset class='zone-wrapper output'>"); {
CX("<legend><div class='button-bar'>");
CX("<button id='btn-render-mode'>Render Mode</button> ");
CX("<span style='white-space:nowrap'>"
| | | | 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 |
CX(" selected, only that part is evaluated.\n*/\n");
CX("%s</textarea></div>",zContent/*safe-for-%s*/);
} CX("</fieldset><!-- .zone-wrapper.input -->");
CX("<fieldset class='zone-wrapper output'>"); {
CX("<legend><div class='button-bar'>");
CX("<button id='btn-render-mode'>Render Mode</button> ");
CX("<span style='white-space:nowrap'>"
"<button id='preview-copy-button' "
"title='Tap to copy to clipboard.'><span></span></button>"
"<label for='preview-copy-button' "
"title='Tap to copy to clipboard.'></label>"
"</span>");
CX("</div></legend>");
CX("<div id='pikchr-output-wrapper'>");
CX("<div id='pikchr-output'></div>");
CX("<textarea class='hidden' id='pikchr-output-text'></textarea>");
|
| ︙ | ︙ |
Changes to src/repolist.c.
| ︙ | ︙ | |||
245 246 247 248 249 250 251 |
if( nName<nSuffix ) continue;
zUrl = sqlite3_mprintf("%.*s", nName-nSuffix, zName);
if( zName[0]=='/'
#ifdef _WIN32
|| sqlite3_strglob("[a-zA-Z]:/*", zName)==0
#endif
){
| | | | | 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 |
if( nName<nSuffix ) continue;
zUrl = sqlite3_mprintf("%.*s", nName-nSuffix, zName);
if( zName[0]=='/'
#ifdef _WIN32
|| sqlite3_strglob("[a-zA-Z]:/*", zName)==0
#endif
){
zFull = fossil_strdup(zName);
}else if ( allRepo ){
zFull = mprintf("/%s", zName);
}else{
zFull = mprintf("%s/%s", g.zRepositoryName, zName);
}
x.zRepoName = zFull;
remote_repo_info(&x);
if( x.isRepolistSkin ){
if( zSkinRepo==0 ){
zSkinRepo = fossil_strdup(x.zRepoName);
zSkinUrl = fossil_strdup(zUrl);
}
}
fossil_free(zFull);
if( !x.isValid
#if USE_SEE
&& !bEncrypted
#endif
|
| ︙ | ︙ |
Added src/robot.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 |
/*
** Copyright (c) 2025 D. Richard Hipp
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the Simplified BSD License (also
** known as the "2-Clause License" or "FreeBSD License".)
** This program is distributed in the hope that it will be useful,
** but without any warranty; without even the implied warranty of
** merchantability or fitness for a particular purpose.
**
** Author contact information:
** drh@hwaci.com
** http://www.hwaci.com/drh/
**
*******************************************************************************
**
** This file contains code that attempts to prevent robots and
** especially bot-nets from consume excess CPU and bandwidth when
** Fossil is run as a service.
*/
#include "config.h"
#include "robot.h"
#include <assert.h>
#include <time.h>
/*
** The name of the cookie used to demonstrate that the client has been
** tested and is believed to be operated by a human, not by a robot.
*/
#if INTERFACE
#define ROBOT_COOKIE "fossil-client-ok"
#endif
/*
** Values computed only once and then cached.
*/
static struct RobotCache {
unsigned int h1, h2; /* Proof-of-work hash values */
unsigned int resultCache; /* 0: unknown. 1: human 2: might-be-robot */
} robot = { 0, 0, 0 };
/*
** Allowed values for robot.resultCache
*/
#define KNOWN_NOT_ROBOT 1
#define MIGHT_BE_ROBOT 2
/*
** Compute two hashes, robot.h1 and robot.h2, that are used as
** part of determining whether or not the HTTP client is a robot.
** These hashes are based on current time, client IP address,
** and User-Agent. robot.h1 is for the current time slot and
** robot.h2 is the previous.
**
** The hashes are integer values between 100,000,000 and 999,999,999
** inclusive.
*/
static void robot_pow_hash(void){
const char *az[2], *z;
sqlite3_int64 tm;
unsigned int h1, h2, k;
if( robot.h1 ) return; /* Already computed */
/* Construct a proof-of-work value based on the IP address of the
** sender and the sender's user-agent string. The current time also
** affects the pow value, so actually compute two values, one for the
** current 900-second interval and one for the previous. Either can
** match. The pow-value is an integer between 100,000,000 and
** 999,999,999.
*/
az[0] = P("REMOTE_ADDR");
az[1] = P("HTTP_USER_AGENT");
tm = time(0);
h1 = (unsigned)(tm/900)&0xffffffff;
h2 = h1 - 1;
for(k=0; k<2; k++){
z = az[k];
if( z==0 ) continue;
while( *z ){
h1 = (h1 + *(unsigned char*)z)*0x9e3779b1;
h2 = (h2 + *(unsigned char*)z)*0x9e3779b1;
z++;
}
}
robot.h1 = (h1 % 900000000) + 100000000;
robot.h2 = (h2 % 900000000) + 100000000;
}
/*
** Return true if the HTTP client has not demonstrated that it is
** human interactive. Return false is the HTTP client might be
** a non-interactive robot.
**
** For this routine, any of the following is considered proof that
** the HTTP client is not a robot:
**
** 1. There is a valid login, including "anonymous". User "nobody"
** is not a valid login, but every other user is.
**
** 2. There exists a ROBOT_COOKIE with the correct proof-of-work
** value.
**
** 3. There exists a proof=VALUE query parameter where VALUE is
** a correct proof-of-work value.
**
** 4. There exists a valid token=VALUE query parameter.
**
** After being run once, this routine caches its findings and
** returns very quickly on subsequent invocations.
*/
int client_might_be_a_robot(void){
const char *z;
/* Only do this computation once, then cache the results for future
** use */
if( robot.resultCache ){
return robot.resultCache==MIGHT_BE_ROBOT;
}
/* Condition 1: Is there a valid login?
*/
if( g.userUid==0 ){
login_check_credentials();
}
if( g.zLogin!=0 ){
robot.resultCache = KNOWN_NOT_ROBOT;
return 0;
}
/* Condition 2: If there is already a proof-of-work cookie
** with a correct value, then the user agent has been authenticated.
*/
z = P(ROBOT_COOKIE);
if( z ){
unsigned h = atoi(z);
robot_pow_hash();
if( (h==robot.h1 || h==robot.h2) && !cgi_is_qp(ROBOT_COOKIE) ){
robot.resultCache = KNOWN_NOT_ROBOT;
return 0;
}
}
/* Condition 3: There is a "proof=VALUE" query parameter with a valid
** VALUE attached. If this is the case, also set the robot cookie
** so that future requests will hit condition 2 above.
*/
z = P("proof");
if( z ){
unsigned h = atoi(z);
robot_pow_hash();
if( h==robot.h1 || h==robot.h2 ){
cgi_set_cookie(ROBOT_COOKIE,z,"/",900);
robot.resultCache = KNOWN_NOT_ROBOT;
return 0;
}
cgi_tag_query_parameter("proof");
}
/* Condition 4: If there is a "token=VALUE" query parameter with a
** valid VALUE argument, then assume that the request is coming from
** either an interactive human session, or an authorized robot that we
** want to treat as human. All it through and also set the robot cookie.
*/
z = P("token");
if( z!=0 ){
if( db_exists("SELECT 1 FROM config"
" WHERE name='token-%q'"
" AND json_valid(value,6)"
" AND value->>'user' IS NOT NULL", z)
){
char *zVal;
robot_pow_hash();
zVal = mprintf("%u", robot.h1);
cgi_set_cookie(ROBOT_COOKIE,zVal,"/",900);
fossil_free(zVal);
robot.resultCache = KNOWN_NOT_ROBOT;
return 0; /* There is a valid token= query parameter */
}
cgi_tag_query_parameter("token");
}
/* We have no proof that the request is coming from an interactive
** human session, so assume the request comes from a robot.
*/
robot.resultCache = MIGHT_BE_ROBOT;
return 1;
}
/*
** Rewrite the current page with content that attempts
** to prove that the client is not a robot.
*/
static void ask_for_proof_that_client_is_not_robot(void){
unsigned p1, p2, p3, p4, p5, k2, k3;
int k;
/* Ask the client to present proof-of-work */
cgi_reset_content();
cgi_set_content_type("text/html");
style_header("Browser Verification");
@ <h1 id="x1">Checking to see if you are a robot<span id="x2"></span></h1>
@ <form method="GET" id="x6"><p>
@ <span id="x3" style="visibility:hidden;">\
@ Press <input type="submit" id="x5" value="Ok" focus> to continue</span>
@ <span id="x7" style="visibility:hidden;">You appear to be a robot.</span>\
@ </p>
cgi_tag_query_parameter("name");
cgi_query_parameters_to_hidden();
@ <input id="x4" type="hidden" name="proof" value="0">
@ </form>
@ <script nonce='%s(style_nonce())'>
@ function aaa(x){return document.getElementById(x);}\
@ function bbb(h,a){\
@ aaa("x4").value=h;\
@ if((a%%75)==0){\
@ aaa("x2").textContent=aaa("x2").textContent+".";\
@ }var z;\
@ if(a>0){\
@ setTimeout(bbb,1,h+a,a-1);\
@ }else if((z=window.getComputedStyle(document.body).zIndex)==='0'||z===0){\
@ aaa("x3").style.visibility="visible";\
@ aaa("x2").textContent="";\
@ aaa("x1").textContent="All clear";\
@ aaa("x6").onsubmit=function(){aaa("x3").style.visibility="hidden";};\
@ aaa("x5").focus();\
@ }else{\
@ aaa("x7").style.visibility="visible";\
@ aaa("x2").textContent="";\
@ aaa("x3").style.display="none";\
@ aaa("x1").textContent="Access Denied";\
@ }\
@ }\
robot_pow_hash();
k = 400 + robot.h2%299;
k2 = (robot.h2/299)%99 + 973;
k3 = (robot.h2/(299*99))%99 + 811;
p1 = (k*k + k)/2;
p2 = robot.h1-p1;
p3 = p2%k2;
p4 = (p2/k2)%k3;
p5 = p2/(k2*k3);
@ function ccc(a,b,c){return (a*%u(k3)+b)*%u(k2)+c;}\
@ window.addEventListener('load',function(){\
@ bbb(ccc(%u(p5),%u(p4),%u(p3)),%u(k));},false);
@ </script>
style_finish_page();
}
/*
** SETTING: robot-restrict width=40 block-text
** The VALUE of this setting is a list of GLOB patterns that match
** pages for which complex HTTP requests from unauthenicated clients
** should be disallowed. "Unauthenticated" means the user is "nobody".
** The recommended value for this setting is:
**
** timelineX,diff,annotate,zip,fileage,file,finfo
**
** The "diff" tag covers all diffing pages such as /vdiff, /fdiff, and
** /vpatch. The "annotate" tag also covers /blame and /praise. "zip"
** also covers /tarball and /sqlar. If a tag has an "X" character appended,
** then it only applies if query parameters are such that the page is
** particularly difficult to compute. In all other case, the tag should
** exactly match the page name.
**
** Change this setting "off" to disable all robot restrictions.
*/
/*
** Return the default restriction GLOB
*/
const char *robot_restrict_default(void){
return "timelineX,diff,annotate,zip,fileage,file,finfo";
}
/*
** Return true if zTag matches one of the tags in the robot-restrict
** setting.
*/
int robot_restrict_has_tag(const char *zTag){
static const char *zGlob = 0;
if( zGlob==0 ){
zGlob = db_get("robot-restrict",robot_restrict_default());
if( zGlob==0 ) zGlob = "";
}
if( zGlob[0]==0 || fossil_strcmp(zGlob, "off")==0 ){
return 0;
}
return glob_multi_match(zGlob,zTag);
}
/*
** Check to see if the page named in the argument is on the
** robot-restrict list. If it is on the list and if the user
** is "nobody" then bring up a captcha to test to make sure that
** client is not a robot.
**
** This routine returns true if a captcha was rendered and if subsequent
** page generation should be aborted. It returns false if the page
** should not be restricted and should be rendered normally.
*/
int robot_restrict(const char *zTag){
if( robot.resultCache==KNOWN_NOT_ROBOT ) return 0;
if( !robot_restrict_has_tag(zTag) ) return 0;
if( !client_might_be_a_robot() ) return 0;
/* Generate the proof-of-work captcha */
ask_for_proof_that_client_is_not_robot();
return 1;
}
/*
** WEBPAGE: test-robotck
**
** Run the robot_restrict() function using the value of the "name="
** query parameter as an argument. Used for testing the robot_restrict()
** logic.
**
** Whenever this page is successfully rendered (when it doesn't go to
** the captcha) it deletes the proof-of-work cookie. So reloading the
** page will reset the cookie and restart the verification.
*/
void robot_restrict_test_page(void){
const char *zName = P("name");
const char *zP1 = P("proof");
const char *zP2 = P(ROBOT_COOKIE);
const char *z;
if( zName==0 || zName[0]==0 ) zName = g.zPath;
login_check_credentials();
if( g.zLogin==0 ){ login_needed(1); return; }
g.zLogin = 0;
if( robot_restrict(zName) ) return;
style_set_current_feature("test");
style_header("robot_restrict() test");
@ <h1>Captcha passed</h1>
@
@ <p>
if( zP1 && zP1[0] ){
@ proof=%h(zP1)<br>
}
if( zP2 && zP2[0] ){
@ %h(ROBOT_COOKIE)=%h(zP2)<br>
cgi_set_cookie(ROBOT_COOKIE,"",0,-1);
}
if( g.perm.Admin ){
z = db_get("robot-restrict",robot_restrict_default());
if( z && z[0] ){
@ robot-restrict=%h(z)</br>
}
@ robot.h1=%u(robot.h1)<br>
@ robot.h2=%u(robot.h2)<br>
switch( robot.resultCache ){
case MIGHT_BE_ROBOT: {
@ robot.resultCache=MIGHT_BE_ROBOT<br>
break;
}
case KNOWN_NOT_ROBOT: {
@ robot.resultCache=KNOWN_NOT_ROBOT<br>
break;
}
default: {
@ robot.resultCache=OTHER (%d(robot.resultCache))<br>
break;
}
}
}
@ </p>
@ <p><a href="%R/test-robotck/%h(zName)">Retry</a>
style_finish_page();
}
/*
** WEBPAGE: tokens
**
** Allow users to create, delete, and view their access token.
**
** The access token is a string TOKEN which if included in a query
** parameter like "token=TOKEN" authenticates a request as coming
** from an authorized agent. This can be used, for example, by
** script to access content without running into problems with
** robot defenses.
*/
void tokens_page(void){
char *zMyToken;
login_check_credentials();
style_set_current_feature("tokens");
style_header("Access Tokens");
if( g.zLogin==0 || fossil_strcmp(g.zLogin,"anonymous")==0 ){
@ User "%h(g.zLogin?g.zLogin:"anonymous")" is not allowed to
@ own or use access tokens.
style_finish_page();
return;
}
if( g.perm.Admin && P("del")!=0 ){
const char *zDel = P("del");
db_unprotect(PROTECT_CONFIG);
db_multi_exec(
"DELETE FROM config WHERE name='token-%q'",
zDel);
db_protect_pop();
}
zMyToken = db_text(0,
"SELECT substr(name,7) FROM config"
" WHERE name GLOB 'token-*'"
" AND json_valid(value,6)"
" AND value->>'user' = %Q",
g.zLogin
);
if( zMyToken==0 && P("new") ){
sqlite3_uint64 r;
sqlite3_randomness(sizeof(r),&r);
zMyToken = mprintf("%016llx", r);
db_unprotect(PROTECT_CONFIG);
db_multi_exec(
"INSERT INTO config(name,value,mtime)"
"VALUES('token-%q','{user:%!j}',now())",
zMyToken, g.zLogin
);
db_protect_pop();
}else if( zMyToken!=0 && P("selfdel")
&& fossil_strcmp(zMyToken,P("selfdel"))==0 ){
db_unprotect(PROTECT_CONFIG);
db_multi_exec(
"DELETE FROM config WHERE name='token-%q'",
zMyToken);
db_protect_pop();
zMyToken = 0;
}
if( zMyToken==0 ){
@ <p>You do not currently have an access token.
@ <a href="%R/tokens?new=true">Create one</a>
}else{
@ <p>Your access token is "%h(zMyToken)".
@ <p>Use this token as the value of the token= query parameter
@ to bypass robot defenses on unauthenticated queries to this
@ server (%R). Do not misuse your token. Keep it confidential.
@ If you misuse your token, or if somebody else steals your token
@ and misuses, that can result in loss of access privileges to this
@ server.
@ <p><a href="%R/tokens?selfdel=%h(zMyToken)">Delete my token</a>
}
if( g.perm.Admin ){
int nTok = 0;
Stmt s;
db_prepare(&s,
"SELECT substr(name,7), value->>'user', datetime(mtime,'unixepoch')"
" FROM config"
" WHERE name GLOB 'token-*'"
" AND json_valid(value,6)"
);
while( db_step(&s)==SQLITE_ROW ){
if( nTok==0 ){
@ <hr>
@ <p>All tokens</p>
@ <table border="1" cellpadding="5" cellspacing="0">
@ <tr><th>User <th>Token <th>Date <th> </tr>
}
nTok++;
@ <tr><td>%h(db_column_text(&s,1))
@ <td>%h(db_column_text(&s,0))
@ <td>%h(db_column_text(&s,2))
@ <td><a href="%R/tokens?del=%h(db_column_text(&s,0))">delete</a>
@ </tr>
}
db_finalize(&s);
if( nTok==0 ){
@ <hr>
@ <p>There are access tokens defined for this repository.
}else{
@ </table>
}
}
style_finish_page();
}
|
Changes to src/search.c.
| ︙ | ︙ | |||
128 129 130 131 132 133 134 |
if( fSrchFlg & SRCHFLG_STATIC ){
p = &gSearch;
search_end(p);
}else{
p = fossil_malloc(sizeof(*p));
memset(p, 0, sizeof(*p));
}
| | | | | | 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
if( fSrchFlg & SRCHFLG_STATIC ){
p = &gSearch;
search_end(p);
}else{
p = fossil_malloc(sizeof(*p));
memset(p, 0, sizeof(*p));
}
p->zPattern = z = fossil_strdup(zPattern);
p->zMarkBegin = fossil_strdup(zMarkBegin);
p->zMarkEnd = fossil_strdup(zMarkEnd);
p->zMarkGap = fossil_strdup(zMarkGap);
p->fSrchFlg = fSrchFlg;
blob_init(&p->snip, 0, 0);
while( *z && p->nTerm<SEARCH_MAX_TERM ){
while( *z && !ISALNUM(*z) ){ z++; }
if( *z==0 ) break;
p->a[p->nTerm].z = z;
for(i=1; ISALNUM(z[i]); i++){}
|
| ︙ | ︙ | |||
1074 1075 1076 1077 1078 1079 1080 |
** replaces all non-alphanum ASCII characters with a space, and
** lower-cases all upper-case ASCII characters. The intent is to avoid
** causing errors in FTS5 searches with inputs which contain AND, OR,
** and symbols like #. The caller is responsible for passing the
** result to fossil_free().
*/
char *search_simplify_pattern(const char * zPattern){
| | | 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 |
** replaces all non-alphanum ASCII characters with a space, and
** lower-cases all upper-case ASCII characters. The intent is to avoid
** causing errors in FTS5 searches with inputs which contain AND, OR,
** and symbols like #. The caller is responsible for passing the
** result to fossil_free().
*/
char *search_simplify_pattern(const char * zPattern){
char *zPat = fossil_strdup(zPattern);
int i;
for(i=0; zPat[i]; i++){
if( (zPat[i]&0x80)==0 && !fossil_isalnum(zPat[i]) ) zPat[i] = ' ';
if( fossil_isupper(zPat[i]) ) zPat[i] = fossil_tolower(zPat[i]);
}
for(i--; i>=0 && zPat[i]==' '; i--){}
if( i<0 ){
|
| ︙ | ︙ |
Changes to src/setup.c.
| ︙ | ︙ | |||
419 420 421 422 423 424 425 426 |
"2", "UserAgent only",
"1", "UserAgent and Javascript",
};
multiple_choice_attribute(
"Enable hyperlinks base on User-Agent and/or Javascript",
"auto-hyperlink", "autohyperlink", "1",
count(azDefenseOpts)/2, azDefenseOpts);
@ <p>Enable hyperlinks (the equivalent of the "h" permission) for all users,
| > > > > > > | < > > | | | < < < < < < < < < < < < | < < < < < < < < < < < < | > | | < < | 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 |
"2", "UserAgent only",
"1", "UserAgent and Javascript",
};
multiple_choice_attribute(
"Enable hyperlinks base on User-Agent and/or Javascript",
"auto-hyperlink", "autohyperlink", "1",
count(azDefenseOpts)/2, azDefenseOpts);
@ <br>
entry_attribute("Delay in milliseconds before enabling hyperlinks", 5,
"auto-hyperlink-delay", "ah-delay", "50", 0);
@ <br>
onoff_attribute("Also require a mouse event before enabling hyperlinks",
"auto-hyperlink-mouseover", "ahmo", 0, 0);
@ <p>Enable hyperlinks (the equivalent of the "h" permission) for all users,
@ including user "nobody" if the request appears to be from a human.
@ Disabling hyperlinks helps prevent robots from walking your site and
@ soaking up all your CPU and bandwidth.
@ If this setting is "UserAgent only" (2) then the
@ UserAgent string is the only factor considered. If the value of this
@ setting is "UserAgent And Javascript" (1) then Javascript is added that
@ runs after the page loads and fills in the href= values of <a>
@ elements. In either case, <a> tags are not generated if the
@ UserAgent string indicates that the client is a robot.
@ (Property: "auto-hyperlink")</p>
@
@ <p>For maximum robot defense, "Delay" should be at least 50 milliseconds
@ and "require a mouse event" should be turned on. These values only come
@ into play when the main auto-hyperlink settings is 2 ("UserAgent and
@ Javascript").
@ (Properties: "auto-hyperlink-delay" and "auto-hyperlink-mouseover")</p>
@
@ <p>To see if Javascript-base hyperlink enabling mechanism is working,
@ visit the <a href="%R/test-env">/test-env</a> page from a separate
@ web browser that is not logged in, even as "anonymous" and verify
@ that the "g.jsHref" value is "1".</p>
}
/*
** WEBPAGE: setup_robot
**
** Settings associated with defense against robots. Requires setup privilege.
*/
|
| ︙ | ︙ | |||
492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 |
@
@ <p>The settings on this page are intended to help site administrators
@ defend the site against robots.
@
@ <form action="%R/setup_robot" method="post"><div>
login_insert_csrf_secret();
@ <input type="submit" name="submit" value="Apply Changes"></p>
@ <hr>
addAutoHyperlinkSettings();
@ <hr>
entry_attribute("Server Load Average Limit", 11, "max-loadavg", "mxldavg",
"0.0", 0);
@ <p>Some expensive operations (such as computing tarballs, zip archives,
@ or annotation/blame pages) are prohibited if the load average on the host
@ computer is too large. Set the threshold for disallowing expensive
@ computations here. Set this to 0.0 to disable the load average limit.
@ This limit is only enforced on Unix servers. On Linux systems,
@ access to the /proc virtual filesystem is required, which means this limit
@ might not work inside a chroot() jail.
@ (Property: "max-loadavg")</p>
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < < < < < < < < < < < < < < < < < < < < < < < < < < | 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 |
@
@ <p>The settings on this page are intended to help site administrators
@ defend the site against robots.
@
@ <form action="%R/setup_robot" method="post"><div>
login_insert_csrf_secret();
@ <input type="submit" name="submit" value="Apply Changes"></p>
@ <hr>
@ <p><b>Do not allow robots access to these pages.</b>
@ <p> If the page name matches the GLOB pattern of this setting, and the
@ users is "nobody", and the client has not previously passed a captcha
@ test to show that it is not a robot, then the page is not displayed.
@ A captcha test is is rendered instead.
@ The recommended value for this setting is:
@ <p>
@    <tt>%h(robot_restrict_default())</tt>
@ <p>
@ The "diff" tag covers all diffing pages such as /vdiff, /fdiff, and
@ /vpatch. The "annotate" tag covers /annotate and also /blame and
@ /praise. The "zip" covers itself and also /tarball and /sqlar. If a
@ tag has an "X" character appended, then it only applies if query
@ parameters are such that the page is particularly difficult to compute.
@ In all other case, the tag should exactly match the page name.
@
@ To disable robot restrictions, change this setting to "off".
@ (Property: robot-restrict)
@ <br>
textarea_attribute("", 2, 80,
"robot-restrict", "rbrestrict", robot_restrict_default(), 0);
@ <hr>
addAutoHyperlinkSettings();
@ <hr>
entry_attribute("Anonymous Login Validity", 11, "anon-cookie-lifespan",
"anoncookls", "840", 0);
@ <p>The number of minutes for which an anonymous login cookie is valid.
@ Set to zero to disable anonymous login.
@ (property: anon-cookie-lifespan)
@ <hr>
entry_attribute("Server Load Average Limit", 11, "max-loadavg", "mxldavg",
"0.0", 0);
@ <p>Some expensive operations (such as computing tarballs, zip archives,
@ or annotation/blame pages) are prohibited if the load average on the host
@ computer is too large. Set the threshold for disallowing expensive
@ computations here. Set this to 0.0 to disable the load average limit.
@ This limit is only enforced on Unix servers. On Linux systems,
@ access to the /proc virtual filesystem is required, which means this limit
@ might not work inside a chroot() jail.
@ (Property: "max-loadavg")</p>
@
@ <hr>
@ <p><input type="submit" name="submit" value="Apply Changes"></p>
@ </div></form>
db_end_transaction(0);
style_finish_page();
}
|
| ︙ | ︙ | |||
772 773 774 775 776 777 778 779 780 781 782 783 784 785 |
"auto-captcha", "autocaptcha", 0, 0);
@ <p>When enabled, a button appears on the login screen for user
@ "anonymous" that will automatically fill in the CAPTCHA password.
@ This is less secure than forcing the user to do it manually, but is
@ probably secure enough and it is certainly more convenient for
@ anonymous users. (Property: "auto-captcha")</p>
@ <hr>
@ <p><input type="submit" name="submit" value="Apply Changes"></p>
@ </div></form>
db_end_transaction(0);
style_finish_page();
}
| > > > > > > > | 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 |
"auto-captcha", "autocaptcha", 0, 0);
@ <p>When enabled, a button appears on the login screen for user
@ "anonymous" that will automatically fill in the CAPTCHA password.
@ This is less secure than forcing the user to do it manually, but is
@ probably secure enough and it is certainly more convenient for
@ anonymous users. (Property: "auto-captcha")</p>
@ <hr>
entry_attribute("Anonymous Login Validity", 11, "anon-cookie-lifespan",
"anoncookls", "840", 0);
@ <p>The number of minutes for which an anonymous login cookie is valid.
@ Set to zero to disable anonymous logins.
@ (property: anon-cookie-lifespan)
@ <hr>
@ <p><input type="submit" name="submit" value="Apply Changes"></p>
@ </div></form>
db_end_transaction(0);
style_finish_page();
}
|
| ︙ | ︙ |
Changes to src/sha1.c.
| ︙ | ︙ | |||
418 419 420 421 422 423 424 | unsigned char zResult[20]; char zDigest[41]; SHA1Init(&ctx); SHA1Update(&ctx, (unsigned const char*)zIn, strlen(zIn)); SHA1Final(zResult, &ctx); DigestToBase16(zResult, zDigest); | | | 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 | unsigned char zResult[20]; char zDigest[41]; SHA1Init(&ctx); SHA1Update(&ctx, (unsigned const char*)zIn, strlen(zIn)); SHA1Final(zResult, &ctx); DigestToBase16(zResult, zDigest); return fossil_strdup(zDigest); } /* ** Convert a cleartext password for a specific user into a SHA1 hash. ** ** The algorithm here is: ** |
| ︙ | ︙ | |||
457 458 459 460 461 462 463 |
if( zProjectId==0 ){
zProjectId = db_get("project-code", 0);
/* On the first xfer request of a clone, the project-code is not yet
** known. Use the cleartext password, since that is all we have.
*/
if( zProjectId==0 ){
| | | | 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 |
if( zProjectId==0 ){
zProjectId = db_get("project-code", 0);
/* On the first xfer request of a clone, the project-code is not yet
** known. Use the cleartext password, since that is all we have.
*/
if( zProjectId==0 ){
return fossil_strdup(zPw);
}
}
zProjCode = zProjectId;
}
SHA1Update(&ctx, (unsigned char*)zProjCode, strlen(zProjCode));
SHA1Update(&ctx, (unsigned char*)"/", 1);
SHA1Update(&ctx, (unsigned char*)zLogin, strlen(zLogin));
SHA1Update(&ctx, (unsigned char*)"/", 1);
SHA1Update(&ctx, (unsigned const char*)zPw, strlen(zPw));
SHA1Final(zResult, &ctx);
DigestToBase16(zResult, zDigest);
return fossil_strdup(zDigest);
}
/*
** Implement the shared_secret() SQL function. shared_secret() takes two or
** three arguments; the third argument is optional.
**
** (1) The cleartext password
|
| ︙ | ︙ |
Changes to src/sha3.c.
| ︙ | ︙ | |||
610 611 612 613 614 615 616 |
char *sha3sum(const char *zIn, int iSize){
SHA3Context ctx;
char zDigest[132];
SHA3Init(&ctx, iSize);
SHA3Update(&ctx, (unsigned const char*)zIn, strlen(zIn));
DigestToBase16(SHA3Final(&ctx), zDigest, iSize/8);
| | | 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 |
char *sha3sum(const char *zIn, int iSize){
SHA3Context ctx;
char zDigest[132];
SHA3Init(&ctx, iSize);
SHA3Update(&ctx, (unsigned const char*)zIn, strlen(zIn));
DigestToBase16(SHA3Final(&ctx), zDigest, iSize/8);
return fossil_strdup(zDigest);
}
#endif
/*
** COMMAND: sha3sum*
**
** Usage: %fossil sha3sum FILE...
|
| ︙ | ︙ |
Changes to src/stash.c.
| ︙ | ︙ | |||
560 561 562 563 564 565 566 567 568 569 570 571 572 573 |
**
** > fossil stash diff ?STASHID? ?DIFF-OPTIONS?
** > fossil stash gdiff ?STASHID? ?DIFF-OPTIONS?
**
** Show diffs of the current working directory and what that
** directory would be if STASHID were applied. With gdiff,
** gdiff-command is used instead of internal diff logic.
*/
void stash_cmd(void){
const char *zCmd;
int nCmd;
int stashid = 0;
undo_capture_command_line();
db_must_be_within_tree();
| > > > > | 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 |
**
** > fossil stash diff ?STASHID? ?DIFF-OPTIONS?
** > fossil stash gdiff ?STASHID? ?DIFF-OPTIONS?
**
** Show diffs of the current working directory and what that
** directory would be if STASHID were applied. With gdiff,
** gdiff-command is used instead of internal diff logic.
**
** > fossil stash rename STASHID NEW-NAME
**
** Change the description of the given STASHID entry to NEW-NAME.
*/
void stash_cmd(void){
const char *zCmd;
int nCmd;
int stashid = 0;
undo_capture_command_line();
db_must_be_within_tree();
|
| ︙ | ︙ | |||
769 770 771 772 773 774 775 |
diff_tk(fBaseline ? "stash show" : "stash diff", 3);
return;
}
diff_options(&DCfg, zCmd[0]=='g', 0);
stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0);
stash_diff(stashid, fBaseline, &DCfg);
}else
| > > > > > > | | 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 |
diff_tk(fBaseline ? "stash show" : "stash diff", 3);
return;
}
diff_options(&DCfg, zCmd[0]=='g', 0);
stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0);
stash_diff(stashid, fBaseline, &DCfg);
}else
if( strncmp(zCmd, "rename", nCmd)==0 ){
if( g.argc!=5 ) usage("rename STASHID NAME");
stashid = stash_get_id(g.argv[3]);
db_multi_exec("UPDATE STASH SET COMMENT=%Q WHERE stashid=%d",
g.argv[4], stashid);
}
else if( strncmp(zCmd, "help", nCmd)==0 ){
g.argv[1] = "help";
g.argv[2] = "stash";
g.argc = 3;
help_cmd();
}else
{
usage("SUBCOMMAND ARGS...");
}
db_end_transaction(0);
}
|
Changes to src/style.c.
| ︙ | ︙ | |||
476 477 478 479 480 481 482 | } /* ** Output TEXT with a click-to-copy button next to it. Loads the copybtn.js ** Javascript module, and generates HTML elements with the following IDs: ** ** TARGETID: The <span> wrapper around TEXT. | | | 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 | } /* ** Output TEXT with a click-to-copy button next to it. Loads the copybtn.js ** Javascript module, and generates HTML elements with the following IDs: ** ** TARGETID: The <span> wrapper around TEXT. ** copy-TARGETID: The <button> for the copy button. ** ** If the FLIPPED argument is non-zero, the copy button is displayed after TEXT. ** ** The COPYLENGTH argument defines the length of the substring of TEXT copied to ** clipboard: ** ** <= 0: No limit (default if the argument is omitted). |
| ︙ | ︙ | |||
508 509 510 511 512 513 514 |
zText = vmprintf(zTextFmt/*works-like:?*/,ap);
va_end(ap);
if( cchLength==1 ) cchLength = hash_digits(0);
else if( cchLength==2 ) cchLength = hash_digits(1);
if( !bFlipped ){
const char *zBtnFmt =
"<span class=\"nobr\">"
| | | | | | > | > | | | | | | | > | > | 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 |
zText = vmprintf(zTextFmt/*works-like:?*/,ap);
va_end(ap);
if( cchLength==1 ) cchLength = hash_digits(0);
else if( cchLength==2 ) cchLength = hash_digits(1);
if( !bFlipped ){
const char *zBtnFmt =
"<span class=\"nobr\">"
"<button "
"class=\"copy-button\" "
"id=\"copy-%h\" "
"data-copytarget=\"%h\" "
"data-copylength=\"%d\">"
"<span>"
"</span>"
"</button>"
"<span id=\"%h\">"
"%s"
"</span>"
"</span>";
if( bOutputCGI ){
cgi_printf(
zBtnFmt/*works-like:"%h%h%d%h%s"*/,
zTargetId,zTargetId,cchLength,zTargetId,zText);
}else{
zResult = mprintf(
zBtnFmt/*works-like:"%h%h%d%h%s"*/,
zTargetId,zTargetId,cchLength,zTargetId,zText);
}
}else{
const char *zBtnFmt =
"<span class=\"nobr\">"
"<span id=\"%h\">"
"%s"
"</span>"
"<button "
"class=\"copy-button copy-button-flipped\" "
"id=\"copy-%h\" "
"data-copytarget=\"%h\" "
"data-copylength=\"%d\">"
"<span>"
"</span>"
"</button>"
"</span>";
if( bOutputCGI ){
cgi_printf(
zBtnFmt/*works-like:"%h%s%h%h%d"*/,
zTargetId,zText,zTargetId,zTargetId,cchLength);
}else{
zResult = mprintf(
|
| ︙ | ︙ | |||
1384 1385 1386 1387 1388 1389 1390 |
** Display CGI-variables and other aspects of the run-time
** environment, for debugging and trouble-shooting purposes.
*/
void page_test_env(void){
webpage_error("");
}
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 |
** Display CGI-variables and other aspects of the run-time
** environment, for debugging and trouble-shooting purposes.
*/
void page_test_env(void){
webpage_error("");
}
/*
** Webpages that encounter an error due to missing or incorrect
** query parameters can jump to this routine to render an error
** message screen.
**
** For administators, or if the test_env_enable setting is true, then
** details of the request environment are displayed. Otherwise, just
|
| ︙ | ︙ | |||
1481 1482 1483 1484 1485 1486 1487 |
#endif
@ g.zBaseURL = %h(g.zBaseURL)<br>
@ g.zHttpsURL = %h(g.zHttpsURL)<br>
@ g.zTop = %h(g.zTop)<br>
@ g.zPath = %h(g.zPath)<br>
@ g.userUid = %d(g.userUid)<br>
@ g.zLogin = %h(g.zLogin)<br>
| | | 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 |
#endif
@ g.zBaseURL = %h(g.zBaseURL)<br>
@ g.zHttpsURL = %h(g.zHttpsURL)<br>
@ g.zTop = %h(g.zTop)<br>
@ g.zPath = %h(g.zPath)<br>
@ g.userUid = %d(g.userUid)<br>
@ g.zLogin = %h(g.zLogin)<br>
@ g.isRobot = %d(g.isRobot)<br>
@ g.jsHref = %d(g.jsHref)<br>
if( g.zLocalRoot ){
@ g.zLocalRoot = %h(g.zLocalRoot)<br>
}else{
@ g.zLocalRoot = <i>none</i><br>
}
if( g.nRequest ){
|
| ︙ | ︙ |
Changes to src/tag.c.
| ︙ | ︙ | |||
216 217 218 219 220 221 222 |
rid
);
}
}
if( zCol ){
db_multi_exec("UPDATE event SET \"%w\"=%Q WHERE objid=%d",
zCol, zValue, rid);
| | | | 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 |
rid
);
}
}
if( zCol ){
db_multi_exec("UPDATE event SET \"%w\"=%Q WHERE objid=%d",
zCol, zValue, rid);
if( tagid==TAG_COMMENT && zValue!=0 ){
char *zCopy = fossil_strdup(zValue);
backlink_extract(zCopy, MT_NONE, rid, BKLNK_COMMENT, mtime, 1);
free(zCopy);
}
}
if( tagid==TAG_DATE ){
db_multi_exec("UPDATE event "
" SET mtime=julianday(%Q),"
|
| ︙ | ︙ |
Changes to src/tar.c.
| ︙ | ︙ | |||
758 759 760 761 762 763 764 765 766 767 768 769 770 771 |
Glob *pInclude = 0; /* The compiled in= glob pattern */
Glob *pExclude = 0; /* The compiled ex= glob pattern */
Blob tarball; /* Tarball accumulated here */
const char *z;
login_check_credentials();
if( !g.perm.Zip ){ login_needed(g.anon.Zip); return; }
fossil_nice_default();
zName = fossil_strdup(PD("name",""));
z = P("r");
if( z==0 ) z = P("uuid");
if( z==0 ) z = tar_uuid_from_name(&zName);
if( z==0 ) z = "trunk";
g.zOpenRevision = zRid = fossil_strdup(z);
| > | 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 |
Glob *pInclude = 0; /* The compiled in= glob pattern */
Glob *pExclude = 0; /* The compiled ex= glob pattern */
Blob tarball; /* Tarball accumulated here */
const char *z;
login_check_credentials();
if( !g.perm.Zip ){ login_needed(g.anon.Zip); return; }
if( robot_restrict("zip") ) return;
fossil_nice_default();
zName = fossil_strdup(PD("name",""));
z = P("r");
if( z==0 ) z = P("uuid");
if( z==0 ) z = tar_uuid_from_name(&zName);
if( z==0 ) z = "trunk";
g.zOpenRevision = zRid = fossil_strdup(z);
|
| ︙ | ︙ |
Changes to src/th_lang.c.
| ︙ | ︙ | |||
954 955 956 957 958 959 960 |
**
** string match PATTERN STRING
**
*/
static int string_match_command(
Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
){
| | | 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 |
**
** string match PATTERN STRING
**
*/
static int string_match_command(
Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
){
extern char *fossil_strndup(const char*,ssize_t);
extern void fossil_free(void*);
char *zPat, *zStr;
int rc;
if( argc!=4 ){
return Th_WrongNumArgs(interp, "string match pattern string");
}
zPat = fossil_strndup(argv[2],TH1_LEN(argl[2]));
|
| ︙ | ︙ |
Changes to src/th_main.c.
| ︙ | ︙ | |||
1430 1431 1432 1433 1434 1435 1436 |
int argc,
const char **argv,
int *argl
){
if( argc!=3 ){
return Th_WrongNumArgs(interp, "setParameter NAME VALUE");
}
| | | 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 |
int argc,
const char **argv,
int *argl
){
if( argc!=3 ){
return Th_WrongNumArgs(interp, "setParameter NAME VALUE");
}
cgi_replace_parameter(fossil_strdup(argv[1]), fossil_strdup(argv[2]));
return TH_OK;
}
/*
** TH1 command: reinitialize ?FLAGS?
**
** Reinitializes the TH1 interpreter using the specified flags.
|
| ︙ | ︙ | |||
2963 2964 2965 2966 2967 2968 2969 |
Th_ReturnCodeName(rc, 0), TH1_LEN(nTrRes), zTrRes);
}
if( rc!=TH_OK ) break;
z += i;
if( z[0] ){ z += 6; }
i = 0;
}else{
| | | 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 |
Th_ReturnCodeName(rc, 0), TH1_LEN(nTrRes), zTrRes);
}
if( rc!=TH_OK ) break;
z += i;
if( z[0] ){ z += 6; }
i = 0;
}else{
i += strcspn(&z[i+1], "<$") + 1;
}
}
if( rc==TH_ERROR ){
zResult = (char*)Th_GetResult(g.interp, &n);
sendError(pOut,zResult, n, 1);
}else{
sendText(pOut,z, i, 0);
|
| ︙ | ︙ |
Changes to src/timeline.c.
| ︙ | ︙ | |||
1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 |
}
if( (!g.perm.Read && !g.perm.RdTkt && !g.perm.RdWiki && !g.perm.RdForum)
|| (bisectLocal && !g.perm.Setup)
){
login_needed(g.anon.Read && g.anon.RdTkt && g.anon.RdWiki);
return;
}
if( !bisectLocal ){
etag_check(ETAG_QUERY|ETAG_COOKIE|ETAG_DATA|ETAG_CONFIG, 0);
}
cookie_read_parameter("y","y");
zType = P("y");
if( zType==0 ){
zType = g.perm.Read ? "ci" : "all";
| > | 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 |
}
if( (!g.perm.Read && !g.perm.RdTkt && !g.perm.RdWiki && !g.perm.RdForum)
|| (bisectLocal && !g.perm.Setup)
){
login_needed(g.anon.Read && g.anon.RdTkt && g.anon.RdWiki);
return;
}
if( zBefore && robot_restrict("timelineX") ) return;
if( !bisectLocal ){
etag_check(ETAG_QUERY|ETAG_COOKIE|ETAG_DATA|ETAG_CONFIG, 0);
}
cookie_read_parameter("y","y");
zType = P("y");
if( zType==0 ){
zType = g.perm.Read ? "ci" : "all";
|
| ︙ | ︙ | |||
1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 |
tmFlags &= ~(TIMELINE_DELTA|TIMELINE_BRCOLOR|TIMELINE_UCOLOR);
tmFlags |= TIMELINE_NOCOLOR;
}
if( showSql ) db_append_dml_to_blob(&allSql);
if( zUses!=0 ){
int ufid = db_int(0, "SELECT rid FROM blob WHERE uuid GLOB '%q*'", zUses);
if( ufid ){
zUses = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", ufid);
db_multi_exec("CREATE TEMP TABLE usesfile(rid INTEGER PRIMARY KEY)");
compute_uses_file("usesfile", ufid, 0);
zType = "ci";
disableY = 1;
if( !haveParameterN ) nEntry = 0;
}else{
| > | 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 |
tmFlags &= ~(TIMELINE_DELTA|TIMELINE_BRCOLOR|TIMELINE_UCOLOR);
tmFlags |= TIMELINE_NOCOLOR;
}
if( showSql ) db_append_dml_to_blob(&allSql);
if( zUses!=0 ){
int ufid = db_int(0, "SELECT rid FROM blob WHERE uuid GLOB '%q*'", zUses);
if( ufid ){
if( robot_restrict("timelineX") ) return;
zUses = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", ufid);
db_multi_exec("CREATE TEMP TABLE usesfile(rid INTEGER PRIMARY KEY)");
compute_uses_file("usesfile", ufid, 0);
zType = "ci";
disableY = 1;
if( !haveParameterN ) nEntry = 0;
}else{
|
| ︙ | ︙ | |||
3037 3038 3039 3040 3041 3042 3043 |
static const char *const azMatchStyles[] = {
"exact", "Exact", "glob", "Glob", "like", "Like", "regexp", "Regexp",
"brlist", "List"
};
double rDate;
zDate = db_text(0, "SELECT min(timestamp) FROM timeline /*scan*/");
if( (!zDate || !zDate[0]) && ( zAfter || zBefore ) ){
| | | | 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 |
static const char *const azMatchStyles[] = {
"exact", "Exact", "glob", "Glob", "like", "Like", "regexp", "Regexp",
"brlist", "List"
};
double rDate;
zDate = db_text(0, "SELECT min(timestamp) FROM timeline /*scan*/");
if( (!zDate || !zDate[0]) && ( zAfter || zBefore ) ){
zDate = fossil_strdup((zAfter ? zAfter : zBefore));
}
if( zDate ){
rDate = symbolic_name_to_mtime(zDate, 0, 0);
if( db_int(0,
"SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob"
" WHERE blob.rid=event.objid AND mtime<=%.17g%s)",
rDate-ONE_SECOND, blob_sql_text(&cond))
){
zOlderButton = fossil_strdup(url_render(&url, "b", zDate, "a", 0));
zOlderButtonLabel = "More";
}
free(zDate);
}
zDate = db_text(0, "SELECT max(timestamp) FROM timeline /*scan*/");
if( (!zDate || !zDate[0]) && ( zAfter || zBefore ) ){
zDate = fossil_strdup((zBefore ? zBefore : zAfter));
}
if( zDate ){
rDate = symbolic_name_to_mtime(zDate, 0, 0);
if( db_int(0,
"SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob"
" WHERE blob.rid=event.objid AND mtime>=%.17g%s)",
rDate+ONE_SECOND, blob_sql_text(&cond))
|
| ︙ | ︙ |
Changes to src/tkt.c.
| ︙ | ︙ | |||
100 101 102 103 104 105 106 |
continue;
}
if( strchr(zFieldName,' ')!=0 ) continue;
if( nField%10==0 ){
aField = fossil_realloc(aField, sizeof(aField[0])*(nField+10) );
}
aField[nField].zBsln = 0;
| | | 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
continue;
}
if( strchr(zFieldName,' ')!=0 ) continue;
if( nField%10==0 ){
aField = fossil_realloc(aField, sizeof(aField[0])*(nField+10) );
}
aField[nField].zBsln = 0;
aField[nField].zName = fossil_strdup(zFieldName);
aField[nField].mUsed = USEDBY_TICKET;
nField++;
}
db_finalize(&q);
if( nBaselines ){
db_prepare(&q, "SELECT 1 FROM pragma_table_info('ticket') "
"WHERE type = 'INTEGER' AND name = :n");
|
| ︙ | ︙ | |||
143 144 145 146 147 148 149 |
aField[i].mUsed |= USEDBY_TICKETCHNG;
continue;
}
if( nField%10==0 ){
aField = fossil_realloc(aField, sizeof(aField[0])*(nField+10) );
}
aField[nField].zBsln = 0;
| | | 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
aField[i].mUsed |= USEDBY_TICKETCHNG;
continue;
}
if( nField%10==0 ){
aField = fossil_realloc(aField, sizeof(aField[0])*(nField+10) );
}
aField[nField].zBsln = 0;
aField[nField].zName = fossil_strdup(zFieldName);
aField[nField].mUsed = USEDBY_TICKETCHNG;
nField++;
}
db_finalize(&q);
qsort(aField, nField, sizeof(aField[0]), nameCmpr);
noRegularMimetype = 1;
for(i=0; i<nField; i++){
|
| ︙ | ︙ | |||
208 209 210 211 212 213 214 |
char *zRevealed = 0;
if( zVal==0 ){
zVal = "";
}else if( strncmp(zName, "private_", 8)==0 ){
zVal = zRevealed = db_reveal(zVal);
}
if( (j = fieldId(zName))>=0 ){
| | | 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 |
char *zRevealed = 0;
if( zVal==0 ){
zVal = "";
}else if( strncmp(zName, "private_", 8)==0 ){
zVal = zRevealed = db_reveal(zVal);
}
if( (j = fieldId(zName))>=0 ){
aField[j].zValue = fossil_strdup(zVal);
}else if( memcmp(zName, "tkt_", 4)==0 && Th_Fetch(zName, &size)==0 ){
/* TICKET table columns that begin with "tkt_" are always safe */
Th_Store(zName, zVal);
}
free(zRevealed);
}
Th_Store("tkt_mage", human_readable_age(db_column_double(&q, 2)));
|
| ︙ | ︙ | |||
1785 1786 1787 1788 1789 1790 1791 |
zFName = g.argv[i++];
if( i==g.argc ){
fossil_fatal("missing value for '%s'!",zFName);
}
zFValue = g.argv[i++];
if( tktEncoding == tktFossilize ){
| | | 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 |
zFName = g.argv[i++];
if( i==g.argc ){
fossil_fatal("missing value for '%s'!",zFName);
}
zFValue = g.argv[i++];
if( tktEncoding == tktFossilize ){
zFValue=fossil_strdup(zFValue);
defossilize(zFValue);
}
append = (zFName[0] == '+');
if( append ){
zFName++;
}
j = fieldId(zFName);
|
| ︙ | ︙ |
Changes to src/tktsetup.c.
| ︙ | ︙ | |||
601 602 603 604 605 606 607 |
@ } else {
@ wiki $comment
@ }
@ }
@ }
@ set seenRow 0
@ set alwaysPlaintext [info exists plaintext]
| | | 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 |
@ } else {
@ wiki $comment
@ }
@ }
@ }
@ set seenRow 0
@ set alwaysPlaintext [info exists plaintext]
@ query {SELECT datetime(tkt_mtime,toLocal()) AS xdate, login AS xlogin,
@ mimetype as xmimetype, icomment AS xcomment,
@ username AS xusername
@ FROM ticketchng
@ WHERE tkt_id=$tkt_id AND length(icomment)>0} {
@ if {$seenRow} {
@ html "<hr>\n"
@ } else {
|
| ︙ | ︙ | |||
787 788 789 790 791 792 793 | @ </td> @ <td>Abandon this edit</td> @ </tr> @ @ <th1> @ set seenRow 0 @ set alwaysPlaintext [info exists plaintext] | | | 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 |
@ </td>
@ <td>Abandon this edit</td>
@ </tr>
@
@ <th1>
@ set seenRow 0
@ set alwaysPlaintext [info exists plaintext]
@ query {SELECT datetime(tkt_mtime,toLocal()) AS xdate, login AS xlogin,
@ mimetype as xmimetype, icomment AS xcomment,
@ username AS xusername
@ FROM ticketchng
@ WHERE tkt_id=$tkt_id AND length(icomment)>0} {
@ if {$seenRow} {
@ html "<hr>\n"
@ } else {
|
| ︙ | ︙ | |||
924 925 926 927 928 929 930 |
@ CASE WHEN status IN ('Open','Verified') THEN '#f2dcdc'
@ WHEN status='Review' THEN '#e8e8e8'
@ WHEN status='Fixed' THEN '#cfe8bd'
@ WHEN status='Tested' THEN '#bde5d6'
@ WHEN status='Deferred' THEN '#cacae5'
@ ELSE '#c8c8c8' END AS 'bgcolor',
@ substr(tkt_uuid,1,10) AS '#',
| | | | 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 |
@ CASE WHEN status IN ('Open','Verified') THEN '#f2dcdc'
@ WHEN status='Review' THEN '#e8e8e8'
@ WHEN status='Fixed' THEN '#cfe8bd'
@ WHEN status='Tested' THEN '#bde5d6'
@ WHEN status='Deferred' THEN '#cacae5'
@ ELSE '#c8c8c8' END AS 'bgcolor',
@ substr(tkt_uuid,1,10) AS '#',
@ datetime(tkt_ctime,toLocal()) AS 'created',
@ datetime(tkt_mtime,toLocal()) AS 'modified',
@ type,
@ status,
@ subsystem,
@ title,
@ comment AS '_comments'
@ FROM ticket
;
|
| ︙ | ︙ |
Changes to src/unversioned.c.
| ︙ | ︙ | |||
145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
db_bind_int(&ins, ":encoding", 1);
db_bind_blob(&ins, ":content", &compressed);
}else{
db_bind_int(&ins, ":encoding", 0);
db_bind_blob(&ins, ":content", pContent);
}
db_step(&ins);
blob_reset(&compressed);
blob_reset(&hash);
db_finalize(&ins);
db_unset("uv-hash", 0);
}
| > > | 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
db_bind_int(&ins, ":encoding", 1);
db_bind_blob(&ins, ":content", &compressed);
}else{
db_bind_int(&ins, ":encoding", 0);
db_bind_blob(&ins, ":content", pContent);
}
db_step(&ins);
admin_log("Wrote unversioned file \"%w\" with hash %!S",
zUVFile, blob_str(&hash));
blob_reset(&compressed);
blob_reset(&hash);
db_finalize(&ins);
db_unset("uv-hash", 0);
}
|
| ︙ | ︙ | |||
316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 |
}
if( strncmp(zCmd, "add", nCmd)==0 ){
const char *zError = 0;
const char *zIn;
const char *zAs;
Blob file;
int i;
zAs = find_option("as",0,1);
verify_all_options();
if( zAs && g.argc!=4 ) usage("add DISKFILE --as UVFILE");
db_begin_transaction();
content_rcvid_init("#!fossil unversioned add");
for(i=3; i<g.argc; i++){
zIn = zAs ? zAs : g.argv[i];
if( zIn[0]==0 ){
zError = "be empty string";
}else if( zIn[0]=='/' ){
zError = "be absolute";
}else if ( !file_is_simple_pathname(zIn,1) ){
zError = "contain complex paths";
}else if( contains_whitespace(zIn) ){
zError = "contain whitespace";
}
if( zError ){
fossil_fatal("unversioned filenames may not %s: %Q", zError, zIn);
}
blob_init(&file,0,0);
blob_read_from_file(&file, g.argv[i], ExtFILE);
unversioned_write(zIn, &file, mtime);
blob_reset(&file);
}
db_end_transaction(0);
| > > > > > > > > > | 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 |
}
if( strncmp(zCmd, "add", nCmd)==0 ){
const char *zError = 0;
const char *zIn;
const char *zAs;
Blob file;
int i;
i64 mxSize = sqlite3_limit(g.db,SQLITE_LIMIT_LENGTH,-1) - 850;
/* Extra space for other fields ------^^^ */
/* of the UNVESIONED table row. */
zAs = find_option("as",0,1);
verify_all_options();
if( zAs && g.argc!=4 ) usage("add DISKFILE --as UVFILE");
db_begin_transaction();
content_rcvid_init("#!fossil unversioned add");
for(i=3; i<g.argc; i++){
zIn = zAs ? zAs : g.argv[i];
if( zIn[0]==0 ){
zError = "be empty string";
}else if( zIn[0]=='/' ){
zError = "be absolute";
}else if ( !file_is_simple_pathname(zIn,1) ){
zError = "contain complex paths";
}else if( contains_whitespace(zIn) ){
zError = "contain whitespace";
}else if( strlen(zIn)>500 ){
zError = "be more than 500 bytes long";
}
if( zError ){
fossil_fatal("unversioned filenames may not %s: %Q", zError, zIn);
}
if( file_size(g.argv[i], ExtFILE)>mxSize ){
fossil_fatal("file \"%s\" is too big; max size: %,lld bytes",
g.argv[i], mxSize);
}
blob_init(&file,0,0);
blob_read_from_file(&file, g.argv[i], ExtFILE);
unversioned_write(zIn, &file, mtime);
blob_reset(&file);
}
db_end_transaction(0);
|
| ︙ | ︙ |
Changes to src/url.c.
| ︙ | ︙ | |||
225 226 227 228 229 230 231 |
if( c!=0 && c!='/' ) fossil_fatal("url missing '/' after port number");
pUrlData->hostname = mprintf("%s:%d", pUrlData->name, pUrlData->port);
}else{
pUrlData->port = pUrlData->dfltPort;
pUrlData->hostname = pUrlData->name;
}
dehttpize(pUrlData->name);
| | | | 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 |
if( c!=0 && c!='/' ) fossil_fatal("url missing '/' after port number");
pUrlData->hostname = mprintf("%s:%d", pUrlData->name, pUrlData->port);
}else{
pUrlData->port = pUrlData->dfltPort;
pUrlData->hostname = pUrlData->name;
}
dehttpize(pUrlData->name);
pUrlData->path = fossil_strdup(&zUrl[i]);
for(i=0; pUrlData->path[i] && pUrlData->path[i]!='?'; i++){}
if( pUrlData->path[i] ){
pUrlData->path[i] = 0;
i++;
}
zExe = fossil_strdup("");
while( pUrlData->path[i]!=0 ){
char *zName, *zValue;
zName = &pUrlData->path[i];
zValue = zName;
while( pUrlData->path[i] && pUrlData->path[i]!='=' ){ i++; }
if( pUrlData->path[i]=='=' ){
pUrlData->path[i] = 0;
|
| ︙ | ︙ | |||
273 274 275 276 277 278 279 |
"%s://%s%T:%d%T%z",
pUrlData->protocol, zLogin, pUrlData->name, pUrlData->port,
pUrlData->path, zExe
);
}
if( pUrlData->isSsh && pUrlData->path[1] ){
char *zOld = pUrlData->path;
| | | | | 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 |
"%s://%s%T:%d%T%z",
pUrlData->protocol, zLogin, pUrlData->name, pUrlData->port,
pUrlData->path, zExe
);
}
if( pUrlData->isSsh && pUrlData->path[1] ){
char *zOld = pUrlData->path;
pUrlData->path = fossil_strdup(zOld+1);
fossil_free(zOld);
}
free(zLogin);
}else if( strncmp(zUrl, "file:", 5)==0 ){
pUrlData->isFile = 1;
if( zUrl[5]=='/' && zUrl[6]=='/' ){
i = 7;
}else{
i = 5;
}
zFile = fossil_strdup(&zUrl[i]);
}else if( file_isfile(zUrl, ExtFILE) ){
pUrlData->isFile = 1;
zFile = fossil_strdup(zUrl);
}else if( file_isdir(zUrl, ExtFILE)==1 ){
zFile = mprintf("%s/FOSSIL", zUrl);
if( file_isfile(zFile, ExtFILE) ){
pUrlData->isFile = 1;
}else{
free(zFile);
zFile = 0;
|
| ︙ | ︙ |
Changes to src/user.c.
| ︙ | ︙ | |||
107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
assert( zPwd==zPwdBuffer );
return zPwd;
}
void freepass(){
if( !zPwdBuffer ) return;
assert( nPwdBuffer>0 );
fossil_secure_free_page(zPwdBuffer, nPwdBuffer);
}
#endif
/*
** Scramble substitution matrix:
*/
static char aSubst[256];
| > > | 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
assert( zPwd==zPwdBuffer );
return zPwd;
}
void freepass(){
if( !zPwdBuffer ) return;
assert( nPwdBuffer>0 );
fossil_secure_free_page(zPwdBuffer, nPwdBuffer);
zPwdBuffer = 0;
nPwdBuffer = 0;
}
#endif
/*
** Scramble substitution matrix:
*/
static char aSubst[256];
|
| ︙ | ︙ | |||
284 285 286 287 288 289 290 |
*/
char *prompt_for_user_password(const char *zUser){
char *zPrompt = mprintf("\rpassword for %s: ", zUser);
char *zPw;
Blob x;
fossil_force_newline();
prompt_for_password(zPrompt, &x, 0);
| | | < | 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 |
*/
char *prompt_for_user_password(const char *zUser){
char *zPrompt = mprintf("\rpassword for %s: ", zUser);
char *zPw;
Blob x;
fossil_force_newline();
prompt_for_password(zPrompt, &x, 0);
fossil_free(zPrompt);
zPw = blob_str(&x)/*transfer ownership*/;
return zPw;
}
/*
** Prompt the user to enter a single line of text.
*/
void prompt_user(const char *zPrompt, Blob *pIn){
|
| ︙ | ︙ | |||
463 464 465 466 467 468 469 |
fossil_print("password unchanged\n");
}else{
char *zSecret = sha1_shared_secret(blob_str(&pw), g.argv[3], 0);
db_unprotect(PROTECT_USER);
db_multi_exec("UPDATE user SET pw=%Q, mtime=now() WHERE uid=%d",
zSecret, uid);
db_protect_pop();
| | | 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 |
fossil_print("password unchanged\n");
}else{
char *zSecret = sha1_shared_secret(blob_str(&pw), g.argv[3], 0);
db_unprotect(PROTECT_USER);
db_multi_exec("UPDATE user SET pw=%Q, mtime=now() WHERE uid=%d",
zSecret, uid);
db_protect_pop();
fossil_free(zSecret);
}
}else if( n>=2 && strncmp(g.argv[2],"capabilities",2)==0 ){
int uid;
if( g.argc!=4 && g.argc!=5 ){
usage("capabilities USERNAME ?PERMISSIONS?");
}
uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", g.argv[3]);
|
| ︙ | ︙ | |||
519 520 521 522 523 524 525 |
if( zLogin==0 ){
return 0;
}
uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", zLogin);
if( uid ){
g.userUid = uid;
| | | 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 |
if( zLogin==0 ){
return 0;
}
uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", zLogin);
if( uid ){
g.userUid = uid;
g.zLogin = fossil_strdup(zLogin);
return 1;
}
return 0;
}
/*
** Figure out what user is at the controls.
|
| ︙ | ︙ |
Changes to src/util.c.
| ︙ | ︙ | |||
897 898 899 900 901 902 903 904 905 906 907 908 909 910 |
fossil_print("%s (%d bits of entropy)\n", zPassword,
(int)(log(et)/log(2.0)));
}else{
fossil_print("%s\n", zPassword);
}
fossil_free(zPassword);
}
/*
** Return the number of decimal digits in a nonnegative integer. This is useful
** when formatting text.
*/
int fossil_num_digits(int n){
return n< 10 ? 1 : n< 100 ? 2 : n< 1000 ? 3
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 |
fossil_print("%s (%d bits of entropy)\n", zPassword,
(int)(log(et)/log(2.0)));
}else{
fossil_print("%s\n", zPassword);
}
fossil_free(zPassword);
}
/*
** Generate a version 4 ("random"), variant 1 UUID (RFC 9562, Section 5.4).
**
** Format: xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
** where M=4 and N=8, 9, a, or b (this leaves 122 random bits)
*/
char* fossil_generate_uuid() {
static const char zDigits[] = "0123456789abcdef";
unsigned char aBlob[16];
unsigned char zStr[37];
unsigned char *p = zStr;
int i, k;
sqlite3_randomness(16, aBlob);
aBlob[6] = (aBlob[6]&0x0f) + 0x40; /* Version byte: 0100 xxxx */
aBlob[8] = (aBlob[8]&0x3f) + 0x80; /* Variant byte: 1000 xxxx */
for(i=0, k=0x550; i<16; i++, k=k>>1){
if( k&1 ){
*p++ = '-'; /* Add a dash after byte 4, 6, 8, and 12 */
}
*p++ = zDigits[aBlob[i]>>4];
*p++ = zDigits[aBlob[i]&0xf];
}
*p = 0;
return fossil_strdup((char*)zStr);
}
/*
** COMMAND: test-generate-uuid
**
** Usage: %fossil test-generate-uuid
**
** Generate a version 4 ("random"), variant 1 UUID (RFC 9562, Section 5.4):
**
** xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx - where M=4 and N=8, 9, a, or b
*/
void test_generate_uuid(void){
fossil_print("%s\n", fossil_generate_uuid());
}
/*
** Return the number of decimal digits in a nonnegative integer. This is useful
** when formatting text.
*/
int fossil_num_digits(int n){
return n< 10 ? 1 : n< 100 ? 2 : n< 1000 ? 3
|
| ︙ | ︙ |
Changes to src/vfile.c.
| ︙ | ︙ | |||
641 642 643 644 645 646 647 |
char *zPath;
char *zUtf8;
if( pEntry->d_name[0]=='.' ){
if( (scanFlags & SCAN_ALL)==0 ) continue;
if( pEntry->d_name[1]==0 ) continue;
if( pEntry->d_name[1]=='.' && pEntry->d_name[2]==0 ) continue;
}
| | | | 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 |
char *zPath;
char *zUtf8;
if( pEntry->d_name[0]=='.' ){
if( (scanFlags & SCAN_ALL)==0 ) continue;
if( pEntry->d_name[1]==0 ) continue;
if( pEntry->d_name[1]=='.' && pEntry->d_name[2]==0 ) continue;
}
zOrigPath = fossil_strdup(blob_str(pPath));
zUtf8 = fossil_path_to_utf8(pEntry->d_name);
blob_appendf(pPath, "/%s", zUtf8);
zPath = blob_str(pPath);
if( glob_match(pIgnore1, &zPath[nPrefix+1]) ||
glob_match(pIgnore2, &zPath[nPrefix+1]) ){
/* do nothing */
#ifdef _DIRENT_HAVE_D_TYPE
}else if( (pEntry->d_type==DT_UNKNOWN || pEntry->d_type==DT_LNK)
? (file_isdir(zPath, eFType)==1) : (pEntry->d_type==DT_DIR) ){
#else
}else if( file_isdir(zPath, eFType)==1 ){
#endif
if( (scanFlags & SCAN_NESTED) || !vfile_top_of_checkout(zPath) ){
char *zSavePath = fossil_strdup(zPath);
int count = vfile_dir_scan(pPath, nPrefix, scanFlags, pIgnore1,
pIgnore2, eFType);
db_bind_text(&ins, ":file", &zSavePath[nPrefix+1]);
db_bind_int(&ins, ":count", count);
db_step(&ins);
db_reset(&ins);
fossil_free(zSavePath);
|
| ︙ | ︙ |
Changes to src/wiki.c.
| ︙ | ︙ | |||
572 573 574 575 576 577 578 |
int isSandbox;
unsigned submenuFlags = W_HELP;
Blob wiki;
Manifest *pWiki = 0;
const char *zPageName;
const char *zMimetype = 0;
int isPopup = P("popup")!=0;
| | | 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 |
int isSandbox;
unsigned submenuFlags = W_HELP;
Blob wiki;
Manifest *pWiki = 0;
const char *zPageName;
const char *zMimetype = 0;
int isPopup = P("popup")!=0;
char *zBody = fossil_strdup("<i>Empty Page</i>");
int noSubmenu = P("nsm")!=0 || g.isHome;
login_check_credentials();
if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; }
zPageName = P("name");
(void)P("s")/*for cgi_check_for_malice(). "s" == search stringy*/;
cgi_check_for_malice();
|
| ︙ | ︙ |
Changes to src/winhttp.c.
| ︙ | ︙ | |||
1152 1153 1154 1155 1156 1157 1158 |
if( zPort && (atoi(zPort)<=0) ){
winhttp_fatal("create", zSvcName,
"port number must be in the range 1 - 65535.");
}
if( !zRepository ){
db_must_be_within_tree();
}else if( file_isdir(zRepository, ExtFILE)==1 ){
| | | 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 |
if( zPort && (atoi(zPort)<=0) ){
winhttp_fatal("create", zSvcName,
"port number must be in the range 1 - 65535.");
}
if( !zRepository ){
db_must_be_within_tree();
}else if( file_isdir(zRepository, ExtFILE)==1 ){
g.zRepositoryName = fossil_strdup(zRepository);
file_simplify_name(g.zRepositoryName, -1, 0);
}else{
db_open_repository(zRepository);
}
db_close(0);
/* Build the fully-qualified path to the service binary file. */
blob_zero(&binPath);
|
| ︙ | ︙ |
Changes to src/xfer.c.
| ︙ | ︙ | |||
825 826 827 828 829 830 831 |
static int check_login(Blob *pLogin, Blob *pNonce, Blob *pSig){
Stmt q;
int rc = -1;
char *zLogin = blob_terminate(pLogin);
defossilize(zLogin);
if( fossil_strcmp(zLogin, "nobody")==0
| | | 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 |
static int check_login(Blob *pLogin, Blob *pNonce, Blob *pSig){
Stmt q;
int rc = -1;
char *zLogin = blob_terminate(pLogin);
defossilize(zLogin);
if( fossil_strcmp(zLogin, "nobody")==0
|| fossil_strcmp(zLogin, "anonymous")==0
){
return 0; /* Anybody is allowed to sync as "nobody" or "anonymous" */
}
if( fossil_strcmp(P("REMOTE_USER"), zLogin)==0
&& db_get_boolean("remote_user_ok",0) ){
return 0; /* Accept Basic Authorization */
}
|
| ︙ | ︙ | |||
864 865 866 867 868 869 870 |
** again with the SHA1 password.
*/
const char *zPw = db_column_text(&q, 0);
char *zSecret = sha1_shared_secret(zPw, blob_str(pLogin), 0);
blob_zero(&combined);
blob_copy(&combined, pNonce);
blob_append(&combined, zSecret, -1);
| | | 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 |
** again with the SHA1 password.
*/
const char *zPw = db_column_text(&q, 0);
char *zSecret = sha1_shared_secret(zPw, blob_str(pLogin), 0);
blob_zero(&combined);
blob_copy(&combined, pNonce);
blob_append(&combined, zSecret, -1);
fossil_free(zSecret);
sha1sum_blob(&combined, &hash);
rc = blob_constant_time_cmp(&hash, pSig);
blob_reset(&hash);
blob_reset(&combined);
}
if( rc==0 ){
const char *zCap;
|
| ︙ | ︙ | |||
1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 | } /* ** If this variable is set, disable login checks. Used for debugging ** only. */ static int disableLogin = 0; /* ** The CGI/HTTP preprocessor always redirects requests with a content-type ** of application/x-fossil or application/x-fossil-debug to this page, ** regardless of what path was specified in the HTTP header. This allows ** clone clients to specify a URL that omits default pathnames, such ** as "http://fossil-scm.org/" instead of "http://fossil-scm.org/index.cgi". | > > > > > > > > > > > > > > > | 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 |
}
/*
** If this variable is set, disable login checks. Used for debugging
** only.
*/
static int disableLogin = 0;
/*
** Must be passed the version info from pragmas
** client-version/server-version cards. If the version info is "new
** enough" then the loginCardMode is ORd into the X-Fossil-Xfer-Login
** card flag, else this is a no-op.
*/
static void xfer_xflc_check(int iRemoteVersion, int iDate, int iTime,
int fLoginCardMode){
if( iRemoteVersion>=22700
&& (iDate > 20250727
|| (iDate == 20250727 && iTime >= 110500)) ){
g.syncInfo.fLoginCardMode |= fLoginCardMode;
}
}
/*
** The CGI/HTTP preprocessor always redirects requests with a content-type
** of application/x-fossil or application/x-fossil-debug to this page,
** regardless of what path was specified in the HTTP header. This allows
** clone clients to specify a URL that omits default pathnames, such
** as "http://fossil-scm.org/" instead of "http://fossil-scm.org/index.cgi".
|
| ︙ | ︙ | |||
1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 |
const char *zScript = 0;
char *zUuidList = 0;
int nUuidList = 0;
char **pzUuidList = 0;
int *pnUuidList = 0;
int uvCatalogSent = 0;
int bSendLinks = 0;
if( fossil_strcmp(PD("REQUEST_METHOD","POST"),"POST") ){
fossil_redirect_home();
}
g.zLogin = "anonymous";
login_set_anon_nobody_capabilities();
login_check_credentials();
| > | 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 |
const char *zScript = 0;
char *zUuidList = 0;
int nUuidList = 0;
char **pzUuidList = 0;
int *pnUuidList = 0;
int uvCatalogSent = 0;
int bSendLinks = 0;
int nLogin = 0;
if( fossil_strcmp(PD("REQUEST_METHOD","POST"),"POST") ){
fossil_redirect_home();
}
g.zLogin = "anonymous";
login_set_anon_nobody_capabilities();
login_check_credentials();
|
| ︙ | ︙ | |||
1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 |
@ error common\sscript\sfailed:\s%F(g.zErrMsg)
nErr++;
}
zScript = xfer_push_code();
if( zScript ){ /* NOTE: Are TH1 transfer hooks enabled? */
pzUuidList = &zUuidList;
pnUuidList = &nUuidList;
}
while( blob_line(xfer.pIn, &xfer.line) ){
if( blob_buffer(&xfer.line)[0]=='#' ) continue;
if( blob_size(&xfer.line)==0 ) continue;
xfer.nToken = blob_tokenize(&xfer.line, xfer.aToken, count(xfer.aToken));
/* file HASH SIZE \n CONTENT
| > > > > > > > > > > > > > > | 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 |
@ error common\sscript\sfailed:\s%F(g.zErrMsg)
nErr++;
}
zScript = xfer_push_code();
if( zScript ){ /* NOTE: Are TH1 transfer hooks enabled? */
pzUuidList = &zUuidList;
pnUuidList = &nUuidList;
}
if( g.syncInfo.zLoginCard ){
/* Login card received via HTTP Cookie header */
assert( g.syncInfo.fLoginCardMode && "Set via HTTP cookie" );
blob_zero(&xfer.line);
blob_append(&xfer.line, g.syncInfo.zLoginCard, -1);
xfer.nToken = blob_tokenize(&xfer.line, xfer.aToken,
count(xfer.aToken));
fossil_free( g.syncInfo.zLoginCard );
g.syncInfo.zLoginCard = 0;
if( xfer.nToken==4
&& blob_eq(&xfer.aToken[0], "login") ){
goto handle_login_card;
}
}
while( blob_line(xfer.pIn, &xfer.line) ){
if( blob_buffer(&xfer.line)[0]=='#' ) continue;
if( blob_size(&xfer.line)==0 ) continue;
xfer.nToken = blob_tokenize(&xfer.line, xfer.aToken, count(xfer.aToken));
/* file HASH SIZE \n CONTENT
|
| ︙ | ︙ | |||
1548 1549 1550 1551 1552 1553 1554 |
@ push %s(db_get("server-code", "x")) %s(db_get("project-code", "x"))
}else
/* login USER NONCE SIGNATURE
**
** The client has sent login credentials to the server.
** Validate the login. This has to happen before anything else.
| > > | > > > > > > > > > | 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 |
@ push %s(db_get("server-code", "x")) %s(db_get("project-code", "x"))
}else
/* login USER NONCE SIGNATURE
**
** The client has sent login credentials to the server.
** Validate the login. This has to happen before anything else.
**
** For many years, Fossil would accept multiple login cards with
** cumulative permissions. But that feature was never used. Hence
** it is now prohibited. Any login card after the first generates
** a fatal error.
*/
if( blob_eq(&xfer.aToken[0], "login")
&& xfer.nToken==4
){
handle_login_card:
nLogin++;
if( disableLogin ){
g.perm.Read = g.perm.Write = g.perm.Private = g.perm.Admin = 1;
}else if( nLogin > 1 ){
cgi_reset_content();
@ error multiple\slogin\cards
nErr++;
break;
}else{
if( check_tail_hash(&xfer.aToken[2], xfer.pIn)
|| check_login(&xfer.aToken[1], &xfer.aToken[2], &xfer.aToken[3])
){
cgi_reset_content();
@ error login\sfailed
nErr++;
|
| ︙ | ︙ | |||
1649 1650 1651 1652 1653 1654 1655 |
if( !g.perm.Private ){
server_private_xfer_not_authorized();
}else{
xfer.nextIsPrivate = 1;
}
}else
| < | 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 |
if( !g.perm.Private ){
server_private_xfer_not_authorized();
}else{
xfer.nextIsPrivate = 1;
}
}else
/* pragma NAME VALUE...
**
** The client issues pragmas to try to influence the behavior of the
** server. These are requests only. Unknown pragmas are silently
** ignored.
*/
if( blob_eq(&xfer.aToken[0], "pragma") && xfer.nToken>=2 ){
|
| ︙ | ︙ | |||
1692 1693 1694 1695 1696 1697 1698 |
/* pragma client-version VERSION ?DATE? ?TIME?
**
** The client announces to the server what version of Fossil it
** is running. The DATE and TIME are a pure numeric ISO8601 time
** for the specific check-in of the client.
*/
if( xfer.nToken>=3 && blob_eq(&xfer.aToken[1], "client-version") ){
| > | > > | 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 |
/* pragma client-version VERSION ?DATE? ?TIME?
**
** The client announces to the server what version of Fossil it
** is running. The DATE and TIME are a pure numeric ISO8601 time
** for the specific check-in of the client.
*/
if( xfer.nToken>=3 && blob_eq(&xfer.aToken[1], "client-version") ){
xfer.remoteVersion = g.syncInfo.remoteVersion =
atoi(blob_str(&xfer.aToken[2]));
if( xfer.nToken>=5 ){
xfer.remoteDate = atoi(blob_str(&xfer.aToken[3]));
xfer.remoteTime = atoi(blob_str(&xfer.aToken[4]));
@ pragma server-version %d(RELEASE_VERSION_NUMBER) \
@ %d(MANIFEST_NUMERIC_DATE) %d(MANIFEST_NUMERIC_TIME)
}
xfer_xflc_check( xfer.remoteVersion, xfer.remoteDate,
xfer.remoteTime, 0x04 );
}else
/* pragma uv-hash HASH
**
** The client wants to make sure that unversioned files are all synced.
** If the HASH does not match, send a complete catalog of
** "uvigot" cards.
|
| ︙ | ︙ | |||
2339 2340 2341 2342 2343 2344 2345 |
db_lset("client-id", zClientId);
}
blob_appendf(&send, "pragma ci-lock %s %s\n", zCkinLock, zClientId);
zCkinLock = 0;
}else if( zClientId ){
blob_appendf(&send, "pragma ci-unlock %s\n", zClientId);
}
| < | | 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 |
db_lset("client-id", zClientId);
}
blob_appendf(&send, "pragma ci-lock %s %s\n", zCkinLock, zClientId);
zCkinLock = 0;
}else if( zClientId ){
blob_appendf(&send, "pragma ci-unlock %s\n", zClientId);
}
/* Append randomness to the end of the uplink message. This makes all
** messages unique so that that the login-card nonce will always
** be unique.
*/
zRandomness = db_text(0, "SELECT hex(randomblob(20))");
blob_appendf(&send, "# %s\n", zRandomness);
fossil_free(zRandomness);
if( (syncFlags & SYNC_VERBOSE)!=0
&& (syncFlags & SYNC_XVERBOSE)==0
){
fossil_print("waiting for server...");
}
fflush(stdout);
|
| ︙ | ︙ | |||
2723 2724 2725 2726 2727 2728 2729 |
}
}else
/* message MESSAGE
**
** A message is received from the server. Print it.
** Similar to "error" but does not stop processing.
| < < < | 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 |
}
}else
/* message MESSAGE
**
** A message is received from the server. Print it.
** Similar to "error" but does not stop processing.
*/
if( blob_eq(&xfer.aToken[0],"message") && xfer.nToken==2 ){
char *zMsg = blob_terminate(&xfer.aToken[1]);
defossilize(zMsg);
if( (syncFlags & SYNC_PUSH) && zMsg
&& sqlite3_strglob("pull only *", zMsg)==0 ){
syncFlags &= ~SYNC_PUSH;
|
| ︙ | ︙ | |||
2755 2756 2757 2758 2759 2760 2761 |
/* pragma server-version VERSION ?DATE? ?TIME?
**
** The server announces to the server what version of Fossil it
** is running. The DATE and TIME are a pure numeric ISO8601 time
** for the specific check-in of the client.
*/
if( xfer.nToken>=3 && blob_eq(&xfer.aToken[1], "server-version") ){
| > | > > | 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 |
/* pragma server-version VERSION ?DATE? ?TIME?
**
** The server announces to the server what version of Fossil it
** is running. The DATE and TIME are a pure numeric ISO8601 time
** for the specific check-in of the client.
*/
if( xfer.nToken>=3 && blob_eq(&xfer.aToken[1], "server-version") ){
xfer.remoteVersion = g.syncInfo.remoteVersion =
atoi(blob_str(&xfer.aToken[2]));
if( xfer.nToken>=5 ){
xfer.remoteDate = atoi(blob_str(&xfer.aToken[3]));
xfer.remoteTime = atoi(blob_str(&xfer.aToken[4]));
}
xfer_xflc_check( xfer.remoteVersion, xfer.remoteDate,
xfer.remoteTime, 0x08 );
}
/* pragma uv-pull-only
** pragma uv-push-ok
**
** If the server is unwilling to accept new unversioned content (because
** this client lacks the necessary permissions) then it sends a
|
| ︙ | ︙ | |||
2894 2895 2896 2897 2898 2899 2900 |
fossil_warning(
"server replies with HTML instead of fossil sync protocol:\n%b",
&recv
);
nErr++;
break;
}
| | | 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 |
fossil_warning(
"server replies with HTML instead of fossil sync protocol:\n%b",
&recv
);
nErr++;
break;
}
blob_appendf(&xfer.err, "unknown command: [%b]\n", &xfer.line);
}
if( blob_size(&xfer.err) ){
fossil_force_newline();
fossil_warning("%b", &xfer.err);
nErr++;
break;
|
| ︙ | ︙ | |||
2961 2962 2963 2964 2965 2966 2967 |
if( go ){
manifest_crosslink_end(MC_PERMIT_HOOKS);
}else{
manifest_crosslink_end(MC_PERMIT_HOOKS);
content_enable_dephantomize(1);
}
db_end_transaction(0);
| | | 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 |
if( go ){
manifest_crosslink_end(MC_PERMIT_HOOKS);
}else{
manifest_crosslink_end(MC_PERMIT_HOOKS);
content_enable_dephantomize(1);
}
db_end_transaction(0);
}; /* while(go) */
transport_stats(&nSent, &nRcvd, 1);
if( pnRcvd ) *pnRcvd = nArtifactRcvd;
if( (rSkew*24.0*3600.0) > 10.0 ){
fossil_warning("*** time skew *** server is fast by %s",
db_timespan_name(rSkew));
g.clockSkewSeen = 1;
}else if( rSkew*24.0*3600.0 < -10.0 ){
|
| ︙ | ︙ |
Changes to src/zip.c.
| ︙ | ︙ | |||
494 495 496 497 498 499 500 |
zName[i+1] = 0;
for(j=0; j<nDir; j++){
if( fossil_strcmp(zName, azDir[j])==0 ) break;
}
if( j>=nDir ){
nDir++;
azDir = fossil_realloc(azDir, sizeof(azDir[0])*nDir);
| | | 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 |
zName[i+1] = 0;
for(j=0; j<nDir; j++){
if( fossil_strcmp(zName, azDir[j])==0 ) break;
}
if( j>=nDir ){
nDir++;
azDir = fossil_realloc(azDir, sizeof(azDir[0])*nDir);
azDir[j] = fossil_strdup(zName);
zip_add_file(p, zName, 0, 0);
}
zName[i+1] = c;
}
}
}
|
| ︙ | ︙ | |||
1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 |
Glob *pExclude = 0; /* The compiled ex= glob pattern */
Blob zip; /* ZIP archive accumulated here */
int eType = ARCHIVE_ZIP; /* Type of archive to generate */
char *zType; /* Human-readable archive type */
login_check_credentials();
if( !g.perm.Zip ){ login_needed(g.anon.Zip); return; }
if( fossil_strcmp(g.zPath, "sqlar")==0 ){
eType = ARCHIVE_SQLAR;
zType = "SQL";
/* For some reason, SQL-archives are like catnip for robots. So
** don't allow them to be downloaded by user "nobody" */
if( g.zLogin==0 ){ login_needed(g.anon.Zip); return; }
}else{
| > | 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 |
Glob *pExclude = 0; /* The compiled ex= glob pattern */
Blob zip; /* ZIP archive accumulated here */
int eType = ARCHIVE_ZIP; /* Type of archive to generate */
char *zType; /* Human-readable archive type */
login_check_credentials();
if( !g.perm.Zip ){ login_needed(g.anon.Zip); return; }
if( robot_restrict("zip") ) return;
if( fossil_strcmp(g.zPath, "sqlar")==0 ){
eType = ARCHIVE_SQLAR;
zType = "SQL";
/* For some reason, SQL-archives are like catnip for robots. So
** don't allow them to be downloaded by user "nobody" */
if( g.zLogin==0 ){ login_needed(g.anon.Zip); return; }
}else{
|
| ︙ | ︙ |
Changes to tools/makemake.tcl.
| ︙ | ︙ | |||
150 151 152 153 154 155 156 157 158 159 160 161 162 163 | printf publish purge rebuild regexp repolist report rss schema search security_audit setup setupuser sha1 | > | 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | printf publish purge rebuild regexp repolist report robot rss schema search security_audit setup setupuser sha1 |
| ︙ | ︙ |
Changes to win/Makefile.dmc.
| ︙ | ︙ | |||
30 31 32 33 34 35 36 | SQLITE_OPTIONS = -DNDEBUG=1 -DSQLITE_DQS=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_MATH_FUNCTIONS -DSQLITE_ENABLE_SETLK_TIMEOUT -DSQLITE_ENABLE_STMTVTAB -DSQLITE_HAVE_ZLIB -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_TRUSTED_SCHEMA=0 -DHAVE_USLEEP SHELL_OPTIONS = -DNDEBUG=1 -DSQLITE_DQS=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_MATH_FUNCTIONS -DSQLITE_ENABLE_SETLK_TIMEOUT -DSQLITE_ENABLE_STMTVTAB -DSQLITE_HAVE_ZLIB -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_TRUSTED_SCHEMA=0 -DHAVE_USLEEP -Dmain=sqlite3_shell -DSQLITE_SHELL_IS_UTF8=1 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) -DSQLITE_SHELL_DBNAME_PROC=sqlcmd_get_dbname -DSQLITE_SHELL_INIT_PROC=sqlcmd_init_proc -Daccess=file_access -Dsystem=fossil_system -Dgetenv=fossil_getenv -Dfopen=fossil_fopen PIKCHR_OPTIONS = -DPIKCHR_TOKEN_LIMIT=10000 | | | | | 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | SQLITE_OPTIONS = -DNDEBUG=1 -DSQLITE_DQS=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_MATH_FUNCTIONS -DSQLITE_ENABLE_SETLK_TIMEOUT -DSQLITE_ENABLE_STMTVTAB -DSQLITE_HAVE_ZLIB -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_TRUSTED_SCHEMA=0 -DHAVE_USLEEP SHELL_OPTIONS = -DNDEBUG=1 -DSQLITE_DQS=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_MATH_FUNCTIONS -DSQLITE_ENABLE_SETLK_TIMEOUT -DSQLITE_ENABLE_STMTVTAB -DSQLITE_HAVE_ZLIB -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_TRUSTED_SCHEMA=0 -DHAVE_USLEEP -Dmain=sqlite3_shell -DSQLITE_SHELL_IS_UTF8=1 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) -DSQLITE_SHELL_DBNAME_PROC=sqlcmd_get_dbname -DSQLITE_SHELL_INIT_PROC=sqlcmd_init_proc -Daccess=file_access -Dsystem=fossil_system -Dgetenv=fossil_getenv -Dfopen=fossil_fopen PIKCHR_OPTIONS = -DPIKCHR_TOKEN_LIMIT=10000 SRC = add_.c ajax_.c alerts_.c allrepo_.c attach_.c backlink_.c backoffice_.c bag_.c bisect_.c blob_.c branch_.c browse_.c builtin_.c bundle_.c cache_.c capabilities_.c captcha_.c cgi_.c chat_.c checkin_.c checkout_.c clearsign_.c clone_.c color_.c comformat_.c configure_.c content_.c cookies_.c db_.c delta_.c deltacmd_.c deltafunc_.c descendants_.c diff_.c diffcmd_.c dispatch_.c doc_.c encode_.c etag_.c event_.c export_.c extcgi_.c file_.c fileedit_.c finfo_.c foci_.c forum_.c fshell_.c fusefs_.c fuzz_.c glob_.c graph_.c gzip_.c hname_.c hook_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c interwiki_.c json_.c json_artifact_.c json_branch_.c json_config_.c json_diff_.c json_dir_.c json_finfo_.c json_login_.c json_query_.c json_report_.c json_status_.c json_tag_.c json_timeline_.c json_user_.c json_wiki_.c leaf_.c loadctrl_.c login_.c lookslike_.c main_.c manifest_.c markdown_.c markdown_html_.c match_.c md5_.c merge_.c merge3_.c moderate_.c name_.c patch_.c path_.c piechart_.c pikchrshow_.c pivot_.c popen_.c pqueue_.c printf_.c publish_.c purge_.c rebuild_.c regexp_.c repolist_.c report_.c robot_.c rss_.c schema_.c search_.c security_audit_.c setup_.c setupuser_.c sha1_.c sha1hard_.c sha3_.c shun_.c sitemap_.c skins_.c smtp_.c sqlcmd_.c stash_.c stat_.c statrep_.c style_.c sync_.c tag_.c tar_.c terminal_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c unicode_.c unversioned_.c update_.c url_.c user_.c utf8_.c util_.c verify_.c vfile_.c wiki_.c wikiformat_.c winfile_.c winhttp_.c xfer_.c xfersetup_.c zip_.c OBJ = $(OBJDIR)\add$O $(OBJDIR)\ajax$O $(OBJDIR)\alerts$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\backlink$O $(OBJDIR)\backoffice$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\builtin$O $(OBJDIR)\bundle$O $(OBJDIR)\cache$O $(OBJDIR)\capabilities$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\chat$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\color$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\cookies$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\deltafunc$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\dispatch$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\etag$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\extcgi$O $(OBJDIR)\file$O $(OBJDIR)\fileedit$O $(OBJDIR)\finfo$O $(OBJDIR)\foci$O $(OBJDIR)\forum$O $(OBJDIR)\fshell$O $(OBJDIR)\fusefs$O $(OBJDIR)\fuzz$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\hname$O $(OBJDIR)\hook$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\interwiki$O $(OBJDIR)\json$O $(OBJDIR)\json_artifact$O $(OBJDIR)\json_branch$O $(OBJDIR)\json_config$O $(OBJDIR)\json_diff$O $(OBJDIR)\json_dir$O $(OBJDIR)\json_finfo$O $(OBJDIR)\json_login$O $(OBJDIR)\json_query$O $(OBJDIR)\json_report$O $(OBJDIR)\json_status$O $(OBJDIR)\json_tag$O $(OBJDIR)\json_timeline$O $(OBJDIR)\json_user$O $(OBJDIR)\json_wiki$O $(OBJDIR)\leaf$O $(OBJDIR)\loadctrl$O $(OBJDIR)\login$O $(OBJDIR)\lookslike$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\markdown$O $(OBJDIR)\markdown_html$O $(OBJDIR)\match$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\moderate$O $(OBJDIR)\name$O $(OBJDIR)\patch$O $(OBJDIR)\path$O $(OBJDIR)\piechart$O $(OBJDIR)\pikchrshow$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\publish$O $(OBJDIR)\purge$O $(OBJDIR)\rebuild$O $(OBJDIR)\regexp$O $(OBJDIR)\repolist$O $(OBJDIR)\report$O $(OBJDIR)\robot$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\security_audit$O $(OBJDIR)\setup$O $(OBJDIR)\setupuser$O $(OBJDIR)\sha1$O $(OBJDIR)\sha1hard$O $(OBJDIR)\sha3$O $(OBJDIR)\shun$O $(OBJDIR)\sitemap$O $(OBJDIR)\skins$O $(OBJDIR)\smtp$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\statrep$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\terminal$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\unicode$O $(OBJDIR)\unversioned$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\utf8$O $(OBJDIR)\util$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winfile$O $(OBJDIR)\winhttp$O $(OBJDIR)\xfer$O $(OBJDIR)\xfersetup$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O RC=$(DMDIR)\bin\rcc RCFLAGS=-32 -w1 -I$(SRCDIR) /D__DMC__ APPNAME = $(OBJDIR)\fossil$(E) all: $(APPNAME) $(APPNAME) : translate$E mkindex$E codecheck1$E headers $(OBJ) $(OBJDIR)\link cd $(OBJDIR) codecheck1$E $(SRC) $(DMDIR)\bin\link @link $(OBJDIR)\fossil.res: $B\win\fossil.rc $(RC) $(RCFLAGS) -o$@ $** $(OBJDIR)\link: $B\win\Makefile.dmc $(OBJDIR)\fossil.res +echo add ajax alerts allrepo attach backlink backoffice bag bisect blob branch browse builtin bundle cache capabilities captcha cgi chat checkin checkout clearsign clone color comformat configure content cookies db delta deltacmd deltafunc descendants diff diffcmd dispatch doc encode etag event export extcgi file fileedit finfo foci forum fshell fusefs fuzz glob graph gzip hname hook http http_socket http_ssl http_transport import info interwiki json json_artifact json_branch json_config json_diff json_dir json_finfo json_login json_query json_report json_status json_tag json_timeline json_user json_wiki leaf loadctrl login lookslike main manifest markdown markdown_html match md5 merge merge3 moderate name patch path piechart pikchrshow pivot popen pqueue printf publish purge rebuild regexp repolist report robot rss schema search security_audit setup setupuser sha1 sha1hard sha3 shun sitemap skins smtp sqlcmd stash stat statrep style sync tag tar terminal th_main timeline tkt tktsetup undo unicode unversioned update url user utf8 util verify vfile wiki wikiformat winfile winhttp xfer xfersetup zip shell sqlite3 th th_lang > $@ +echo fossil >> $@ +echo fossil >> $@ +echo $(LIBS) >> $@ +echo. >> $@ +echo fossil >> $@ translate$E: $(SRCDIR_tools)\translate.c |
| ︙ | ︙ | |||
753 754 755 756 757 758 759 760 761 762 763 764 765 766 | +translate$E $** > $@ $(OBJDIR)\report$O : report_.c report.h $(TCC) -o$@ -c report_.c report_.c : $(SRCDIR)\report.c +translate$E $** > $@ $(OBJDIR)\rss$O : rss_.c rss.h $(TCC) -o$@ -c rss_.c rss_.c : $(SRCDIR)\rss.c +translate$E $** > $@ | > > > > > > | 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 | +translate$E $** > $@ $(OBJDIR)\report$O : report_.c report.h $(TCC) -o$@ -c report_.c report_.c : $(SRCDIR)\report.c +translate$E $** > $@ $(OBJDIR)\robot$O : robot_.c robot.h $(TCC) -o$@ -c robot_.c robot_.c : $(SRCDIR)\robot.c +translate$E $** > $@ $(OBJDIR)\rss$O : rss_.c rss.h $(TCC) -o$@ -c rss_.c rss_.c : $(SRCDIR)\rss.c +translate$E $** > $@ |
| ︙ | ︙ | |||
1013 1014 1015 1016 1017 1018 1019 | $(OBJDIR)\zip$O : zip_.c zip.h $(TCC) -o$@ -c zip_.c zip_.c : $(SRCDIR)\zip.c +translate$E $** > $@ headers: makeheaders$E page_index.h builtin_data.h VERSION.h | | | 1019 1020 1021 1022 1023 1024 1025 1026 1027 | $(OBJDIR)\zip$O : zip_.c zip.h $(TCC) -o$@ -c zip_.c zip_.c : $(SRCDIR)\zip.c +translate$E $** > $@ headers: makeheaders$E page_index.h builtin_data.h VERSION.h +makeheaders$E add_.c:add.h ajax_.c:ajax.h alerts_.c:alerts.h allrepo_.c:allrepo.h attach_.c:attach.h backlink_.c:backlink.h backoffice_.c:backoffice.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h builtin_.c:builtin.h bundle_.c:bundle.h cache_.c:cache.h capabilities_.c:capabilities.h captcha_.c:captcha.h cgi_.c:cgi.h chat_.c:chat.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h color_.c:color.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h cookies_.c:cookies.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h deltafunc_.c:deltafunc.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h dispatch_.c:dispatch.h doc_.c:doc.h encode_.c:encode.h etag_.c:etag.h event_.c:event.h export_.c:export.h extcgi_.c:extcgi.h file_.c:file.h fileedit_.c:fileedit.h finfo_.c:finfo.h foci_.c:foci.h forum_.c:forum.h fshell_.c:fshell.h fusefs_.c:fusefs.h fuzz_.c:fuzz.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.h hname_.c:hname.h hook_.c:hook.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h interwiki_.c:interwiki.h json_.c:json.h json_artifact_.c:json_artifact.h json_branch_.c:json_branch.h json_config_.c:json_config.h json_diff_.c:json_diff.h json_dir_.c:json_dir.h json_finfo_.c:json_finfo.h json_login_.c:json_login.h json_query_.c:json_query.h json_report_.c:json_report.h json_status_.c:json_status.h json_tag_.c:json_tag.h json_timeline_.c:json_timeline.h json_user_.c:json_user.h json_wiki_.c:json_wiki.h leaf_.c:leaf.h loadctrl_.c:loadctrl.h login_.c:login.h lookslike_.c:lookslike.h main_.c:main.h manifest_.c:manifest.h markdown_.c:markdown.h markdown_html_.c:markdown_html.h match_.c:match.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h moderate_.c:moderate.h name_.c:name.h patch_.c:patch.h path_.c:path.h piechart_.c:piechart.h pikchrshow_.c:pikchrshow.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h publish_.c:publish.h purge_.c:purge.h rebuild_.c:rebuild.h regexp_.c:regexp.h repolist_.c:repolist.h report_.c:report.h robot_.c:robot.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h security_audit_.c:security_audit.h setup_.c:setup.h setupuser_.c:setupuser.h sha1_.c:sha1.h sha1hard_.c:sha1hard.h sha3_.c:sha3.h shun_.c:shun.h sitemap_.c:sitemap.h skins_.c:skins.h smtp_.c:smtp.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h statrep_.c:statrep.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h terminal_.c:terminal.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h unicode_.c:unicode.h unversioned_.c:unversioned.h update_.c:update.h url_.c:url.h user_.c:user.h utf8_.c:utf8.h util_.c:util.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winfile_.c:winfile.h winhttp_.c:winhttp.h xfer_.c:xfer.h xfersetup_.c:xfersetup.h zip_.c:zip.h $(SRCDIR_extsrc)\pikchr.c:pikchr.h $(SRCDIR_extsrc)\sqlite3.h $(SRCDIR)\th.h VERSION.h $(SRCDIR_extsrc)\cson_amalgamation.h @copy /Y nul: headers |
Changes to win/Makefile.mingw.
| ︙ | ︙ | |||
503 504 505 506 507 508 509 510 511 512 513 514 515 516 | $(SRCDIR)/printf.c \ $(SRCDIR)/publish.c \ $(SRCDIR)/purge.c \ $(SRCDIR)/rebuild.c \ $(SRCDIR)/regexp.c \ $(SRCDIR)/repolist.c \ $(SRCDIR)/report.c \ $(SRCDIR)/rss.c \ $(SRCDIR)/schema.c \ $(SRCDIR)/search.c \ $(SRCDIR)/security_audit.c \ $(SRCDIR)/setup.c \ $(SRCDIR)/setupuser.c \ $(SRCDIR)/sha1.c \ | > | 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 | $(SRCDIR)/printf.c \ $(SRCDIR)/publish.c \ $(SRCDIR)/purge.c \ $(SRCDIR)/rebuild.c \ $(SRCDIR)/regexp.c \ $(SRCDIR)/repolist.c \ $(SRCDIR)/report.c \ $(SRCDIR)/robot.c \ $(SRCDIR)/rss.c \ $(SRCDIR)/schema.c \ $(SRCDIR)/search.c \ $(SRCDIR)/security_audit.c \ $(SRCDIR)/setup.c \ $(SRCDIR)/setupuser.c \ $(SRCDIR)/sha1.c \ |
| ︙ | ︙ | |||
769 770 771 772 773 774 775 776 777 778 779 780 781 782 | $(OBJDIR)/printf_.c \ $(OBJDIR)/publish_.c \ $(OBJDIR)/purge_.c \ $(OBJDIR)/rebuild_.c \ $(OBJDIR)/regexp_.c \ $(OBJDIR)/repolist_.c \ $(OBJDIR)/report_.c \ $(OBJDIR)/rss_.c \ $(OBJDIR)/schema_.c \ $(OBJDIR)/search_.c \ $(OBJDIR)/security_audit_.c \ $(OBJDIR)/setup_.c \ $(OBJDIR)/setupuser_.c \ $(OBJDIR)/sha1_.c \ | > | 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 | $(OBJDIR)/printf_.c \ $(OBJDIR)/publish_.c \ $(OBJDIR)/purge_.c \ $(OBJDIR)/rebuild_.c \ $(OBJDIR)/regexp_.c \ $(OBJDIR)/repolist_.c \ $(OBJDIR)/report_.c \ $(OBJDIR)/robot_.c \ $(OBJDIR)/rss_.c \ $(OBJDIR)/schema_.c \ $(OBJDIR)/search_.c \ $(OBJDIR)/security_audit_.c \ $(OBJDIR)/setup_.c \ $(OBJDIR)/setupuser_.c \ $(OBJDIR)/sha1_.c \ |
| ︙ | ︙ | |||
919 920 921 922 923 924 925 926 927 928 929 930 931 932 | $(OBJDIR)/printf.o \ $(OBJDIR)/publish.o \ $(OBJDIR)/purge.o \ $(OBJDIR)/rebuild.o \ $(OBJDIR)/regexp.o \ $(OBJDIR)/repolist.o \ $(OBJDIR)/report.o \ $(OBJDIR)/rss.o \ $(OBJDIR)/schema.o \ $(OBJDIR)/search.o \ $(OBJDIR)/security_audit.o \ $(OBJDIR)/setup.o \ $(OBJDIR)/setupuser.o \ $(OBJDIR)/sha1.o \ | > | 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 | $(OBJDIR)/printf.o \ $(OBJDIR)/publish.o \ $(OBJDIR)/purge.o \ $(OBJDIR)/rebuild.o \ $(OBJDIR)/regexp.o \ $(OBJDIR)/repolist.o \ $(OBJDIR)/report.o \ $(OBJDIR)/robot.o \ $(OBJDIR)/rss.o \ $(OBJDIR)/schema.o \ $(OBJDIR)/search.o \ $(OBJDIR)/security_audit.o \ $(OBJDIR)/setup.o \ $(OBJDIR)/setupuser.o \ $(OBJDIR)/sha1.o \ |
| ︙ | ︙ | |||
1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 | $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h \ $(OBJDIR)/publish_.c:$(OBJDIR)/publish.h \ $(OBJDIR)/purge_.c:$(OBJDIR)/purge.h \ $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h \ $(OBJDIR)/regexp_.c:$(OBJDIR)/regexp.h \ $(OBJDIR)/repolist_.c:$(OBJDIR)/repolist.h \ $(OBJDIR)/report_.c:$(OBJDIR)/report.h \ $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h \ $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h \ $(OBJDIR)/search_.c:$(OBJDIR)/search.h \ $(OBJDIR)/security_audit_.c:$(OBJDIR)/security_audit.h \ $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h \ $(OBJDIR)/setupuser_.c:$(OBJDIR)/setupuser.h \ $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h \ | > | 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 | $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h \ $(OBJDIR)/publish_.c:$(OBJDIR)/publish.h \ $(OBJDIR)/purge_.c:$(OBJDIR)/purge.h \ $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h \ $(OBJDIR)/regexp_.c:$(OBJDIR)/regexp.h \ $(OBJDIR)/repolist_.c:$(OBJDIR)/repolist.h \ $(OBJDIR)/report_.c:$(OBJDIR)/report.h \ $(OBJDIR)/robot_.c:$(OBJDIR)/robot.h \ $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h \ $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h \ $(OBJDIR)/search_.c:$(OBJDIR)/search.h \ $(OBJDIR)/security_audit_.c:$(OBJDIR)/security_audit.h \ $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h \ $(OBJDIR)/setupuser_.c:$(OBJDIR)/setupuser.h \ $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h \ |
| ︙ | ︙ | |||
2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 | $(OBJDIR)/report_.c: $(SRCDIR)/report.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/report.c >$@ $(OBJDIR)/report.o: $(OBJDIR)/report_.c $(OBJDIR)/report.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/report.o -c $(OBJDIR)/report_.c $(OBJDIR)/report.h: $(OBJDIR)/headers $(OBJDIR)/rss_.c: $(SRCDIR)/rss.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/rss.c >$@ $(OBJDIR)/rss.o: $(OBJDIR)/rss_.c $(OBJDIR)/rss.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/rss.o -c $(OBJDIR)/rss_.c | > > > > > > > > | 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 | $(OBJDIR)/report_.c: $(SRCDIR)/report.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/report.c >$@ $(OBJDIR)/report.o: $(OBJDIR)/report_.c $(OBJDIR)/report.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/report.o -c $(OBJDIR)/report_.c $(OBJDIR)/report.h: $(OBJDIR)/headers $(OBJDIR)/robot_.c: $(SRCDIR)/robot.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/robot.c >$@ $(OBJDIR)/robot.o: $(OBJDIR)/robot_.c $(OBJDIR)/robot.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/robot.o -c $(OBJDIR)/robot_.c $(OBJDIR)/robot.h: $(OBJDIR)/headers $(OBJDIR)/rss_.c: $(SRCDIR)/rss.c $(TRANSLATE) $(TRANSLATE) $(SRCDIR)/rss.c >$@ $(OBJDIR)/rss.o: $(OBJDIR)/rss_.c $(OBJDIR)/rss.h $(SRCDIR)/config.h $(XTCC) -o $(OBJDIR)/rss.o -c $(OBJDIR)/rss_.c |
| ︙ | ︙ |
Changes to win/Makefile.msc.
| ︙ | ︙ | |||
465 466 467 468 469 470 471 472 473 474 475 476 477 478 |
"$(OX)\printf_.c" \
"$(OX)\publish_.c" \
"$(OX)\purge_.c" \
"$(OX)\rebuild_.c" \
"$(OX)\regexp_.c" \
"$(OX)\repolist_.c" \
"$(OX)\report_.c" \
"$(OX)\rss_.c" \
"$(OX)\schema_.c" \
"$(OX)\search_.c" \
"$(OX)\security_audit_.c" \
"$(OX)\setup_.c" \
"$(OX)\setupuser_.c" \
"$(OX)\sha1_.c" \
| > | 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 |
"$(OX)\printf_.c" \
"$(OX)\publish_.c" \
"$(OX)\purge_.c" \
"$(OX)\rebuild_.c" \
"$(OX)\regexp_.c" \
"$(OX)\repolist_.c" \
"$(OX)\report_.c" \
"$(OX)\robot_.c" \
"$(OX)\rss_.c" \
"$(OX)\schema_.c" \
"$(OX)\search_.c" \
"$(OX)\security_audit_.c" \
"$(OX)\setup_.c" \
"$(OX)\setupuser_.c" \
"$(OX)\sha1_.c" \
|
| ︙ | ︙ | |||
732 733 734 735 736 737 738 739 740 741 742 743 744 745 |
"$(OX)\printf$O" \
"$(OX)\publish$O" \
"$(OX)\purge$O" \
"$(OX)\rebuild$O" \
"$(OX)\regexp$O" \
"$(OX)\repolist$O" \
"$(OX)\report$O" \
"$(OX)\rss$O" \
"$(OX)\schema$O" \
"$(OX)\search$O" \
"$(OX)\security_audit$O" \
"$(OX)\setup$O" \
"$(OX)\setupuser$O" \
"$(OX)\sha1$O" \
| > | 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 |
"$(OX)\printf$O" \
"$(OX)\publish$O" \
"$(OX)\purge$O" \
"$(OX)\rebuild$O" \
"$(OX)\regexp$O" \
"$(OX)\repolist$O" \
"$(OX)\report$O" \
"$(OX)\robot$O" \
"$(OX)\rss$O" \
"$(OX)\schema$O" \
"$(OX)\search$O" \
"$(OX)\security_audit$O" \
"$(OX)\setup$O" \
"$(OX)\setupuser$O" \
"$(OX)\sha1$O" \
|
| ︙ | ︙ | |||
982 983 984 985 986 987 988 989 990 991 992 993 994 995 | echo "$(OX)\printf.obj" >> $@ echo "$(OX)\publish.obj" >> $@ echo "$(OX)\purge.obj" >> $@ echo "$(OX)\rebuild.obj" >> $@ echo "$(OX)\regexp.obj" >> $@ echo "$(OX)\repolist.obj" >> $@ echo "$(OX)\report.obj" >> $@ echo "$(OX)\rss.obj" >> $@ echo "$(OX)\schema.obj" >> $@ echo "$(OX)\search.obj" >> $@ echo "$(OX)\security_audit.obj" >> $@ echo "$(OX)\setup.obj" >> $@ echo "$(OX)\setupuser.obj" >> $@ echo "$(OX)\sha1.obj" >> $@ | > | 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 | echo "$(OX)\printf.obj" >> $@ echo "$(OX)\publish.obj" >> $@ echo "$(OX)\purge.obj" >> $@ echo "$(OX)\rebuild.obj" >> $@ echo "$(OX)\regexp.obj" >> $@ echo "$(OX)\repolist.obj" >> $@ echo "$(OX)\report.obj" >> $@ echo "$(OX)\robot.obj" >> $@ echo "$(OX)\rss.obj" >> $@ echo "$(OX)\schema.obj" >> $@ echo "$(OX)\search.obj" >> $@ echo "$(OX)\security_audit.obj" >> $@ echo "$(OX)\setup.obj" >> $@ echo "$(OX)\setupuser.obj" >> $@ echo "$(OX)\sha1.obj" >> $@ |
| ︙ | ︙ | |||
1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 | "$(OBJDIR)\translate$E" $** > $@ "$(OX)\report$O" : "$(OX)\report_.c" "$(OX)\report.h" $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\report_.c" "$(OX)\report_.c" : "$(SRCDIR)\report.c" "$(OBJDIR)\translate$E" $** > $@ "$(OX)\rss$O" : "$(OX)\rss_.c" "$(OX)\rss.h" $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\rss_.c" "$(OX)\rss_.c" : "$(SRCDIR)\rss.c" "$(OBJDIR)\translate$E" $** > $@ | > > > > > > | 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 | "$(OBJDIR)\translate$E" $** > $@ "$(OX)\report$O" : "$(OX)\report_.c" "$(OX)\report.h" $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\report_.c" "$(OX)\report_.c" : "$(SRCDIR)\report.c" "$(OBJDIR)\translate$E" $** > $@ "$(OX)\robot$O" : "$(OX)\robot_.c" "$(OX)\robot.h" $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\robot_.c" "$(OX)\robot_.c" : "$(SRCDIR)\robot.c" "$(OBJDIR)\translate$E" $** > $@ "$(OX)\rss$O" : "$(OX)\rss_.c" "$(OX)\rss.h" $(TCC) /Fo$@ /Fd$(@D)\ -c "$(OX)\rss_.c" "$(OX)\rss_.c" : "$(SRCDIR)\rss.c" "$(OBJDIR)\translate$E" $** > $@ |
| ︙ | ︙ | |||
2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 | "$(OX)\printf_.c":"$(OX)\printf.h" \ "$(OX)\publish_.c":"$(OX)\publish.h" \ "$(OX)\purge_.c":"$(OX)\purge.h" \ "$(OX)\rebuild_.c":"$(OX)\rebuild.h" \ "$(OX)\regexp_.c":"$(OX)\regexp.h" \ "$(OX)\repolist_.c":"$(OX)\repolist.h" \ "$(OX)\report_.c":"$(OX)\report.h" \ "$(OX)\rss_.c":"$(OX)\rss.h" \ "$(OX)\schema_.c":"$(OX)\schema.h" \ "$(OX)\search_.c":"$(OX)\search.h" \ "$(OX)\security_audit_.c":"$(OX)\security_audit.h" \ "$(OX)\setup_.c":"$(OX)\setup.h" \ "$(OX)\setupuser_.c":"$(OX)\setupuser.h" \ "$(OX)\sha1_.c":"$(OX)\sha1.h" \ | > | 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 | "$(OX)\printf_.c":"$(OX)\printf.h" \ "$(OX)\publish_.c":"$(OX)\publish.h" \ "$(OX)\purge_.c":"$(OX)\purge.h" \ "$(OX)\rebuild_.c":"$(OX)\rebuild.h" \ "$(OX)\regexp_.c":"$(OX)\regexp.h" \ "$(OX)\repolist_.c":"$(OX)\repolist.h" \ "$(OX)\report_.c":"$(OX)\report.h" \ "$(OX)\robot_.c":"$(OX)\robot.h" \ "$(OX)\rss_.c":"$(OX)\rss.h" \ "$(OX)\schema_.c":"$(OX)\schema.h" \ "$(OX)\search_.c":"$(OX)\search.h" \ "$(OX)\security_audit_.c":"$(OX)\security_audit.h" \ "$(OX)\setup_.c":"$(OX)\setup.h" \ "$(OX)\setupuser_.c":"$(OX)\setupuser.h" \ "$(OX)\sha1_.c":"$(OX)\sha1.h" \ |
| ︙ | ︙ |
Changes to www/changes.wiki.
| ︙ | ︙ | |||
11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
so that it works with other query parameters like p=, d=, from=, and to=.
<li> Always include nodes identify by sel1= and sel2= in the /timeline display.
<li> Enable the --editor option on the [/help?cmd=amend|fossil amend] command.
<li> Require at least an anonymous login to access the /blame page and similar,
to help prevent robots from soaking up excess CPU time on such pages.
<li> When walking the filesystem looking for Fossil repositories, avoid descending
into directories named "/proc".
</ol>
<h2 id='v2_26'>Changes for version 2.26 (2025-04-30)</h2><ol>
<li>Enhancements to [/help?cmd=diff|fossil diff] and similar:
<ol type="a">
<li> The argument to the --from option can be a directory name, causing
Fossil to use files under that directory as the baseline for the diff.
| > > > | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
so that it works with other query parameters like p=, d=, from=, and to=.
<li> Always include nodes identify by sel1= and sel2= in the /timeline display.
<li> Enable the --editor option on the [/help?cmd=amend|fossil amend] command.
<li> Require at least an anonymous login to access the /blame page and similar,
to help prevent robots from soaking up excess CPU time on such pages.
<li> When walking the filesystem looking for Fossil repositories, avoid descending
into directories named "/proc".
<li> Reduce memory requirements for sending authenticated sync protocol
messages.
<li> Add the [/help?cmd=stash | stash rename] subcommand.
</ol>
<h2 id='v2_26'>Changes for version 2.26 (2025-04-30)</h2><ol>
<li>Enhancements to [/help?cmd=diff|fossil diff] and similar:
<ol type="a">
<li> The argument to the --from option can be a directory name, causing
Fossil to use files under that directory as the baseline for the diff.
|
| ︙ | ︙ |
Changes to www/sync.wiki.
| ︙ | ︙ | |||
218 219 220 221 222 223 224 | <h3 id="login">3.2 Login Cards</h3> Every message from client to server begins with one or more login cards. Each login card has the following format: <pre><b>login</b> <i>userid nonce signature</i></pre> | | > | | | | | | | < | | > > > > | > > | > > > | > > > | 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 | <h3 id="login">3.2 Login Cards</h3> Every message from client to server begins with one or more login cards. Each login card has the following format: <pre><b>login</b> <i>userid nonce signature</i></pre> The userid is the name of the user that is requesting service from the server, encoded in "fossilized" form (exactly as described for <a href="#error">the error card</a>). The nonce is the SHA1 hash of the remainder of the message - all text that follows the newline character that terminates the login card. The signature is the SHA1 hash of the concatenation of the nonce and the users password. When receving a login card, the server looks up the user and verifies that the nonce matches the SHA1 hash of the remainder of the message. It then checks the signature hash to make sure the signature matches. If everything checks out, then the client is granted all privileges of the specified user. Only one login card is permitted. A second login card will trigger a sync error. (Prior to 2025-07-21, the protocol permitted multiple logins, treating the login as the union of all privileges from all login cards. That capability was never used and has been removed.) As of version 2.27, Fossil supports transfering of the login card externally to the request payload via a Cookie HTTP header: <verbatim> Cookie: x-f-x-l=... </verbatim> Where "..." is the URL-encoded login cookie. <code>x-f-x-l</code> is short for X-Fossil-Xfer-Login. <h3 id="file">3.3 File Cards</h3> Artifacts are transferred using either "file" cards, or "cfile" or "uvfile" cards. The name "file" card comes from the fact that most artifacts correspond to files that are under version control. |
| ︙ | ︙ |