Fossil SCM
Merge updates from trunk.
Commit
2269309f92d928ca9fcf3d57874c39926b4c4b941b72e3a02fb5f344936b8441
Parent
d364933abc1ffe9…
23 files changed
+5
-7
+1
-1
+1
-1
+4
-4
+4
-1
+48
-28
+2
-1
+1
-1
+34
-34
+34
-34
+67
-40
+11
-10
+5
-5
+28
-28
+28
-28
+721
-143
+6
-4
-215
+59
-222
+1
-1
+1
-1
+2
-1
+5
-3
~
Dockerfile
~
Makefile.in
~
VERSION
~
auto.def
~
skins/default/css.txt
~
src/branch.c
~
src/json_branch.c
~
src/main.mk
~
src/makemake.tcl
~
src/makemake.tcl
~
src/sqlite3.c
~
src/sqlite3.h
~
win/Makefile.PellesCGMake
~
win/Makefile.msc
~
win/Makefile.msc
~
www/alerts.md
~
www/changes.wiki
-
www/emaildesign.md
~
www/forum.wiki
~
www/makefile.wiki
~
www/makefile.wiki
~
www/mkindex.tcl
~
www/permutedindex.html
+5
-7
| --- Dockerfile | ||
| +++ Dockerfile | ||
| @@ -1,25 +1,23 @@ | ||
| 1 | 1 | ### |
| 2 | 2 | # Dockerfile for Fossil |
| 3 | 3 | ### |
| 4 | -FROM fedora:24 | |
| 4 | +FROM fedora:28 | |
| 5 | 5 | |
| 6 | 6 | ### Now install some additional parts we will need for the build |
| 7 | -RUN dnf update -y && dnf install -y gcc make zlib-devel openssl-devel tar && dnf clean all && groupadd -r fossil -g 433 && useradd -u 431 -r -g fossil -d /opt/fossil -s /sbin/nologin -c "Fossil user" fossil | |
| 7 | +RUN dnf update -y && dnf install -y gcc make tcl tcl-devel zlib-devel openssl-devel tar && dnf clean all && groupadd -r fossil -g 433 && useradd -u 431 -r -g fossil -d /opt/fossil -s /sbin/nologin -c "Fossil user" fossil | |
| 8 | 8 | |
| 9 | 9 | ### If you want to build "trunk", change the next line accordingly. |
| 10 | 10 | ENV FOSSIL_INSTALL_VERSION release |
| 11 | 11 | |
| 12 | -RUN curl "http://core.tcl.tk/tcl/tarball/tcl-src.tar.gz?name=tcl-src&uuid=release" | tar zx | |
| 13 | -RUN cd tcl-src/unix && ./configure --prefix=/usr --disable-load && make && make install | |
| 14 | -RUN curl "http://www.fossil-scm.org/index.html/tarball/fossil-src.tar.gz?name=fossil-src&uuid=${FOSSIL_INSTALL_VERSION}" | tar zx | |
| 15 | -RUN cd fossil-src && ./configure --disable-fusefs --json --with-th1-docs --with-th1-hooks --with-tcl --with-tcl-stubs --with-tcl-private-stubs | |
| 12 | +RUN curl "https://www.fossil-scm.org/index.html/tarball/fossil-src.tar.gz?name=fossil-src&uuid=${FOSSIL_INSTALL_VERSION}" | tar zx | |
| 13 | +RUN cd fossil-src && ./configure --disable-fusefs --json --with-th1-docs --with-th1-hooks --with-tcl=1 --with-tcl-stubs --with-tcl-private-stubs | |
| 16 | 14 | RUN cd fossil-src/src && mv main.c main.c.orig && sed s/\"now\"/0/ <main.c.orig >main.c |
| 17 | 15 | RUN cd fossil-src && make && strip fossil && cp fossil /usr/bin && cd .. && rm -rf fossil-src && chmod a+rx /usr/bin/fossil && mkdir -p /opt/fossil && chown fossil:fossil /opt/fossil |
| 18 | 16 | |
| 19 | 17 | ### Build is done, remove modules no longer needed |
| 20 | -RUN dnf remove -y gcc make zlib-devel openssl-devel tar && dnf clean all | |
| 18 | +RUN dnf remove -y gcc make zlib-devel tcl-devel openssl-devel tar && dnf clean all | |
| 21 | 19 | |
| 22 | 20 | USER fossil |
| 23 | 21 | |
| 24 | 22 | ENV HOME /opt/fossil |
| 25 | 23 | |
| 26 | 24 |
| --- Dockerfile | |
| +++ Dockerfile | |
| @@ -1,25 +1,23 @@ | |
| 1 | ### |
| 2 | # Dockerfile for Fossil |
| 3 | ### |
| 4 | FROM fedora:24 |
| 5 | |
| 6 | ### Now install some additional parts we will need for the build |
| 7 | RUN dnf update -y && dnf install -y gcc make zlib-devel openssl-devel tar && dnf clean all && groupadd -r fossil -g 433 && useradd -u 431 -r -g fossil -d /opt/fossil -s /sbin/nologin -c "Fossil user" fossil |
| 8 | |
| 9 | ### If you want to build "trunk", change the next line accordingly. |
| 10 | ENV FOSSIL_INSTALL_VERSION release |
| 11 | |
| 12 | RUN curl "http://core.tcl.tk/tcl/tarball/tcl-src.tar.gz?name=tcl-src&uuid=release" | tar zx |
| 13 | RUN cd tcl-src/unix && ./configure --prefix=/usr --disable-load && make && make install |
| 14 | RUN curl "http://www.fossil-scm.org/index.html/tarball/fossil-src.tar.gz?name=fossil-src&uuid=${FOSSIL_INSTALL_VERSION}" | tar zx |
| 15 | RUN cd fossil-src && ./configure --disable-fusefs --json --with-th1-docs --with-th1-hooks --with-tcl --with-tcl-stubs --with-tcl-private-stubs |
| 16 | RUN cd fossil-src/src && mv main.c main.c.orig && sed s/\"now\"/0/ <main.c.orig >main.c |
| 17 | RUN cd fossil-src && make && strip fossil && cp fossil /usr/bin && cd .. && rm -rf fossil-src && chmod a+rx /usr/bin/fossil && mkdir -p /opt/fossil && chown fossil:fossil /opt/fossil |
| 18 | |
| 19 | ### Build is done, remove modules no longer needed |
| 20 | RUN dnf remove -y gcc make zlib-devel openssl-devel tar && dnf clean all |
| 21 | |
| 22 | USER fossil |
| 23 | |
| 24 | ENV HOME /opt/fossil |
| 25 | |
| 26 |
| --- Dockerfile | |
| +++ Dockerfile | |
| @@ -1,25 +1,23 @@ | |
| 1 | ### |
| 2 | # Dockerfile for Fossil |
| 3 | ### |
| 4 | FROM fedora:28 |
| 5 | |
| 6 | ### Now install some additional parts we will need for the build |
| 7 | RUN dnf update -y && dnf install -y gcc make tcl tcl-devel zlib-devel openssl-devel tar && dnf clean all && groupadd -r fossil -g 433 && useradd -u 431 -r -g fossil -d /opt/fossil -s /sbin/nologin -c "Fossil user" fossil |
| 8 | |
| 9 | ### If you want to build "trunk", change the next line accordingly. |
| 10 | ENV FOSSIL_INSTALL_VERSION release |
| 11 | |
| 12 | RUN curl "https://www.fossil-scm.org/index.html/tarball/fossil-src.tar.gz?name=fossil-src&uuid=${FOSSIL_INSTALL_VERSION}" | tar zx |
| 13 | RUN cd fossil-src && ./configure --disable-fusefs --json --with-th1-docs --with-th1-hooks --with-tcl=1 --with-tcl-stubs --with-tcl-private-stubs |
| 14 | RUN cd fossil-src/src && mv main.c main.c.orig && sed s/\"now\"/0/ <main.c.orig >main.c |
| 15 | RUN cd fossil-src && make && strip fossil && cp fossil /usr/bin && cd .. && rm -rf fossil-src && chmod a+rx /usr/bin/fossil && mkdir -p /opt/fossil && chown fossil:fossil /opt/fossil |
| 16 | |
| 17 | ### Build is done, remove modules no longer needed |
| 18 | RUN dnf remove -y gcc make zlib-devel tcl-devel openssl-devel tar && dnf clean all |
| 19 | |
| 20 | USER fossil |
| 21 | |
| 22 | ENV HOME /opt/fossil |
| 23 | |
| 24 |
+1
-1
| --- Makefile.in | ||
| +++ Makefile.in | ||
| @@ -50,11 +50,11 @@ | ||
| 50 | 50 | FOSSIL_ENABLE_MINIZ = @FOSSIL_ENABLE_MINIZ@ |
| 51 | 51 | |
| 52 | 52 | include $(SRCDIR)/main.mk |
| 53 | 53 | |
| 54 | 54 | distclean: clean |
| 55 | - rm -f autoconfig.h config.log Makefile | |
| 55 | + -rm -f autoconfig.h config.log Makefile | |
| 56 | 56 | |
| 57 | 57 | reconfig: |
| 58 | 58 | @AUTOREMAKE@ |
| 59 | 59 | |
| 60 | 60 | # Automatically reconfigure whenever an autosetup file or one of the |
| 61 | 61 |
| --- Makefile.in | |
| +++ Makefile.in | |
| @@ -50,11 +50,11 @@ | |
| 50 | FOSSIL_ENABLE_MINIZ = @FOSSIL_ENABLE_MINIZ@ |
| 51 | |
| 52 | include $(SRCDIR)/main.mk |
| 53 | |
| 54 | distclean: clean |
| 55 | rm -f autoconfig.h config.log Makefile |
| 56 | |
| 57 | reconfig: |
| 58 | @AUTOREMAKE@ |
| 59 | |
| 60 | # Automatically reconfigure whenever an autosetup file or one of the |
| 61 |
| --- Makefile.in | |
| +++ Makefile.in | |
| @@ -50,11 +50,11 @@ | |
| 50 | FOSSIL_ENABLE_MINIZ = @FOSSIL_ENABLE_MINIZ@ |
| 51 | |
| 52 | include $(SRCDIR)/main.mk |
| 53 | |
| 54 | distclean: clean |
| 55 | -rm -f autoconfig.h config.log Makefile |
| 56 | |
| 57 | reconfig: |
| 58 | @AUTOREMAKE@ |
| 59 | |
| 60 | # Automatically reconfigure whenever an autosetup file or one of the |
| 61 |
M
VERSION
+1
-1
| --- VERSION | ||
| +++ VERSION | ||
| @@ -1,1 +1,1 @@ | ||
| 1 | -2.6 | |
| 1 | +2.7 | |
| 2 | 2 |
| --- VERSION | |
| +++ VERSION | |
| @@ -1,1 +1,1 @@ | |
| 1 | 2.6 |
| 2 |
| --- VERSION | |
| +++ VERSION | |
| @@ -1,1 +1,1 @@ | |
| 1 | 2.7 |
| 2 |
M
auto.def
+4
-4
| --- auto.def | ||
| +++ auto.def | ||
| @@ -126,17 +126,17 @@ | ||
| 126 | 126 | # the code below will append -ldl to LIBS. |
| 127 | 127 | # |
| 128 | 128 | foreach extralibs {{} {-ldl}} { |
| 129 | 129 | |
| 130 | 130 | # Locate the system SQLite by searching for sqlite3_open(). Then check |
| 131 | - # if sqlite3_keyword_check() can be found as well. If we can find open() but | |
| 132 | - # not keyword_check(), then the system SQLite is too old to link against | |
| 131 | + # if sqlite3_create_window_function can be found as well. If we can find open() but | |
| 132 | + # not create_window_function(), then the system SQLite is too old to link against | |
| 133 | 133 | # fossil. |
| 134 | 134 | # |
| 135 | 135 | if {[check-function-in-lib sqlite3_open sqlite3 $extralibs]} { |
| 136 | - if {![check-function-in-lib sqlite3_keyword_check sqlite3 $extralibs]} { | |
| 137 | - user-error "system sqlite3 too old (require >= 3.24.0)" | |
| 136 | + if {![check-function-in-lib sqlite3_create_window_function sqlite3 $extralibs]} { | |
| 137 | + user-error "system sqlite3 too old (require >= 3.25.0)" | |
| 138 | 138 | } |
| 139 | 139 | |
| 140 | 140 | # Success. Update symbols and return. |
| 141 | 141 | # |
| 142 | 142 | define USE_SYSTEM_SQLITE 1 |
| 143 | 143 |
| --- auto.def | |
| +++ auto.def | |
| @@ -126,17 +126,17 @@ | |
| 126 | # the code below will append -ldl to LIBS. |
| 127 | # |
| 128 | foreach extralibs {{} {-ldl}} { |
| 129 | |
| 130 | # Locate the system SQLite by searching for sqlite3_open(). Then check |
| 131 | # if sqlite3_keyword_check() can be found as well. If we can find open() but |
| 132 | # not keyword_check(), then the system SQLite is too old to link against |
| 133 | # fossil. |
| 134 | # |
| 135 | if {[check-function-in-lib sqlite3_open sqlite3 $extralibs]} { |
| 136 | if {![check-function-in-lib sqlite3_keyword_check sqlite3 $extralibs]} { |
| 137 | user-error "system sqlite3 too old (require >= 3.24.0)" |
| 138 | } |
| 139 | |
| 140 | # Success. Update symbols and return. |
| 141 | # |
| 142 | define USE_SYSTEM_SQLITE 1 |
| 143 |
| --- auto.def | |
| +++ auto.def | |
| @@ -126,17 +126,17 @@ | |
| 126 | # the code below will append -ldl to LIBS. |
| 127 | # |
| 128 | foreach extralibs {{} {-ldl}} { |
| 129 | |
| 130 | # Locate the system SQLite by searching for sqlite3_open(). Then check |
| 131 | # if sqlite3_create_window_function can be found as well. If we can find open() but |
| 132 | # not create_window_function(), then the system SQLite is too old to link against |
| 133 | # fossil. |
| 134 | # |
| 135 | if {[check-function-in-lib sqlite3_open sqlite3 $extralibs]} { |
| 136 | if {![check-function-in-lib sqlite3_create_window_function sqlite3 $extralibs]} { |
| 137 | user-error "system sqlite3 too old (require >= 3.25.0)" |
| 138 | } |
| 139 | |
| 140 | # Success. Update symbols and return. |
| 141 | # |
| 142 | define USE_SYSTEM_SQLITE 1 |
| 143 |
+4
-1
| --- skins/default/css.txt | ||
| +++ skins/default/css.txt | ||
| @@ -143,11 +143,14 @@ | ||
| 143 | 143 | overflow: auto; |
| 144 | 144 | border: 1px solid #ccc; |
| 145 | 145 | border-radius: 5px; |
| 146 | 146 | } |
| 147 | 147 | .content blockquote { |
| 148 | - padding: 0 15px; | |
| 148 | + background-color: rgba(65, 131, 196, 0.1); | |
| 149 | + border-left: 3px solid #254769; | |
| 150 | + padding: 0.1em; | |
| 151 | + padding-left: 1em; | |
| 149 | 152 | } |
| 150 | 153 | |
| 151 | 154 | table.report { |
| 152 | 155 | cursor: auto; |
| 153 | 156 | border-radius: 5px; |
| 154 | 157 |
| --- skins/default/css.txt | |
| +++ skins/default/css.txt | |
| @@ -143,11 +143,14 @@ | |
| 143 | overflow: auto; |
| 144 | border: 1px solid #ccc; |
| 145 | border-radius: 5px; |
| 146 | } |
| 147 | .content blockquote { |
| 148 | padding: 0 15px; |
| 149 | } |
| 150 | |
| 151 | table.report { |
| 152 | cursor: auto; |
| 153 | border-radius: 5px; |
| 154 |
| --- skins/default/css.txt | |
| +++ skins/default/css.txt | |
| @@ -143,11 +143,14 @@ | |
| 143 | overflow: auto; |
| 144 | border: 1px solid #ccc; |
| 145 | border-radius: 5px; |
| 146 | } |
| 147 | .content blockquote { |
| 148 | background-color: rgba(65, 131, 196, 0.1); |
| 149 | border-left: 3px solid #254769; |
| 150 | padding: 0.1em; |
| 151 | padding-left: 1em; |
| 152 | } |
| 153 | |
| 154 | table.report { |
| 155 | cursor: auto; |
| 156 | border-radius: 5px; |
| 157 |
+48
-28
| --- src/branch.c | ||
| +++ src/branch.c | ||
| @@ -268,10 +268,24 @@ | ||
| 268 | 268 | ** Usage: %fossil branch SUBCOMMAND ... ?OPTIONS? |
| 269 | 269 | ** |
| 270 | 270 | ** Run various subcommands to manage branches of the open repository or |
| 271 | 271 | ** of the repository identified by the -R or --repository option. |
| 272 | 272 | ** |
| 273 | +** fossil branch current | |
| 274 | +** | |
| 275 | +** Print the name of the branch for the current check-out | |
| 276 | +** | |
| 277 | +** fossil branch info BRANCH-NAME | |
| 278 | +** | |
| 279 | +** Print information about a branch | |
| 280 | +** | |
| 281 | +** fossil branch list|ls ?-a|--all|-c|--closed? | |
| 282 | +** | |
| 283 | +** List all branches. Use -a or --all to list all branches and | |
| 284 | +** -c or --closed to list all closed branches. The default is to | |
| 285 | +** show only open branches. | |
| 286 | +** | |
| 273 | 287 | ** fossil branch new BRANCH-NAME BASIS ?OPTIONS? |
| 274 | 288 | ** |
| 275 | 289 | ** Create a new branch BRANCH-NAME off of check-in BASIS. |
| 276 | 290 | ** Supported options for this subcommand include: |
| 277 | 291 | ** --private branch is private (i.e., remains local) |
| @@ -284,31 +298,50 @@ | ||
| 284 | 298 | ** year-month-day form, it may be truncated, the "T" may be |
| 285 | 299 | ** replaced by a space, and it may also name a timezone offset |
| 286 | 300 | ** from UTC as "-HH:MM" (westward) or "+HH:MM" (eastward). |
| 287 | 301 | ** Either no timezone suffix or "Z" means UTC. |
| 288 | 302 | ** |
| 289 | -** fossil branch list|ls ?-a|--all|-c|--closed? | |
| 290 | -** | |
| 291 | -** List all branches. Use -a or --all to list all branches and | |
| 292 | -** -c or --closed to list all closed branches. The default is to | |
| 293 | -** show only open branches. | |
| 294 | -** | |
| 295 | -** fossil branch info BRANCH-NAME | |
| 296 | -** | |
| 297 | -** Print information about a branch | |
| 298 | -** | |
| 299 | 303 | ** Options: |
| 300 | 304 | ** -R|--repository FILE Run commands on repository FILE |
| 305 | +** | |
| 306 | +** Summary: | |
| 307 | +** fossil branch current | |
| 308 | +** fossil branch info BRANCHNAME | |
| 309 | +** fossil branch [list|ls] | |
| 310 | +** fossil branch new | |
| 301 | 311 | */ |
| 302 | 312 | void branch_cmd(void){ |
| 303 | 313 | int n; |
| 304 | 314 | const char *zCmd = "list"; |
| 305 | 315 | db_find_and_open_repository(0, 0); |
| 306 | 316 | if( g.argc>=3 ) zCmd = g.argv[2]; |
| 307 | 317 | n = strlen(zCmd); |
| 308 | - if( strncmp(zCmd,"new",n)==0 ){ | |
| 309 | - branch_new(); | |
| 318 | + if( strncmp(zCmd,"current",n)==0 ){ | |
| 319 | + if( !g.localOpen ){ | |
| 320 | + fossil_fatal("not within an open checkout"); | |
| 321 | + }else{ | |
| 322 | + int vid = db_lget_int("checkout", 0); | |
| 323 | + char *zCurrent = db_text(0, "SELECT value FROM tagxref" | |
| 324 | + " WHERE rid=%d AND tagid=%d", vid, TAG_BRANCH); | |
| 325 | + fossil_print("%s\n", zCurrent); | |
| 326 | + fossil_free(zCurrent); | |
| 327 | + } | |
| 328 | + }else if( strncmp(zCmd,"info",n)==0 ){ | |
| 329 | + int i; | |
| 330 | + for(i=3; i<g.argc; i++){ | |
| 331 | + const char *zBrName = g.argv[i]; | |
| 332 | + int rid = branch_is_open(zBrName); | |
| 333 | + if( rid==0 ){ | |
| 334 | + fossil_print("%s: not an open branch\n", zBrName); | |
| 335 | + }else{ | |
| 336 | + const char *zUuid = db_text(0,"SELECT uuid FROM blob WHERE rid=%d",rid); | |
| 337 | + const char *zDate = db_text(0, | |
| 338 | + "SELECT datetime(mtime,toLocal()) FROM event" | |
| 339 | + " WHERE objid=%d", rid); | |
| 340 | + fossil_print("%s: open as of %s on %.16s\n", zBrName, zDate, zUuid); | |
| 341 | + } | |
| 342 | + } | |
| 310 | 343 | }else if( (strncmp(zCmd,"list",n)==0)||(strncmp(zCmd, "ls", n)==0) ){ |
| 311 | 344 | Stmt q; |
| 312 | 345 | int vid; |
| 313 | 346 | char *zCurrent = 0; |
| 314 | 347 | int brFlags = BRL_OPEN_ONLY; |
| @@ -325,28 +358,15 @@ | ||
| 325 | 358 | const char *zBr = db_column_text(&q, 0); |
| 326 | 359 | int isCur = zCurrent!=0 && fossil_strcmp(zCurrent,zBr)==0; |
| 327 | 360 | fossil_print("%s%s\n", (isCur ? "* " : " "), zBr); |
| 328 | 361 | } |
| 329 | 362 | db_finalize(&q); |
| 330 | - }else if( strncmp(zCmd,"info",n)==0 ){ | |
| 331 | - int i; | |
| 332 | - for(i=3; i<g.argc; i++){ | |
| 333 | - const char *zBrName = g.argv[i]; | |
| 334 | - int rid = branch_is_open(zBrName); | |
| 335 | - if( rid==0 ){ | |
| 336 | - fossil_print("%s: not an open branch\n", zBrName); | |
| 337 | - }else{ | |
| 338 | - const char *zUuid = db_text(0,"SELECT uuid FROM blob WHERE rid=%d",rid); | |
| 339 | - const char *zDate = db_text(0, | |
| 340 | - "SELECT datetime(mtime,toLocal()) FROM event" | |
| 341 | - " WHERE objid=%d", rid); | |
| 342 | - fossil_print("%s: open as of %s on %.16s\n", zBrName, zDate, zUuid); | |
| 343 | - } | |
| 344 | - } | |
| 363 | + }else if( strncmp(zCmd,"new",n)==0 ){ | |
| 364 | + branch_new(); | |
| 345 | 365 | }else{ |
| 346 | 366 | fossil_fatal("branch subcommand should be one of: " |
| 347 | - "info list ls new"); | |
| 367 | + "current info list ls new"); | |
| 348 | 368 | } |
| 349 | 369 | } |
| 350 | 370 | |
| 351 | 371 | static const char brlistQuery[] = |
| 352 | 372 | @ SELECT |
| 353 | 373 |
| --- src/branch.c | |
| +++ src/branch.c | |
| @@ -268,10 +268,24 @@ | |
| 268 | ** Usage: %fossil branch SUBCOMMAND ... ?OPTIONS? |
| 269 | ** |
| 270 | ** Run various subcommands to manage branches of the open repository or |
| 271 | ** of the repository identified by the -R or --repository option. |
| 272 | ** |
| 273 | ** fossil branch new BRANCH-NAME BASIS ?OPTIONS? |
| 274 | ** |
| 275 | ** Create a new branch BRANCH-NAME off of check-in BASIS. |
| 276 | ** Supported options for this subcommand include: |
| 277 | ** --private branch is private (i.e., remains local) |
| @@ -284,31 +298,50 @@ | |
| 284 | ** year-month-day form, it may be truncated, the "T" may be |
| 285 | ** replaced by a space, and it may also name a timezone offset |
| 286 | ** from UTC as "-HH:MM" (westward) or "+HH:MM" (eastward). |
| 287 | ** Either no timezone suffix or "Z" means UTC. |
| 288 | ** |
| 289 | ** fossil branch list|ls ?-a|--all|-c|--closed? |
| 290 | ** |
| 291 | ** List all branches. Use -a or --all to list all branches and |
| 292 | ** -c or --closed to list all closed branches. The default is to |
| 293 | ** show only open branches. |
| 294 | ** |
| 295 | ** fossil branch info BRANCH-NAME |
| 296 | ** |
| 297 | ** Print information about a branch |
| 298 | ** |
| 299 | ** Options: |
| 300 | ** -R|--repository FILE Run commands on repository FILE |
| 301 | */ |
| 302 | void branch_cmd(void){ |
| 303 | int n; |
| 304 | const char *zCmd = "list"; |
| 305 | db_find_and_open_repository(0, 0); |
| 306 | if( g.argc>=3 ) zCmd = g.argv[2]; |
| 307 | n = strlen(zCmd); |
| 308 | if( strncmp(zCmd,"new",n)==0 ){ |
| 309 | branch_new(); |
| 310 | }else if( (strncmp(zCmd,"list",n)==0)||(strncmp(zCmd, "ls", n)==0) ){ |
| 311 | Stmt q; |
| 312 | int vid; |
| 313 | char *zCurrent = 0; |
| 314 | int brFlags = BRL_OPEN_ONLY; |
| @@ -325,28 +358,15 @@ | |
| 325 | const char *zBr = db_column_text(&q, 0); |
| 326 | int isCur = zCurrent!=0 && fossil_strcmp(zCurrent,zBr)==0; |
| 327 | fossil_print("%s%s\n", (isCur ? "* " : " "), zBr); |
| 328 | } |
| 329 | db_finalize(&q); |
| 330 | }else if( strncmp(zCmd,"info",n)==0 ){ |
| 331 | int i; |
| 332 | for(i=3; i<g.argc; i++){ |
| 333 | const char *zBrName = g.argv[i]; |
| 334 | int rid = branch_is_open(zBrName); |
| 335 | if( rid==0 ){ |
| 336 | fossil_print("%s: not an open branch\n", zBrName); |
| 337 | }else{ |
| 338 | const char *zUuid = db_text(0,"SELECT uuid FROM blob WHERE rid=%d",rid); |
| 339 | const char *zDate = db_text(0, |
| 340 | "SELECT datetime(mtime,toLocal()) FROM event" |
| 341 | " WHERE objid=%d", rid); |
| 342 | fossil_print("%s: open as of %s on %.16s\n", zBrName, zDate, zUuid); |
| 343 | } |
| 344 | } |
| 345 | }else{ |
| 346 | fossil_fatal("branch subcommand should be one of: " |
| 347 | "info list ls new"); |
| 348 | } |
| 349 | } |
| 350 | |
| 351 | static const char brlistQuery[] = |
| 352 | @ SELECT |
| 353 |
| --- src/branch.c | |
| +++ src/branch.c | |
| @@ -268,10 +268,24 @@ | |
| 268 | ** Usage: %fossil branch SUBCOMMAND ... ?OPTIONS? |
| 269 | ** |
| 270 | ** Run various subcommands to manage branches of the open repository or |
| 271 | ** of the repository identified by the -R or --repository option. |
| 272 | ** |
| 273 | ** fossil branch current |
| 274 | ** |
| 275 | ** Print the name of the branch for the current check-out |
| 276 | ** |
| 277 | ** fossil branch info BRANCH-NAME |
| 278 | ** |
| 279 | ** Print information about a branch |
| 280 | ** |
| 281 | ** fossil branch list|ls ?-a|--all|-c|--closed? |
| 282 | ** |
| 283 | ** List all branches. Use -a or --all to list all branches and |
| 284 | ** -c or --closed to list all closed branches. The default is to |
| 285 | ** show only open branches. |
| 286 | ** |
| 287 | ** fossil branch new BRANCH-NAME BASIS ?OPTIONS? |
| 288 | ** |
| 289 | ** Create a new branch BRANCH-NAME off of check-in BASIS. |
| 290 | ** Supported options for this subcommand include: |
| 291 | ** --private branch is private (i.e., remains local) |
| @@ -284,31 +298,50 @@ | |
| 298 | ** year-month-day form, it may be truncated, the "T" may be |
| 299 | ** replaced by a space, and it may also name a timezone offset |
| 300 | ** from UTC as "-HH:MM" (westward) or "+HH:MM" (eastward). |
| 301 | ** Either no timezone suffix or "Z" means UTC. |
| 302 | ** |
| 303 | ** Options: |
| 304 | ** -R|--repository FILE Run commands on repository FILE |
| 305 | ** |
| 306 | ** Summary: |
| 307 | ** fossil branch current |
| 308 | ** fossil branch info BRANCHNAME |
| 309 | ** fossil branch [list|ls] |
| 310 | ** fossil branch new |
| 311 | */ |
| 312 | void branch_cmd(void){ |
| 313 | int n; |
| 314 | const char *zCmd = "list"; |
| 315 | db_find_and_open_repository(0, 0); |
| 316 | if( g.argc>=3 ) zCmd = g.argv[2]; |
| 317 | n = strlen(zCmd); |
| 318 | if( strncmp(zCmd,"current",n)==0 ){ |
| 319 | if( !g.localOpen ){ |
| 320 | fossil_fatal("not within an open checkout"); |
| 321 | }else{ |
| 322 | int vid = db_lget_int("checkout", 0); |
| 323 | char *zCurrent = db_text(0, "SELECT value FROM tagxref" |
| 324 | " WHERE rid=%d AND tagid=%d", vid, TAG_BRANCH); |
| 325 | fossil_print("%s\n", zCurrent); |
| 326 | fossil_free(zCurrent); |
| 327 | } |
| 328 | }else if( strncmp(zCmd,"info",n)==0 ){ |
| 329 | int i; |
| 330 | for(i=3; i<g.argc; i++){ |
| 331 | const char *zBrName = g.argv[i]; |
| 332 | int rid = branch_is_open(zBrName); |
| 333 | if( rid==0 ){ |
| 334 | fossil_print("%s: not an open branch\n", zBrName); |
| 335 | }else{ |
| 336 | const char *zUuid = db_text(0,"SELECT uuid FROM blob WHERE rid=%d",rid); |
| 337 | const char *zDate = db_text(0, |
| 338 | "SELECT datetime(mtime,toLocal()) FROM event" |
| 339 | " WHERE objid=%d", rid); |
| 340 | fossil_print("%s: open as of %s on %.16s\n", zBrName, zDate, zUuid); |
| 341 | } |
| 342 | } |
| 343 | }else if( (strncmp(zCmd,"list",n)==0)||(strncmp(zCmd, "ls", n)==0) ){ |
| 344 | Stmt q; |
| 345 | int vid; |
| 346 | char *zCurrent = 0; |
| 347 | int brFlags = BRL_OPEN_ONLY; |
| @@ -325,28 +358,15 @@ | |
| 358 | const char *zBr = db_column_text(&q, 0); |
| 359 | int isCur = zCurrent!=0 && fossil_strcmp(zCurrent,zBr)==0; |
| 360 | fossil_print("%s%s\n", (isCur ? "* " : " "), zBr); |
| 361 | } |
| 362 | db_finalize(&q); |
| 363 | }else if( strncmp(zCmd,"new",n)==0 ){ |
| 364 | branch_new(); |
| 365 | }else{ |
| 366 | fossil_fatal("branch subcommand should be one of: " |
| 367 | "current info list ls new"); |
| 368 | } |
| 369 | } |
| 370 | |
| 371 | static const char brlistQuery[] = |
| 372 | @ SELECT |
| 373 |
+2
-1
| --- src/json_branch.c | ||
| +++ src/json_branch.c | ||
| @@ -68,11 +68,11 @@ | ||
| 68 | 68 | cson_value * listV; |
| 69 | 69 | cson_array * list; |
| 70 | 70 | char const * range = NULL; |
| 71 | 71 | int branchListFlags = BRL_OPEN_ONLY; |
| 72 | 72 | char * sawConversionError = NULL; |
| 73 | - Stmt q; | |
| 73 | + Stmt q = empty_Stmt; | |
| 74 | 74 | if( !g.perm.Read ){ |
| 75 | 75 | json_set_err(FSL_JSON_E_DENIED, |
| 76 | 76 | "Requires 'o' permissions."); |
| 77 | 77 | return NULL; |
| 78 | 78 | } |
| @@ -143,10 +143,11 @@ | ||
| 143 | 143 | } |
| 144 | 144 | if( sawConversionError ){ |
| 145 | 145 | json_warn(FSL_JSON_W_COL_TO_JSON_FAILED,"%s",sawConversionError); |
| 146 | 146 | free(sawConversionError); |
| 147 | 147 | } |
| 148 | + db_finalize(&q); | |
| 148 | 149 | return payV; |
| 149 | 150 | } |
| 150 | 151 | |
| 151 | 152 | /* |
| 152 | 153 | ** Parameters for the create-branch operation. |
| 153 | 154 |
| --- src/json_branch.c | |
| +++ src/json_branch.c | |
| @@ -68,11 +68,11 @@ | |
| 68 | cson_value * listV; |
| 69 | cson_array * list; |
| 70 | char const * range = NULL; |
| 71 | int branchListFlags = BRL_OPEN_ONLY; |
| 72 | char * sawConversionError = NULL; |
| 73 | Stmt q; |
| 74 | if( !g.perm.Read ){ |
| 75 | json_set_err(FSL_JSON_E_DENIED, |
| 76 | "Requires 'o' permissions."); |
| 77 | return NULL; |
| 78 | } |
| @@ -143,10 +143,11 @@ | |
| 143 | } |
| 144 | if( sawConversionError ){ |
| 145 | json_warn(FSL_JSON_W_COL_TO_JSON_FAILED,"%s",sawConversionError); |
| 146 | free(sawConversionError); |
| 147 | } |
| 148 | return payV; |
| 149 | } |
| 150 | |
| 151 | /* |
| 152 | ** Parameters for the create-branch operation. |
| 153 |
| --- src/json_branch.c | |
| +++ src/json_branch.c | |
| @@ -68,11 +68,11 @@ | |
| 68 | cson_value * listV; |
| 69 | cson_array * list; |
| 70 | char const * range = NULL; |
| 71 | int branchListFlags = BRL_OPEN_ONLY; |
| 72 | char * sawConversionError = NULL; |
| 73 | Stmt q = empty_Stmt; |
| 74 | if( !g.perm.Read ){ |
| 75 | json_set_err(FSL_JSON_E_DENIED, |
| 76 | "Requires 'o' permissions."); |
| 77 | return NULL; |
| 78 | } |
| @@ -143,10 +143,11 @@ | |
| 143 | } |
| 144 | if( sawConversionError ){ |
| 145 | json_warn(FSL_JSON_W_COL_TO_JSON_FAILED,"%s",sawConversionError); |
| 146 | free(sawConversionError); |
| 147 | } |
| 148 | db_finalize(&q); |
| 149 | return payV; |
| 150 | } |
| 151 | |
| 152 | /* |
| 153 | ** Parameters for the create-branch operation. |
| 154 |
+1
-1
| --- src/main.mk | ||
| +++ src/main.mk | ||
| @@ -686,11 +686,11 @@ | ||
| 686 | 686 | # |
| 687 | 687 | $(SRCDIR)/../manifest: |
| 688 | 688 | # noop |
| 689 | 689 | |
| 690 | 690 | clean: |
| 691 | - rm -rf $(OBJDIR)/* $(APPNAME) | |
| 691 | + -rm -rf $(OBJDIR)/* $(APPNAME) | |
| 692 | 692 | |
| 693 | 693 | |
| 694 | 694 | $(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex |
| 695 | 695 | $(OBJDIR)/mkindex $(TRANS_SRC) >$@ |
| 696 | 696 | |
| 697 | 697 |
| --- src/main.mk | |
| +++ src/main.mk | |
| @@ -686,11 +686,11 @@ | |
| 686 | # |
| 687 | $(SRCDIR)/../manifest: |
| 688 | # noop |
| 689 | |
| 690 | clean: |
| 691 | rm -rf $(OBJDIR)/* $(APPNAME) |
| 692 | |
| 693 | |
| 694 | $(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex |
| 695 | $(OBJDIR)/mkindex $(TRANS_SRC) >$@ |
| 696 | |
| 697 |
| --- src/main.mk | |
| +++ src/main.mk | |
| @@ -686,11 +686,11 @@ | |
| 686 | # |
| 687 | $(SRCDIR)/../manifest: |
| 688 | # noop |
| 689 | |
| 690 | clean: |
| 691 | -rm -rf $(OBJDIR)/* $(APPNAME) |
| 692 | |
| 693 | |
| 694 | $(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex |
| 695 | $(OBJDIR)/mkindex $(TRANS_SRC) >$@ |
| 696 | |
| 697 |
+34
-34
| --- src/makemake.tcl | ||
| +++ src/makemake.tcl | ||
| @@ -448,11 +448,11 @@ | ||
| 448 | 448 | # |
| 449 | 449 | $(SRCDIR)/../manifest: |
| 450 | 450 | # noop |
| 451 | 451 | |
| 452 | 452 | clean: |
| 453 | - rm -rf $(OBJDIR)/* $(APPNAME) | |
| 453 | + -rm -rf $(OBJDIR)/* $(APPNAME) | |
| 454 | 454 | |
| 455 | 455 | } |
| 456 | 456 | |
| 457 | 457 | set mhargs {} |
| 458 | 458 | foreach s [lsort $src] { |
| @@ -1985,40 +1985,40 @@ | ||
| 1985 | 1985 | |
| 1986 | 1986 | "$(OX)\builtin_data.h": "$(OBJDIR)\mkbuiltin$E" "$(OX)\builtin_data.reslist" |
| 1987 | 1987 | "$(OBJDIR)\mkbuiltin$E" --prefix "$(SRCDIR)/" --reslist "$(OX)\builtin_data.reslist" > $@ |
| 1988 | 1988 | |
| 1989 | 1989 | cleanx: |
| 1990 | - del "$(OX)\*.obj" 2>NUL | |
| 1991 | - del "$(OBJDIR)\*.obj" 2>NUL | |
| 1992 | - del "$(OX)\*_.c" 2>NUL | |
| 1993 | - del "$(OX)\*.h" 2>NUL | |
| 1994 | - del "$(OX)\*.ilk" 2>NUL | |
| 1995 | - del "$(OX)\*.map" 2>NUL | |
| 1996 | - del "$(OX)\*.res" 2>NUL | |
| 1997 | - del "$(OX)\*.reslist" 2>NUL | |
| 1998 | - del "$(OX)\headers" 2>NUL | |
| 1999 | - del "$(OX)\linkopts" 2>NUL | |
| 2000 | - del "$(OX)\vc*.pdb" 2>NUL | |
| 1990 | + -del "$(OX)\*.obj" 2>NUL | |
| 1991 | + -del "$(OBJDIR)\*.obj" 2>NUL | |
| 1992 | + -del "$(OX)\*_.c" 2>NUL | |
| 1993 | + -del "$(OX)\*.h" 2>NUL | |
| 1994 | + -del "$(OX)\*.ilk" 2>NUL | |
| 1995 | + -del "$(OX)\*.map" 2>NUL | |
| 1996 | + -del "$(OX)\*.res" 2>NUL | |
| 1997 | + -del "$(OX)\*.reslist" 2>NUL | |
| 1998 | + -del "$(OX)\headers" 2>NUL | |
| 1999 | + -del "$(OX)\linkopts" 2>NUL | |
| 2000 | + -del "$(OX)\vc*.pdb" 2>NUL | |
| 2001 | 2001 | |
| 2002 | 2002 | clean: cleanx |
| 2003 | - del "$(APPNAME)" 2>NUL | |
| 2004 | - del "$(PDBNAME)" 2>NUL | |
| 2005 | - del "$(APPMANIFEST)" 2>NUL | |
| 2006 | - del "$(OBJDIR)\translate$E" 2>NUL | |
| 2007 | - del "$(OBJDIR)\translate$P" 2>NUL | |
| 2008 | - del "$(OBJDIR)\mkindex$E" 2>NUL | |
| 2009 | - del "$(OBJDIR)\mkindex$P" 2>NUL | |
| 2010 | - del "$(OBJDIR)\makeheaders$E" 2>NUL | |
| 2011 | - del "$(OBJDIR)\makeheaders$P" 2>NUL | |
| 2012 | - del "$(OBJDIR)\mkversion$E" 2>NUL | |
| 2013 | - del "$(OBJDIR)\mkversion$P" 2>NUL | |
| 2014 | - del "$(OBJDIR)\mkcss$E" 2>NUL | |
| 2015 | - del "$(OBJDIR)\mkcss$P" 2>NUL | |
| 2016 | - del "$(OBJDIR)\codecheck1$E" 2>NUL | |
| 2017 | - del "$(OBJDIR)\codecheck1$P" 2>NUL | |
| 2018 | - del "$(OBJDIR)\mkbuiltin$E" 2>NUL | |
| 2019 | - del "$(OBJDIR)\mkbuiltin$P" 2>NUL | |
| 2003 | + -del "$(APPNAME)" 2>NUL | |
| 2004 | + -del "$(PDBNAME)" 2>NUL | |
| 2005 | + -del "$(APPMANIFEST)" 2>NUL | |
| 2006 | + -del "$(OBJDIR)\translate$E" 2>NUL | |
| 2007 | + -del "$(OBJDIR)\translate$P" 2>NUL | |
| 2008 | + -del "$(OBJDIR)\mkindex$E" 2>NUL | |
| 2009 | + -del "$(OBJDIR)\mkindex$P" 2>NUL | |
| 2010 | + -del "$(OBJDIR)\makeheaders$E" 2>NUL | |
| 2011 | + -del "$(OBJDIR)\makeheaders$P" 2>NUL | |
| 2012 | + -del "$(OBJDIR)\mkversion$E" 2>NUL | |
| 2013 | + -del "$(OBJDIR)\mkversion$P" 2>NUL | |
| 2014 | + -del "$(OBJDIR)\mkcss$E" 2>NUL | |
| 2015 | + -del "$(OBJDIR)\mkcss$P" 2>NUL | |
| 2016 | + -del "$(OBJDIR)\codecheck1$E" 2>NUL | |
| 2017 | + -del "$(OBJDIR)\codecheck1$P" 2>NUL | |
| 2018 | + -del "$(OBJDIR)\mkbuiltin$E" 2>NUL | |
| 2019 | + -del "$(OBJDIR)\mkbuiltin$P" 2>NUL | |
| 2020 | 2020 | |
| 2021 | 2021 | realclean: clean |
| 2022 | 2022 | |
| 2023 | 2023 | "$(OBJDIR)\json$O" : "$(SRCDIR)\json_detail.h" |
| 2024 | 2024 | "$(OBJDIR)\json_artifact$O" : "$(SRCDIR)\json_detail.h" |
| @@ -2275,14 +2275,14 @@ | ||
| 2275 | 2275 | |
| 2276 | 2276 | # cleanup |
| 2277 | 2277 | |
| 2278 | 2278 | .PHONY: clean |
| 2279 | 2279 | clean: |
| 2280 | - del /F $(TRANSLATEDOBJ) $(SQLITEOBJ) $(THOBJ) $(ZLIBOBJ) $(UTILS_OBJ) version.obj | |
| 2281 | - del /F $(TRANSLATEDSRC) | |
| 2282 | - del /F *.h headers | |
| 2283 | - del /F $(RESOURCE) | |
| 2280 | + -del /F $(TRANSLATEDOBJ) $(SQLITEOBJ) $(THOBJ) $(ZLIBOBJ) $(UTILS_OBJ) version.obj | |
| 2281 | + -del /F $(TRANSLATEDSRC) | |
| 2282 | + -del /F *.h headers | |
| 2283 | + -del /F $(RESOURCE) | |
| 2284 | 2284 | |
| 2285 | 2285 | .PHONY: clobber |
| 2286 | 2286 | clobber: clean |
| 2287 | - del /F *.exe | |
| 2287 | + -del /F *.exe | |
| 2288 | 2288 | }] |
| 2289 | 2289 |
| --- src/makemake.tcl | |
| +++ src/makemake.tcl | |
| @@ -448,11 +448,11 @@ | |
| 448 | # |
| 449 | $(SRCDIR)/../manifest: |
| 450 | # noop |
| 451 | |
| 452 | clean: |
| 453 | rm -rf $(OBJDIR)/* $(APPNAME) |
| 454 | |
| 455 | } |
| 456 | |
| 457 | set mhargs {} |
| 458 | foreach s [lsort $src] { |
| @@ -1985,40 +1985,40 @@ | |
| 1985 | |
| 1986 | "$(OX)\builtin_data.h": "$(OBJDIR)\mkbuiltin$E" "$(OX)\builtin_data.reslist" |
| 1987 | "$(OBJDIR)\mkbuiltin$E" --prefix "$(SRCDIR)/" --reslist "$(OX)\builtin_data.reslist" > $@ |
| 1988 | |
| 1989 | cleanx: |
| 1990 | del "$(OX)\*.obj" 2>NUL |
| 1991 | del "$(OBJDIR)\*.obj" 2>NUL |
| 1992 | del "$(OX)\*_.c" 2>NUL |
| 1993 | del "$(OX)\*.h" 2>NUL |
| 1994 | del "$(OX)\*.ilk" 2>NUL |
| 1995 | del "$(OX)\*.map" 2>NUL |
| 1996 | del "$(OX)\*.res" 2>NUL |
| 1997 | del "$(OX)\*.reslist" 2>NUL |
| 1998 | del "$(OX)\headers" 2>NUL |
| 1999 | del "$(OX)\linkopts" 2>NUL |
| 2000 | del "$(OX)\vc*.pdb" 2>NUL |
| 2001 | |
| 2002 | clean: cleanx |
| 2003 | del "$(APPNAME)" 2>NUL |
| 2004 | del "$(PDBNAME)" 2>NUL |
| 2005 | del "$(APPMANIFEST)" 2>NUL |
| 2006 | del "$(OBJDIR)\translate$E" 2>NUL |
| 2007 | del "$(OBJDIR)\translate$P" 2>NUL |
| 2008 | del "$(OBJDIR)\mkindex$E" 2>NUL |
| 2009 | del "$(OBJDIR)\mkindex$P" 2>NUL |
| 2010 | del "$(OBJDIR)\makeheaders$E" 2>NUL |
| 2011 | del "$(OBJDIR)\makeheaders$P" 2>NUL |
| 2012 | del "$(OBJDIR)\mkversion$E" 2>NUL |
| 2013 | del "$(OBJDIR)\mkversion$P" 2>NUL |
| 2014 | del "$(OBJDIR)\mkcss$E" 2>NUL |
| 2015 | del "$(OBJDIR)\mkcss$P" 2>NUL |
| 2016 | del "$(OBJDIR)\codecheck1$E" 2>NUL |
| 2017 | del "$(OBJDIR)\codecheck1$P" 2>NUL |
| 2018 | del "$(OBJDIR)\mkbuiltin$E" 2>NUL |
| 2019 | del "$(OBJDIR)\mkbuiltin$P" 2>NUL |
| 2020 | |
| 2021 | realclean: clean |
| 2022 | |
| 2023 | "$(OBJDIR)\json$O" : "$(SRCDIR)\json_detail.h" |
| 2024 | "$(OBJDIR)\json_artifact$O" : "$(SRCDIR)\json_detail.h" |
| @@ -2275,14 +2275,14 @@ | |
| 2275 | |
| 2276 | # cleanup |
| 2277 | |
| 2278 | .PHONY: clean |
| 2279 | clean: |
| 2280 | del /F $(TRANSLATEDOBJ) $(SQLITEOBJ) $(THOBJ) $(ZLIBOBJ) $(UTILS_OBJ) version.obj |
| 2281 | del /F $(TRANSLATEDSRC) |
| 2282 | del /F *.h headers |
| 2283 | del /F $(RESOURCE) |
| 2284 | |
| 2285 | .PHONY: clobber |
| 2286 | clobber: clean |
| 2287 | del /F *.exe |
| 2288 | }] |
| 2289 |
| --- src/makemake.tcl | |
| +++ src/makemake.tcl | |
| @@ -448,11 +448,11 @@ | |
| 448 | # |
| 449 | $(SRCDIR)/../manifest: |
| 450 | # noop |
| 451 | |
| 452 | clean: |
| 453 | -rm -rf $(OBJDIR)/* $(APPNAME) |
| 454 | |
| 455 | } |
| 456 | |
| 457 | set mhargs {} |
| 458 | foreach s [lsort $src] { |
| @@ -1985,40 +1985,40 @@ | |
| 1985 | |
| 1986 | "$(OX)\builtin_data.h": "$(OBJDIR)\mkbuiltin$E" "$(OX)\builtin_data.reslist" |
| 1987 | "$(OBJDIR)\mkbuiltin$E" --prefix "$(SRCDIR)/" --reslist "$(OX)\builtin_data.reslist" > $@ |
| 1988 | |
| 1989 | cleanx: |
| 1990 | -del "$(OX)\*.obj" 2>NUL |
| 1991 | -del "$(OBJDIR)\*.obj" 2>NUL |
| 1992 | -del "$(OX)\*_.c" 2>NUL |
| 1993 | -del "$(OX)\*.h" 2>NUL |
| 1994 | -del "$(OX)\*.ilk" 2>NUL |
| 1995 | -del "$(OX)\*.map" 2>NUL |
| 1996 | -del "$(OX)\*.res" 2>NUL |
| 1997 | -del "$(OX)\*.reslist" 2>NUL |
| 1998 | -del "$(OX)\headers" 2>NUL |
| 1999 | -del "$(OX)\linkopts" 2>NUL |
| 2000 | -del "$(OX)\vc*.pdb" 2>NUL |
| 2001 | |
| 2002 | clean: cleanx |
| 2003 | -del "$(APPNAME)" 2>NUL |
| 2004 | -del "$(PDBNAME)" 2>NUL |
| 2005 | -del "$(APPMANIFEST)" 2>NUL |
| 2006 | -del "$(OBJDIR)\translate$E" 2>NUL |
| 2007 | -del "$(OBJDIR)\translate$P" 2>NUL |
| 2008 | -del "$(OBJDIR)\mkindex$E" 2>NUL |
| 2009 | -del "$(OBJDIR)\mkindex$P" 2>NUL |
| 2010 | -del "$(OBJDIR)\makeheaders$E" 2>NUL |
| 2011 | -del "$(OBJDIR)\makeheaders$P" 2>NUL |
| 2012 | -del "$(OBJDIR)\mkversion$E" 2>NUL |
| 2013 | -del "$(OBJDIR)\mkversion$P" 2>NUL |
| 2014 | -del "$(OBJDIR)\mkcss$E" 2>NUL |
| 2015 | -del "$(OBJDIR)\mkcss$P" 2>NUL |
| 2016 | -del "$(OBJDIR)\codecheck1$E" 2>NUL |
| 2017 | -del "$(OBJDIR)\codecheck1$P" 2>NUL |
| 2018 | -del "$(OBJDIR)\mkbuiltin$E" 2>NUL |
| 2019 | -del "$(OBJDIR)\mkbuiltin$P" 2>NUL |
| 2020 | |
| 2021 | realclean: clean |
| 2022 | |
| 2023 | "$(OBJDIR)\json$O" : "$(SRCDIR)\json_detail.h" |
| 2024 | "$(OBJDIR)\json_artifact$O" : "$(SRCDIR)\json_detail.h" |
| @@ -2275,14 +2275,14 @@ | |
| 2275 | |
| 2276 | # cleanup |
| 2277 | |
| 2278 | .PHONY: clean |
| 2279 | clean: |
| 2280 | -del /F $(TRANSLATEDOBJ) $(SQLITEOBJ) $(THOBJ) $(ZLIBOBJ) $(UTILS_OBJ) version.obj |
| 2281 | -del /F $(TRANSLATEDSRC) |
| 2282 | -del /F *.h headers |
| 2283 | -del /F $(RESOURCE) |
| 2284 | |
| 2285 | .PHONY: clobber |
| 2286 | clobber: clean |
| 2287 | -del /F *.exe |
| 2288 | }] |
| 2289 |
+34
-34
| --- src/makemake.tcl | ||
| +++ src/makemake.tcl | ||
| @@ -448,11 +448,11 @@ | ||
| 448 | 448 | # |
| 449 | 449 | $(SRCDIR)/../manifest: |
| 450 | 450 | # noop |
| 451 | 451 | |
| 452 | 452 | clean: |
| 453 | - rm -rf $(OBJDIR)/* $(APPNAME) | |
| 453 | + -rm -rf $(OBJDIR)/* $(APPNAME) | |
| 454 | 454 | |
| 455 | 455 | } |
| 456 | 456 | |
| 457 | 457 | set mhargs {} |
| 458 | 458 | foreach s [lsort $src] { |
| @@ -1985,40 +1985,40 @@ | ||
| 1985 | 1985 | |
| 1986 | 1986 | "$(OX)\builtin_data.h": "$(OBJDIR)\mkbuiltin$E" "$(OX)\builtin_data.reslist" |
| 1987 | 1987 | "$(OBJDIR)\mkbuiltin$E" --prefix "$(SRCDIR)/" --reslist "$(OX)\builtin_data.reslist" > $@ |
| 1988 | 1988 | |
| 1989 | 1989 | cleanx: |
| 1990 | - del "$(OX)\*.obj" 2>NUL | |
| 1991 | - del "$(OBJDIR)\*.obj" 2>NUL | |
| 1992 | - del "$(OX)\*_.c" 2>NUL | |
| 1993 | - del "$(OX)\*.h" 2>NUL | |
| 1994 | - del "$(OX)\*.ilk" 2>NUL | |
| 1995 | - del "$(OX)\*.map" 2>NUL | |
| 1996 | - del "$(OX)\*.res" 2>NUL | |
| 1997 | - del "$(OX)\*.reslist" 2>NUL | |
| 1998 | - del "$(OX)\headers" 2>NUL | |
| 1999 | - del "$(OX)\linkopts" 2>NUL | |
| 2000 | - del "$(OX)\vc*.pdb" 2>NUL | |
| 1990 | + -del "$(OX)\*.obj" 2>NUL | |
| 1991 | + -del "$(OBJDIR)\*.obj" 2>NUL | |
| 1992 | + -del "$(OX)\*_.c" 2>NUL | |
| 1993 | + -del "$(OX)\*.h" 2>NUL | |
| 1994 | + -del "$(OX)\*.ilk" 2>NUL | |
| 1995 | + -del "$(OX)\*.map" 2>NUL | |
| 1996 | + -del "$(OX)\*.res" 2>NUL | |
| 1997 | + -del "$(OX)\*.reslist" 2>NUL | |
| 1998 | + -del "$(OX)\headers" 2>NUL | |
| 1999 | + -del "$(OX)\linkopts" 2>NUL | |
| 2000 | + -del "$(OX)\vc*.pdb" 2>NUL | |
| 2001 | 2001 | |
| 2002 | 2002 | clean: cleanx |
| 2003 | - del "$(APPNAME)" 2>NUL | |
| 2004 | - del "$(PDBNAME)" 2>NUL | |
| 2005 | - del "$(APPMANIFEST)" 2>NUL | |
| 2006 | - del "$(OBJDIR)\translate$E" 2>NUL | |
| 2007 | - del "$(OBJDIR)\translate$P" 2>NUL | |
| 2008 | - del "$(OBJDIR)\mkindex$E" 2>NUL | |
| 2009 | - del "$(OBJDIR)\mkindex$P" 2>NUL | |
| 2010 | - del "$(OBJDIR)\makeheaders$E" 2>NUL | |
| 2011 | - del "$(OBJDIR)\makeheaders$P" 2>NUL | |
| 2012 | - del "$(OBJDIR)\mkversion$E" 2>NUL | |
| 2013 | - del "$(OBJDIR)\mkversion$P" 2>NUL | |
| 2014 | - del "$(OBJDIR)\mkcss$E" 2>NUL | |
| 2015 | - del "$(OBJDIR)\mkcss$P" 2>NUL | |
| 2016 | - del "$(OBJDIR)\codecheck1$E" 2>NUL | |
| 2017 | - del "$(OBJDIR)\codecheck1$P" 2>NUL | |
| 2018 | - del "$(OBJDIR)\mkbuiltin$E" 2>NUL | |
| 2019 | - del "$(OBJDIR)\mkbuiltin$P" 2>NUL | |
| 2003 | + -del "$(APPNAME)" 2>NUL | |
| 2004 | + -del "$(PDBNAME)" 2>NUL | |
| 2005 | + -del "$(APPMANIFEST)" 2>NUL | |
| 2006 | + -del "$(OBJDIR)\translate$E" 2>NUL | |
| 2007 | + -del "$(OBJDIR)\translate$P" 2>NUL | |
| 2008 | + -del "$(OBJDIR)\mkindex$E" 2>NUL | |
| 2009 | + -del "$(OBJDIR)\mkindex$P" 2>NUL | |
| 2010 | + -del "$(OBJDIR)\makeheaders$E" 2>NUL | |
| 2011 | + -del "$(OBJDIR)\makeheaders$P" 2>NUL | |
| 2012 | + -del "$(OBJDIR)\mkversion$E" 2>NUL | |
| 2013 | + -del "$(OBJDIR)\mkversion$P" 2>NUL | |
| 2014 | + -del "$(OBJDIR)\mkcss$E" 2>NUL | |
| 2015 | + -del "$(OBJDIR)\mkcss$P" 2>NUL | |
| 2016 | + -del "$(OBJDIR)\codecheck1$E" 2>NUL | |
| 2017 | + -del "$(OBJDIR)\codecheck1$P" 2>NUL | |
| 2018 | + -del "$(OBJDIR)\mkbuiltin$E" 2>NUL | |
| 2019 | + -del "$(OBJDIR)\mkbuiltin$P" 2>NUL | |
| 2020 | 2020 | |
| 2021 | 2021 | realclean: clean |
| 2022 | 2022 | |
| 2023 | 2023 | "$(OBJDIR)\json$O" : "$(SRCDIR)\json_detail.h" |
| 2024 | 2024 | "$(OBJDIR)\json_artifact$O" : "$(SRCDIR)\json_detail.h" |
| @@ -2275,14 +2275,14 @@ | ||
| 2275 | 2275 | |
| 2276 | 2276 | # cleanup |
| 2277 | 2277 | |
| 2278 | 2278 | .PHONY: clean |
| 2279 | 2279 | clean: |
| 2280 | - del /F $(TRANSLATEDOBJ) $(SQLITEOBJ) $(THOBJ) $(ZLIBOBJ) $(UTILS_OBJ) version.obj | |
| 2281 | - del /F $(TRANSLATEDSRC) | |
| 2282 | - del /F *.h headers | |
| 2283 | - del /F $(RESOURCE) | |
| 2280 | + -del /F $(TRANSLATEDOBJ) $(SQLITEOBJ) $(THOBJ) $(ZLIBOBJ) $(UTILS_OBJ) version.obj | |
| 2281 | + -del /F $(TRANSLATEDSRC) | |
| 2282 | + -del /F *.h headers | |
| 2283 | + -del /F $(RESOURCE) | |
| 2284 | 2284 | |
| 2285 | 2285 | .PHONY: clobber |
| 2286 | 2286 | clobber: clean |
| 2287 | - del /F *.exe | |
| 2287 | + -del /F *.exe | |
| 2288 | 2288 | }] |
| 2289 | 2289 |
| --- src/makemake.tcl | |
| +++ src/makemake.tcl | |
| @@ -448,11 +448,11 @@ | |
| 448 | # |
| 449 | $(SRCDIR)/../manifest: |
| 450 | # noop |
| 451 | |
| 452 | clean: |
| 453 | rm -rf $(OBJDIR)/* $(APPNAME) |
| 454 | |
| 455 | } |
| 456 | |
| 457 | set mhargs {} |
| 458 | foreach s [lsort $src] { |
| @@ -1985,40 +1985,40 @@ | |
| 1985 | |
| 1986 | "$(OX)\builtin_data.h": "$(OBJDIR)\mkbuiltin$E" "$(OX)\builtin_data.reslist" |
| 1987 | "$(OBJDIR)\mkbuiltin$E" --prefix "$(SRCDIR)/" --reslist "$(OX)\builtin_data.reslist" > $@ |
| 1988 | |
| 1989 | cleanx: |
| 1990 | del "$(OX)\*.obj" 2>NUL |
| 1991 | del "$(OBJDIR)\*.obj" 2>NUL |
| 1992 | del "$(OX)\*_.c" 2>NUL |
| 1993 | del "$(OX)\*.h" 2>NUL |
| 1994 | del "$(OX)\*.ilk" 2>NUL |
| 1995 | del "$(OX)\*.map" 2>NUL |
| 1996 | del "$(OX)\*.res" 2>NUL |
| 1997 | del "$(OX)\*.reslist" 2>NUL |
| 1998 | del "$(OX)\headers" 2>NUL |
| 1999 | del "$(OX)\linkopts" 2>NUL |
| 2000 | del "$(OX)\vc*.pdb" 2>NUL |
| 2001 | |
| 2002 | clean: cleanx |
| 2003 | del "$(APPNAME)" 2>NUL |
| 2004 | del "$(PDBNAME)" 2>NUL |
| 2005 | del "$(APPMANIFEST)" 2>NUL |
| 2006 | del "$(OBJDIR)\translate$E" 2>NUL |
| 2007 | del "$(OBJDIR)\translate$P" 2>NUL |
| 2008 | del "$(OBJDIR)\mkindex$E" 2>NUL |
| 2009 | del "$(OBJDIR)\mkindex$P" 2>NUL |
| 2010 | del "$(OBJDIR)\makeheaders$E" 2>NUL |
| 2011 | del "$(OBJDIR)\makeheaders$P" 2>NUL |
| 2012 | del "$(OBJDIR)\mkversion$E" 2>NUL |
| 2013 | del "$(OBJDIR)\mkversion$P" 2>NUL |
| 2014 | del "$(OBJDIR)\mkcss$E" 2>NUL |
| 2015 | del "$(OBJDIR)\mkcss$P" 2>NUL |
| 2016 | del "$(OBJDIR)\codecheck1$E" 2>NUL |
| 2017 | del "$(OBJDIR)\codecheck1$P" 2>NUL |
| 2018 | del "$(OBJDIR)\mkbuiltin$E" 2>NUL |
| 2019 | del "$(OBJDIR)\mkbuiltin$P" 2>NUL |
| 2020 | |
| 2021 | realclean: clean |
| 2022 | |
| 2023 | "$(OBJDIR)\json$O" : "$(SRCDIR)\json_detail.h" |
| 2024 | "$(OBJDIR)\json_artifact$O" : "$(SRCDIR)\json_detail.h" |
| @@ -2275,14 +2275,14 @@ | |
| 2275 | |
| 2276 | # cleanup |
| 2277 | |
| 2278 | .PHONY: clean |
| 2279 | clean: |
| 2280 | del /F $(TRANSLATEDOBJ) $(SQLITEOBJ) $(THOBJ) $(ZLIBOBJ) $(UTILS_OBJ) version.obj |
| 2281 | del /F $(TRANSLATEDSRC) |
| 2282 | del /F *.h headers |
| 2283 | del /F $(RESOURCE) |
| 2284 | |
| 2285 | .PHONY: clobber |
| 2286 | clobber: clean |
| 2287 | del /F *.exe |
| 2288 | }] |
| 2289 |
| --- src/makemake.tcl | |
| +++ src/makemake.tcl | |
| @@ -448,11 +448,11 @@ | |
| 448 | # |
| 449 | $(SRCDIR)/../manifest: |
| 450 | # noop |
| 451 | |
| 452 | clean: |
| 453 | -rm -rf $(OBJDIR)/* $(APPNAME) |
| 454 | |
| 455 | } |
| 456 | |
| 457 | set mhargs {} |
| 458 | foreach s [lsort $src] { |
| @@ -1985,40 +1985,40 @@ | |
| 1985 | |
| 1986 | "$(OX)\builtin_data.h": "$(OBJDIR)\mkbuiltin$E" "$(OX)\builtin_data.reslist" |
| 1987 | "$(OBJDIR)\mkbuiltin$E" --prefix "$(SRCDIR)/" --reslist "$(OX)\builtin_data.reslist" > $@ |
| 1988 | |
| 1989 | cleanx: |
| 1990 | -del "$(OX)\*.obj" 2>NUL |
| 1991 | -del "$(OBJDIR)\*.obj" 2>NUL |
| 1992 | -del "$(OX)\*_.c" 2>NUL |
| 1993 | -del "$(OX)\*.h" 2>NUL |
| 1994 | -del "$(OX)\*.ilk" 2>NUL |
| 1995 | -del "$(OX)\*.map" 2>NUL |
| 1996 | -del "$(OX)\*.res" 2>NUL |
| 1997 | -del "$(OX)\*.reslist" 2>NUL |
| 1998 | -del "$(OX)\headers" 2>NUL |
| 1999 | -del "$(OX)\linkopts" 2>NUL |
| 2000 | -del "$(OX)\vc*.pdb" 2>NUL |
| 2001 | |
| 2002 | clean: cleanx |
| 2003 | -del "$(APPNAME)" 2>NUL |
| 2004 | -del "$(PDBNAME)" 2>NUL |
| 2005 | -del "$(APPMANIFEST)" 2>NUL |
| 2006 | -del "$(OBJDIR)\translate$E" 2>NUL |
| 2007 | -del "$(OBJDIR)\translate$P" 2>NUL |
| 2008 | -del "$(OBJDIR)\mkindex$E" 2>NUL |
| 2009 | -del "$(OBJDIR)\mkindex$P" 2>NUL |
| 2010 | -del "$(OBJDIR)\makeheaders$E" 2>NUL |
| 2011 | -del "$(OBJDIR)\makeheaders$P" 2>NUL |
| 2012 | -del "$(OBJDIR)\mkversion$E" 2>NUL |
| 2013 | -del "$(OBJDIR)\mkversion$P" 2>NUL |
| 2014 | -del "$(OBJDIR)\mkcss$E" 2>NUL |
| 2015 | -del "$(OBJDIR)\mkcss$P" 2>NUL |
| 2016 | -del "$(OBJDIR)\codecheck1$E" 2>NUL |
| 2017 | -del "$(OBJDIR)\codecheck1$P" 2>NUL |
| 2018 | -del "$(OBJDIR)\mkbuiltin$E" 2>NUL |
| 2019 | -del "$(OBJDIR)\mkbuiltin$P" 2>NUL |
| 2020 | |
| 2021 | realclean: clean |
| 2022 | |
| 2023 | "$(OBJDIR)\json$O" : "$(SRCDIR)\json_detail.h" |
| 2024 | "$(OBJDIR)\json_artifact$O" : "$(SRCDIR)\json_detail.h" |
| @@ -2275,14 +2275,14 @@ | |
| 2275 | |
| 2276 | # cleanup |
| 2277 | |
| 2278 | .PHONY: clean |
| 2279 | clean: |
| 2280 | -del /F $(TRANSLATEDOBJ) $(SQLITEOBJ) $(THOBJ) $(ZLIBOBJ) $(UTILS_OBJ) version.obj |
| 2281 | -del /F $(TRANSLATEDSRC) |
| 2282 | -del /F *.h headers |
| 2283 | -del /F $(RESOURCE) |
| 2284 | |
| 2285 | .PHONY: clobber |
| 2286 | clobber: clean |
| 2287 | -del /F *.exe |
| 2288 | }] |
| 2289 |
+67
-40
| --- src/sqlite3.c | ||
| +++ src/sqlite3.c | ||
| @@ -1156,11 +1156,11 @@ | ||
| 1156 | 1156 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 1157 | 1157 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 1158 | 1158 | */ |
| 1159 | 1159 | #define SQLITE_VERSION "3.25.0" |
| 1160 | 1160 | #define SQLITE_VERSION_NUMBER 3025000 |
| 1161 | -#define SQLITE_SOURCE_ID "2018-09-10 19:34:06 74c381b573817d0212153278b5ee5d2238a27a727dcf7ee769365c47bb9fc40d" | |
| 1161 | +#define SQLITE_SOURCE_ID "2018-09-15 04:01:47 b63af6c3bd33152742648d5d2e8dc5d5fcbcdd27df409272b6aea00a6f761760" | |
| 1162 | 1162 | |
| 1163 | 1163 | /* |
| 1164 | 1164 | ** CAPI3REF: Run-Time Library Version Numbers |
| 1165 | 1165 | ** KEYWORDS: sqlite3_version sqlite3_sourceid |
| 1166 | 1166 | ** |
| @@ -2113,22 +2113,23 @@ | ||
| 2113 | 2113 | ** The [SQLITE_FCNTL_DATA_VERSION] opcode is used to detect changes to |
| 2114 | 2114 | ** a database file. The argument is a pointer to a 32-bit unsigned integer. |
| 2115 | 2115 | ** The "data version" for the pager is written into the pointer. The |
| 2116 | 2116 | ** "data version" changes whenever any change occurs to the corresponding |
| 2117 | 2117 | ** database file, either through SQL statements on the same database |
| 2118 | -** connection, or through transactions committed by separate database | |
| 2118 | +** connection or through transactions committed by separate database | |
| 2119 | 2119 | ** connections possibly in other processes. The [sqlite3_total_changes()] |
| 2120 | 2120 | ** interface can be used to find if any database on the connection has changed, |
| 2121 | -** but that interface response to changes on TEMP as well as MAIN and does | |
| 2121 | +** but that interface responds to changes on TEMP as well as MAIN and does | |
| 2122 | 2122 | ** not provide a mechanism to detect changes to MAIN only. Also, the |
| 2123 | -** [sqlite3_total_changes()] interface response to internal changes only and | |
| 2123 | +** [sqlite3_total_changes()] interface responds to internal changes only and | |
| 2124 | 2124 | ** omits changes made by other database connections. The |
| 2125 | 2125 | ** [PRAGMA data_version] command provide a mechanism to detect changes to |
| 2126 | 2126 | ** a single attached database that occur due to other database connections, |
| 2127 | -** but omits changes implemented by the database connection for which it is | |
| 2127 | +** but omits changes implemented by the database connection on which it is | |
| 2128 | 2128 | ** called. This file control is the only mechanism to detect changes that |
| 2129 | -** happen either internally or externally on a single database. | |
| 2129 | +** happen either internally or externally and that are associated with | |
| 2130 | +** a particular attached database. | |
| 2130 | 2131 | ** </ul> |
| 2131 | 2132 | */ |
| 2132 | 2133 | #define SQLITE_FCNTL_LOCKSTATE 1 |
| 2133 | 2134 | #define SQLITE_FCNTL_GET_LOCKPROXYFILE 2 |
| 2134 | 2135 | #define SQLITE_FCNTL_SET_LOCKPROXYFILE 3 |
| @@ -5762,11 +5763,11 @@ | ||
| 5762 | 5763 | ** SQL function or aggregate, pass NULL pointers for all three function |
| 5763 | 5764 | ** callbacks. |
| 5764 | 5765 | ** |
| 5765 | 5766 | ** ^The sixth, seventh, eighth and ninth parameters (xStep, xFinal, xValue |
| 5766 | 5767 | ** and xInverse) passed to sqlite3_create_window_function are pointers to |
| 5767 | -** C-lanugage callbacks that implement the new function. xStep and xFinal | |
| 5768 | +** C-language callbacks that implement the new function. xStep and xFinal | |
| 5768 | 5769 | ** must both be non-NULL. xValue and xInverse may either both be NULL, in |
| 5769 | 5770 | ** which case a regular aggregate function is created, or must both be |
| 5770 | 5771 | ** non-NULL, in which case the new function may be used as either an aggregate |
| 5771 | 5772 | ** or aggregate window function. More details regarding the implementation |
| 5772 | 5773 | ** of aggregate window functions are |
| @@ -10288,11 +10289,11 @@ | ||
| 10288 | 10289 | ** |
| 10289 | 10290 | ** The SQLITE_DESERIALIZE_FREEONCLOSE means that the database serialization |
| 10290 | 10291 | ** in the P argument is held in memory obtained from [sqlite3_malloc64()] |
| 10291 | 10292 | ** and that SQLite should take ownership of this memory and automatically |
| 10292 | 10293 | ** free it when it has finished using it. Without this flag, the caller |
| 10293 | -** is resposible for freeing any dynamically allocated memory. | |
| 10294 | +** is responsible for freeing any dynamically allocated memory. | |
| 10294 | 10295 | ** |
| 10295 | 10296 | ** The SQLITE_DESERIALIZE_RESIZEABLE flag means that SQLite is allowed to |
| 10296 | 10297 | ** grow the size of the database using calls to [sqlite3_realloc64()]. This |
| 10297 | 10298 | ** flag should only be used if SQLITE_DESERIALIZE_FREEONCLOSE is also used. |
| 10298 | 10299 | ** Without this flag, the deserialized database cannot increase in size beyond |
| @@ -12466,11 +12467,11 @@ | ||
| 12466 | 12467 | ** "place". |
| 12467 | 12468 | ** |
| 12468 | 12469 | ** This way, even if the tokenizer does not provide synonyms |
| 12469 | 12470 | ** when tokenizing query text (it should not - to do would be |
| 12470 | 12471 | ** inefficient), it doesn't matter if the user queries for |
| 12471 | -** 'first + place' or '1st + place', as there are entires in the | |
| 12472 | +** 'first + place' or '1st + place', as there are entries in the | |
| 12472 | 12473 | ** FTS index corresponding to both forms of the first token. |
| 12473 | 12474 | ** </ol> |
| 12474 | 12475 | ** |
| 12475 | 12476 | ** Whether it is parsing document or query text, any call to xToken that |
| 12476 | 12477 | ** specifies a <i>tflags</i> argument with the FTS5_TOKEN_COLOCATED bit |
| @@ -12494,11 +12495,11 @@ | ||
| 12494 | 12495 | ** |
| 12495 | 12496 | ** In many cases, method (1) above is the best approach. It does not add |
| 12496 | 12497 | ** extra data to the FTS index or require FTS5 to query for multiple terms, |
| 12497 | 12498 | ** so it is efficient in terms of disk space and query speed. However, it |
| 12498 | 12499 | ** does not support prefix queries very well. If, as suggested above, the |
| 12499 | -** token "first" is subsituted for "1st" by the tokenizer, then the query: | |
| 12500 | +** token "first" is substituted for "1st" by the tokenizer, then the query: | |
| 12500 | 12501 | ** |
| 12501 | 12502 | ** <codeblock> |
| 12502 | 12503 | ** ... MATCH '1s*'</codeblock> |
| 12503 | 12504 | ** |
| 12504 | 12505 | ** will not match documents that contain the token "1st" (as the tokenizer |
| @@ -18972,10 +18973,11 @@ | ||
| 18972 | 18973 | SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *, Token *); |
| 18973 | 18974 | SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *, SrcList *); |
| 18974 | 18975 | SQLITE_PRIVATE void *sqlite3RenameTokenMap(Parse*, void*, Token*); |
| 18975 | 18976 | SQLITE_PRIVATE void sqlite3RenameTokenRemap(Parse*, void *pTo, void *pFrom); |
| 18976 | 18977 | SQLITE_PRIVATE void sqlite3RenameExprUnmap(Parse*, Expr*); |
| 18978 | +SQLITE_PRIVATE void sqlite3RenameExprlistUnmap(Parse*, ExprList*); | |
| 18977 | 18979 | SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq(Parse*, u8, CollSeq *, const char*); |
| 18978 | 18980 | SQLITE_PRIVATE char sqlite3AffinityType(const char*, Column*); |
| 18979 | 18981 | SQLITE_PRIVATE void sqlite3Analyze(Parse*, Token*, Token*); |
| 18980 | 18982 | SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler*, sqlite3_file*); |
| 18981 | 18983 | SQLITE_PRIVATE int sqlite3FindDb(sqlite3*, Token*); |
| @@ -27606,11 +27608,16 @@ | ||
| 27606 | 27608 | bufpt = va_arg(ap,char*); |
| 27607 | 27609 | } |
| 27608 | 27610 | if( bufpt==0 ){ |
| 27609 | 27611 | bufpt = ""; |
| 27610 | 27612 | }else if( xtype==etDYNSTRING ){ |
| 27611 | - if( pAccum->nChar==0 && pAccum->mxAlloc && width==0 && precision<0 ){ | |
| 27613 | + if( pAccum->nChar==0 | |
| 27614 | + && pAccum->mxAlloc | |
| 27615 | + && width==0 | |
| 27616 | + && precision<0 | |
| 27617 | + && pAccum->accError==0 | |
| 27618 | + ){ | |
| 27612 | 27619 | /* Special optimization for sqlite3_mprintf("%z..."): |
| 27613 | 27620 | ** Extend an existing memory allocation rather than creating |
| 27614 | 27621 | ** a new one. */ |
| 27615 | 27622 | assert( (pAccum->printfFlags&SQLITE_PRINTF_MALLOCED)==0 ); |
| 27616 | 27623 | pAccum->zText = bufpt; |
| @@ -36968,11 +36975,13 @@ | ||
| 36968 | 36975 | static void unixShmBarrier( |
| 36969 | 36976 | sqlite3_file *fd /* Database file holding the shared memory */ |
| 36970 | 36977 | ){ |
| 36971 | 36978 | UNUSED_PARAMETER(fd); |
| 36972 | 36979 | sqlite3MemoryBarrier(); /* compiler-defined memory barrier */ |
| 36973 | - assert( unixFileMutexNotheld((unixFile*)fd) ); | |
| 36980 | + assert( fd->pMethods->xLock==nolockLock | |
| 36981 | + || unixFileMutexNotheld((unixFile*)fd) | |
| 36982 | + ); | |
| 36974 | 36983 | unixEnterMutex(); /* Also mutex, for redundancy */ |
| 36975 | 36984 | unixLeaveMutex(); |
| 36976 | 36985 | } |
| 36977 | 36986 | |
| 36978 | 36987 | /* |
| @@ -46285,12 +46294,12 @@ | ||
| 46285 | 46294 | ** block of memory. |
| 46286 | 46295 | ** |
| 46287 | 46296 | ** This file also implements interface sqlite3_serialize() and |
| 46288 | 46297 | ** sqlite3_deserialize(). |
| 46289 | 46298 | */ |
| 46290 | -#ifdef SQLITE_ENABLE_DESERIALIZE | |
| 46291 | 46299 | /* #include "sqliteInt.h" */ |
| 46300 | +#ifdef SQLITE_ENABLE_DESERIALIZE | |
| 46292 | 46301 | |
| 46293 | 46302 | /* |
| 46294 | 46303 | ** Forward declaration of objects used by this utility |
| 46295 | 46304 | */ |
| 46296 | 46305 | typedef struct sqlite3_vfs MemVfs; |
| @@ -60507,11 +60516,11 @@ | ||
| 60507 | 60516 | ** Other threads might append new content to the WAL and wal-index but |
| 60508 | 60517 | ** that extra content is ignored by the current thread. |
| 60509 | 60518 | ** |
| 60510 | 60519 | ** If the database contents have changes since the previous read |
| 60511 | 60520 | ** transaction, then *pChanged is set to 1 before returning. The |
| 60512 | -** Pager layer will use this to know that is cache is stale and | |
| 60521 | +** Pager layer will use this to know that its cache is stale and | |
| 60513 | 60522 | ** needs to be flushed. |
| 60514 | 60523 | */ |
| 60515 | 60524 | SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){ |
| 60516 | 60525 | int rc; /* Return code */ |
| 60517 | 60526 | int cnt = 0; /* Number of TryBeginRead attempts */ |
| @@ -78538,11 +78547,11 @@ | ||
| 78538 | 78547 | ** error, then it might not have been halted properly. So halt |
| 78539 | 78548 | ** it now. |
| 78540 | 78549 | */ |
| 78541 | 78550 | sqlite3VdbeHalt(p); |
| 78542 | 78551 | |
| 78543 | - /* If the VDBE has be run even partially, then transfer the error code | |
| 78552 | + /* If the VDBE has been run even partially, then transfer the error code | |
| 78544 | 78553 | ** and error message from the VDBE into the main database structure. But |
| 78545 | 78554 | ** if the VDBE has just been set to run but has not actually executed any |
| 78546 | 78555 | ** instructions yet, leave the main database error information unchanged. |
| 78547 | 78556 | */ |
| 78548 | 78557 | if( p->pc>=0 ){ |
| @@ -101161,11 +101170,11 @@ | ||
| 101161 | 101170 | ** bTemp is not true, database "temp", can still be parsed. This is |
| 101162 | 101171 | ** called at the end of the generation of an ALTER TABLE ... RENAME ... |
| 101163 | 101172 | ** statement to ensure that the operation has not rendered any schema |
| 101164 | 101173 | ** objects unusable. |
| 101165 | 101174 | */ |
| 101166 | -void renameTestSchema(Parse *pParse, const char *zDb, int bTemp){ | |
| 101175 | +static void renameTestSchema(Parse *pParse, const char *zDb, int bTemp){ | |
| 101167 | 101176 | sqlite3NestedParse(pParse, |
| 101168 | 101177 | "SELECT 1 " |
| 101169 | 101178 | "FROM \"%w\".%s " |
| 101170 | 101179 | "WHERE name NOT LIKE 'sqlite_%%'" |
| 101171 | 101180 | " AND sql NOT LIKE 'create virtual%%'" |
| @@ -101188,11 +101197,11 @@ | ||
| 101188 | 101197 | |
| 101189 | 101198 | /* |
| 101190 | 101199 | ** Generate code to reload the schema for database iDb. And, if iDb!=1, for |
| 101191 | 101200 | ** the temp database as well. |
| 101192 | 101201 | */ |
| 101193 | -void renameReloadSchema(Parse *pParse, int iDb){ | |
| 101202 | +static void renameReloadSchema(Parse *pParse, int iDb){ | |
| 101194 | 101203 | Vdbe *v = pParse->pVdbe; |
| 101195 | 101204 | if( v ){ |
| 101196 | 101205 | sqlite3ChangeCookie(pParse, iDb); |
| 101197 | 101206 | sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, iDb, 0); |
| 101198 | 101207 | if( iDb!=1 ) sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, 1, 0); |
| @@ -101768,11 +101777,11 @@ | ||
| 101768 | 101777 | ** if( x==y ) ... |
| 101769 | 101778 | ** |
| 101770 | 101779 | ** Technically, as x no longer points into a valid object or to the byte |
| 101771 | 101780 | ** following a valid object, it may not be used in comparison operations. |
| 101772 | 101781 | */ |
| 101773 | -void renameTokenCheckAll(Parse *pParse, void *pPtr){ | |
| 101782 | +static void renameTokenCheckAll(Parse *pParse, void *pPtr){ | |
| 101774 | 101783 | if( pParse->nErr==0 && pParse->db->mallocFailed==0 ){ |
| 101775 | 101784 | RenameToken *p; |
| 101776 | 101785 | u8 i = 0; |
| 101777 | 101786 | for(p=pParse->pRename; p; p=p->pNext){ |
| 101778 | 101787 | if( p->p ){ |
| @@ -101840,10 +101849,28 @@ | ||
| 101840 | 101849 | memset(&sWalker, 0, sizeof(Walker)); |
| 101841 | 101850 | sWalker.pParse = pParse; |
| 101842 | 101851 | sWalker.xExprCallback = renameUnmapExprCb; |
| 101843 | 101852 | sqlite3WalkExpr(&sWalker, pExpr); |
| 101844 | 101853 | } |
| 101854 | + | |
| 101855 | +/* | |
| 101856 | +** Remove all nodes that are part of expression-list pEList from the | |
| 101857 | +** rename list. | |
| 101858 | +*/ | |
| 101859 | +SQLITE_PRIVATE void sqlite3RenameExprlistUnmap(Parse *pParse, ExprList *pEList){ | |
| 101860 | + if( pEList ){ | |
| 101861 | + int i; | |
| 101862 | + Walker sWalker; | |
| 101863 | + memset(&sWalker, 0, sizeof(Walker)); | |
| 101864 | + sWalker.pParse = pParse; | |
| 101865 | + sWalker.xExprCallback = renameUnmapExprCb; | |
| 101866 | + sqlite3WalkExprList(&sWalker, pEList); | |
| 101867 | + for(i=0; i<pEList->nExpr; i++){ | |
| 101868 | + sqlite3RenameTokenRemap(pParse, 0, (void*)pEList->a[i].zName); | |
| 101869 | + } | |
| 101870 | + } | |
| 101871 | +} | |
| 101845 | 101872 | |
| 101846 | 101873 | /* |
| 101847 | 101874 | ** Free the list of RenameToken objects given in the second argument |
| 101848 | 101875 | */ |
| 101849 | 101876 | static void renameTokenFree(sqlite3 *db, RenameToken *pToken){ |
| @@ -107746,10 +107773,13 @@ | ||
| 107746 | 107773 | /* Use sqlite3EndTable() to add the view to the SQLITE_MASTER table */ |
| 107747 | 107774 | sqlite3EndTable(pParse, 0, &sEnd, 0, 0); |
| 107748 | 107775 | |
| 107749 | 107776 | create_view_fail: |
| 107750 | 107777 | sqlite3SelectDelete(db, pSelect); |
| 107778 | + if( IN_RENAME_OBJECT ){ | |
| 107779 | + sqlite3RenameExprlistUnmap(pParse, pCNames); | |
| 107780 | + } | |
| 107751 | 107781 | sqlite3ExprListDelete(db, pCNames); |
| 107752 | 107782 | return; |
| 107753 | 107783 | } |
| 107754 | 107784 | #endif /* SQLITE_OMIT_VIEW */ |
| 107755 | 107785 | |
| @@ -135329,15 +135359,12 @@ | ||
| 135329 | 135359 | static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){ |
| 135330 | 135360 | int rc = WRC_Continue; |
| 135331 | 135361 | struct CCurHint *pHint = pWalker->u.pCCurHint; |
| 135332 | 135362 | if( pExpr->op==TK_COLUMN ){ |
| 135333 | 135363 | if( pExpr->iTable!=pHint->iTabCur ){ |
| 135334 | - Vdbe *v = pWalker->pParse->pVdbe; | |
| 135335 | 135364 | int reg = ++pWalker->pParse->nMem; /* Register for column value */ |
| 135336 | - sqlite3ExprCodeGetColumnOfTable( | |
| 135337 | - v, pExpr->pTab, pExpr->iTable, pExpr->iColumn, reg | |
| 135338 | - ); | |
| 135365 | + sqlite3ExprCode(pWalker->pParse, pExpr, reg); | |
| 135339 | 135366 | pExpr->op = TK_REGISTER; |
| 135340 | 135367 | pExpr->iTable = reg; |
| 135341 | 135368 | }else if( pHint->pIdx!=0 ){ |
| 135342 | 135369 | pExpr->iTable = pHint->iIdxCur; |
| 135343 | 135370 | pExpr->iColumn = sqlite3ColumnOfIndex(pHint->pIdx, pExpr->iColumn); |
| @@ -177353,15 +177380,15 @@ | ||
| 177353 | 177380 | jsonAppendChar(pStr, ']'); |
| 177354 | 177381 | if( pStr->bErr ){ |
| 177355 | 177382 | if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx); |
| 177356 | 177383 | assert( pStr->bStatic ); |
| 177357 | 177384 | }else if( isFinal ){ |
| 177358 | - sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed, | |
| 177385 | + sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, | |
| 177359 | 177386 | pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free); |
| 177360 | 177387 | pStr->bStatic = 1; |
| 177361 | 177388 | }else{ |
| 177362 | - sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed, SQLITE_TRANSIENT); | |
| 177389 | + sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT); | |
| 177363 | 177390 | pStr->nUsed--; |
| 177364 | 177391 | } |
| 177365 | 177392 | }else{ |
| 177366 | 177393 | sqlite3_result_text(ctx, "[]", 2, SQLITE_STATIC); |
| 177367 | 177394 | } |
| @@ -177406,11 +177433,11 @@ | ||
| 177406 | 177433 | }else if( z[i]=='\\' ){ |
| 177407 | 177434 | i++; |
| 177408 | 177435 | } |
| 177409 | 177436 | } |
| 177410 | 177437 | pStr->nUsed -= i; |
| 177411 | - memmove(&z[1], &z[i+1], pStr->nUsed-1); | |
| 177438 | + memmove(&z[1], &z[i+1], (size_t)pStr->nUsed-1); | |
| 177412 | 177439 | } |
| 177413 | 177440 | #else |
| 177414 | 177441 | # define jsonGroupInverse 0 |
| 177415 | 177442 | #endif |
| 177416 | 177443 | |
| @@ -177452,15 +177479,15 @@ | ||
| 177452 | 177479 | jsonAppendChar(pStr, '}'); |
| 177453 | 177480 | if( pStr->bErr ){ |
| 177454 | 177481 | if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx); |
| 177455 | 177482 | assert( pStr->bStatic ); |
| 177456 | 177483 | }else if( isFinal ){ |
| 177457 | - sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed, | |
| 177484 | + sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, | |
| 177458 | 177485 | pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free); |
| 177459 | 177486 | pStr->bStatic = 1; |
| 177460 | 177487 | }else{ |
| 177461 | - sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed, SQLITE_TRANSIENT); | |
| 177488 | + sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT); | |
| 177462 | 177489 | pStr->nUsed--; |
| 177463 | 177490 | } |
| 177464 | 177491 | }else{ |
| 177465 | 177492 | sqlite3_result_text(ctx, "{}", 2, SQLITE_STATIC); |
| 177466 | 177493 | } |
| @@ -181310,11 +181337,11 @@ | ||
| 181310 | 181337 | ** DROP TABLE <tablename>; -- Would fail with SQLITE_LOCKED |
| 181311 | 181338 | ** COMMIT; |
| 181312 | 181339 | */ |
| 181313 | 181340 | static int rtreeSavepoint(sqlite3_vtab *pVtab, int iSavepoint){ |
| 181314 | 181341 | Rtree *pRtree = (Rtree *)pVtab; |
| 181315 | - int iwt = pRtree->inWrTrans; | |
| 181342 | + u8 iwt = pRtree->inWrTrans; | |
| 181316 | 181343 | UNUSED_PARAMETER(iSavepoint); |
| 181317 | 181344 | pRtree->inWrTrans = 0; |
| 181318 | 181345 | nodeBlobReset(pRtree); |
| 181319 | 181346 | pRtree->inWrTrans = iwt; |
| 181320 | 181347 | return SQLITE_OK; |
| @@ -182450,11 +182477,11 @@ | ||
| 182450 | 182477 | continue; |
| 182451 | 182478 | } |
| 182452 | 182479 | break; |
| 182453 | 182480 | } |
| 182454 | 182481 | if( z[j-1]<'0' ) return 0; |
| 182455 | - if( pVal ) *pVal = atof((const char*)p->z); | |
| 182482 | + if( pVal ) *pVal = (GeoCoord)atof((const char*)p->z); | |
| 182456 | 182483 | p->z += j; |
| 182457 | 182484 | return 1; |
| 182458 | 182485 | } |
| 182459 | 182486 | |
| 182460 | 182487 | /* |
| @@ -182705,12 +182732,12 @@ | ||
| 182705 | 182732 | int ii; |
| 182706 | 182733 | if( p ){ |
| 182707 | 182734 | for(ii=0; ii<p->nVertex; ii++){ |
| 182708 | 182735 | x0 = p->a[ii*2]; |
| 182709 | 182736 | y0 = p->a[ii*2+1]; |
| 182710 | - x1 = A*x0 + B*y0 + E; | |
| 182711 | - y1 = C*x0 + D*y0 + F; | |
| 182737 | + x1 = (GeoCoord)(A*x0 + B*y0 + E); | |
| 182738 | + y1 = (GeoCoord)(C*x0 + D*y0 + F); | |
| 182712 | 182739 | p->a[ii*2] = x1; |
| 182713 | 182740 | p->a[ii*2+1] = y1; |
| 182714 | 182741 | } |
| 182715 | 182742 | sqlite3_result_blob(context, p->hdr, |
| 182716 | 182743 | 4+8*p->nVertex, SQLITE_TRANSIENT); |
| @@ -182781,15 +182808,15 @@ | ||
| 182781 | 182808 | int ii; |
| 182782 | 182809 | mnX = mxX = p->a[0]; |
| 182783 | 182810 | mnY = mxY = p->a[1]; |
| 182784 | 182811 | for(ii=1; ii<p->nVertex; ii++){ |
| 182785 | 182812 | double r = p->a[ii*2]; |
| 182786 | - if( r<mnX ) mnX = r; | |
| 182787 | - else if( r>mxX ) mxX = r; | |
| 182813 | + if( r<mnX ) mnX = (float)r; | |
| 182814 | + else if( r>mxX ) mxX = (float)r; | |
| 182788 | 182815 | r = p->a[ii*2+1]; |
| 182789 | - if( r<mnY ) mnY = r; | |
| 182790 | - else if( r>mxY ) mxY = r; | |
| 182816 | + if( r<mnY ) mnY = (float)r; | |
| 182817 | + else if( r>mxY ) mxY = (float)r; | |
| 182791 | 182818 | } |
| 182792 | 182819 | if( pRc ) *pRc = SQLITE_OK; |
| 182793 | 182820 | if( aCoord==0 ){ |
| 182794 | 182821 | geopolyBboxFill: |
| 182795 | 182822 | pOut = sqlite3_realloc(p, sizeof(GeoPoly)+sizeof(GeoCoord)*6); |
| @@ -197385,11 +197412,11 @@ | ||
| 197385 | 197412 | ** "place". |
| 197386 | 197413 | ** |
| 197387 | 197414 | ** This way, even if the tokenizer does not provide synonyms |
| 197388 | 197415 | ** when tokenizing query text (it should not - to do would be |
| 197389 | 197416 | ** inefficient), it doesn't matter if the user queries for |
| 197390 | -** 'first + place' or '1st + place', as there are entires in the | |
| 197417 | +** 'first + place' or '1st + place', as there are entries in the | |
| 197391 | 197418 | ** FTS index corresponding to both forms of the first token. |
| 197392 | 197419 | ** </ol> |
| 197393 | 197420 | ** |
| 197394 | 197421 | ** Whether it is parsing document or query text, any call to xToken that |
| 197395 | 197422 | ** specifies a <i>tflags</i> argument with the FTS5_TOKEN_COLOCATED bit |
| @@ -197413,11 +197440,11 @@ | ||
| 197413 | 197440 | ** |
| 197414 | 197441 | ** In many cases, method (1) above is the best approach. It does not add |
| 197415 | 197442 | ** extra data to the FTS index or require FTS5 to query for multiple terms, |
| 197416 | 197443 | ** so it is efficient in terms of disk space and query speed. However, it |
| 197417 | 197444 | ** does not support prefix queries very well. If, as suggested above, the |
| 197418 | -** token "first" is subsituted for "1st" by the tokenizer, then the query: | |
| 197445 | +** token "first" is substituted for "1st" by the tokenizer, then the query: | |
| 197419 | 197446 | ** |
| 197420 | 197447 | ** <codeblock> |
| 197421 | 197448 | ** ... MATCH '1s*'</codeblock> |
| 197422 | 197449 | ** |
| 197423 | 197450 | ** will not match documents that contain the token "1st" (as the tokenizer |
| @@ -214387,11 +214414,11 @@ | ||
| 214387 | 214414 | int nArg, /* Number of args */ |
| 214388 | 214415 | sqlite3_value **apUnused /* Function arguments */ |
| 214389 | 214416 | ){ |
| 214390 | 214417 | assert( nArg==0 ); |
| 214391 | 214418 | UNUSED_PARAM2(nArg, apUnused); |
| 214392 | - sqlite3_result_text(pCtx, "fts5: 2018-09-10 16:38:25 564fa75195c5179d0bc86431aaff06136fc65ec63aa9839cd1114b1fbfac928b", -1, SQLITE_TRANSIENT); | |
| 214419 | + sqlite3_result_text(pCtx, "fts5: 2018-09-15 04:01:47 b63af6c3bd33152742648d5d2e8dc5d5fcbcdd27df409272b6aea00a6f761760", -1, SQLITE_TRANSIENT); | |
| 214393 | 214420 | } |
| 214394 | 214421 | |
| 214395 | 214422 | static int fts5Init(sqlite3 *db){ |
| 214396 | 214423 | static const sqlite3_module fts5Mod = { |
| 214397 | 214424 | /* iVersion */ 2, |
| @@ -219097,12 +219124,12 @@ | ||
| 219097 | 219124 | } |
| 219098 | 219125 | #endif /* SQLITE_CORE */ |
| 219099 | 219126 | #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */ |
| 219100 | 219127 | |
| 219101 | 219128 | /************** End of stmt.c ************************************************/ |
| 219102 | -#if __LINE__!=219102 | |
| 219129 | +#if __LINE__!=219129 | |
| 219103 | 219130 | #undef SQLITE_SOURCE_ID |
| 219104 | -#define SQLITE_SOURCE_ID "2018-09-10 19:34:06 74c381b573817d0212153278b5ee5d2238a27a727dcf7ee769365c47bb9falt2" | |
| 219131 | +#define SQLITE_SOURCE_ID "2018-09-15 04:01:47 b63af6c3bd33152742648d5d2e8dc5d5fcbcdd27df409272b6aea00a6f76alt2" | |
| 219105 | 219132 | #endif |
| 219106 | 219133 | /* Return the source-id for this library */ |
| 219107 | 219134 | SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } |
| 219108 | 219135 | /************************** End of sqlite3.c ******************************/ |
| 219109 | 219136 |
| --- src/sqlite3.c | |
| +++ src/sqlite3.c | |
| @@ -1156,11 +1156,11 @@ | |
| 1156 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 1157 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 1158 | */ |
| 1159 | #define SQLITE_VERSION "3.25.0" |
| 1160 | #define SQLITE_VERSION_NUMBER 3025000 |
| 1161 | #define SQLITE_SOURCE_ID "2018-09-10 19:34:06 74c381b573817d0212153278b5ee5d2238a27a727dcf7ee769365c47bb9fc40d" |
| 1162 | |
| 1163 | /* |
| 1164 | ** CAPI3REF: Run-Time Library Version Numbers |
| 1165 | ** KEYWORDS: sqlite3_version sqlite3_sourceid |
| 1166 | ** |
| @@ -2113,22 +2113,23 @@ | |
| 2113 | ** The [SQLITE_FCNTL_DATA_VERSION] opcode is used to detect changes to |
| 2114 | ** a database file. The argument is a pointer to a 32-bit unsigned integer. |
| 2115 | ** The "data version" for the pager is written into the pointer. The |
| 2116 | ** "data version" changes whenever any change occurs to the corresponding |
| 2117 | ** database file, either through SQL statements on the same database |
| 2118 | ** connection, or through transactions committed by separate database |
| 2119 | ** connections possibly in other processes. The [sqlite3_total_changes()] |
| 2120 | ** interface can be used to find if any database on the connection has changed, |
| 2121 | ** but that interface response to changes on TEMP as well as MAIN and does |
| 2122 | ** not provide a mechanism to detect changes to MAIN only. Also, the |
| 2123 | ** [sqlite3_total_changes()] interface response to internal changes only and |
| 2124 | ** omits changes made by other database connections. The |
| 2125 | ** [PRAGMA data_version] command provide a mechanism to detect changes to |
| 2126 | ** a single attached database that occur due to other database connections, |
| 2127 | ** but omits changes implemented by the database connection for which it is |
| 2128 | ** called. This file control is the only mechanism to detect changes that |
| 2129 | ** happen either internally or externally on a single database. |
| 2130 | ** </ul> |
| 2131 | */ |
| 2132 | #define SQLITE_FCNTL_LOCKSTATE 1 |
| 2133 | #define SQLITE_FCNTL_GET_LOCKPROXYFILE 2 |
| 2134 | #define SQLITE_FCNTL_SET_LOCKPROXYFILE 3 |
| @@ -5762,11 +5763,11 @@ | |
| 5762 | ** SQL function or aggregate, pass NULL pointers for all three function |
| 5763 | ** callbacks. |
| 5764 | ** |
| 5765 | ** ^The sixth, seventh, eighth and ninth parameters (xStep, xFinal, xValue |
| 5766 | ** and xInverse) passed to sqlite3_create_window_function are pointers to |
| 5767 | ** C-lanugage callbacks that implement the new function. xStep and xFinal |
| 5768 | ** must both be non-NULL. xValue and xInverse may either both be NULL, in |
| 5769 | ** which case a regular aggregate function is created, or must both be |
| 5770 | ** non-NULL, in which case the new function may be used as either an aggregate |
| 5771 | ** or aggregate window function. More details regarding the implementation |
| 5772 | ** of aggregate window functions are |
| @@ -10288,11 +10289,11 @@ | |
| 10288 | ** |
| 10289 | ** The SQLITE_DESERIALIZE_FREEONCLOSE means that the database serialization |
| 10290 | ** in the P argument is held in memory obtained from [sqlite3_malloc64()] |
| 10291 | ** and that SQLite should take ownership of this memory and automatically |
| 10292 | ** free it when it has finished using it. Without this flag, the caller |
| 10293 | ** is resposible for freeing any dynamically allocated memory. |
| 10294 | ** |
| 10295 | ** The SQLITE_DESERIALIZE_RESIZEABLE flag means that SQLite is allowed to |
| 10296 | ** grow the size of the database using calls to [sqlite3_realloc64()]. This |
| 10297 | ** flag should only be used if SQLITE_DESERIALIZE_FREEONCLOSE is also used. |
| 10298 | ** Without this flag, the deserialized database cannot increase in size beyond |
| @@ -12466,11 +12467,11 @@ | |
| 12466 | ** "place". |
| 12467 | ** |
| 12468 | ** This way, even if the tokenizer does not provide synonyms |
| 12469 | ** when tokenizing query text (it should not - to do would be |
| 12470 | ** inefficient), it doesn't matter if the user queries for |
| 12471 | ** 'first + place' or '1st + place', as there are entires in the |
| 12472 | ** FTS index corresponding to both forms of the first token. |
| 12473 | ** </ol> |
| 12474 | ** |
| 12475 | ** Whether it is parsing document or query text, any call to xToken that |
| 12476 | ** specifies a <i>tflags</i> argument with the FTS5_TOKEN_COLOCATED bit |
| @@ -12494,11 +12495,11 @@ | |
| 12494 | ** |
| 12495 | ** In many cases, method (1) above is the best approach. It does not add |
| 12496 | ** extra data to the FTS index or require FTS5 to query for multiple terms, |
| 12497 | ** so it is efficient in terms of disk space and query speed. However, it |
| 12498 | ** does not support prefix queries very well. If, as suggested above, the |
| 12499 | ** token "first" is subsituted for "1st" by the tokenizer, then the query: |
| 12500 | ** |
| 12501 | ** <codeblock> |
| 12502 | ** ... MATCH '1s*'</codeblock> |
| 12503 | ** |
| 12504 | ** will not match documents that contain the token "1st" (as the tokenizer |
| @@ -18972,10 +18973,11 @@ | |
| 18972 | SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *, Token *); |
| 18973 | SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *, SrcList *); |
| 18974 | SQLITE_PRIVATE void *sqlite3RenameTokenMap(Parse*, void*, Token*); |
| 18975 | SQLITE_PRIVATE void sqlite3RenameTokenRemap(Parse*, void *pTo, void *pFrom); |
| 18976 | SQLITE_PRIVATE void sqlite3RenameExprUnmap(Parse*, Expr*); |
| 18977 | SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq(Parse*, u8, CollSeq *, const char*); |
| 18978 | SQLITE_PRIVATE char sqlite3AffinityType(const char*, Column*); |
| 18979 | SQLITE_PRIVATE void sqlite3Analyze(Parse*, Token*, Token*); |
| 18980 | SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler*, sqlite3_file*); |
| 18981 | SQLITE_PRIVATE int sqlite3FindDb(sqlite3*, Token*); |
| @@ -27606,11 +27608,16 @@ | |
| 27606 | bufpt = va_arg(ap,char*); |
| 27607 | } |
| 27608 | if( bufpt==0 ){ |
| 27609 | bufpt = ""; |
| 27610 | }else if( xtype==etDYNSTRING ){ |
| 27611 | if( pAccum->nChar==0 && pAccum->mxAlloc && width==0 && precision<0 ){ |
| 27612 | /* Special optimization for sqlite3_mprintf("%z..."): |
| 27613 | ** Extend an existing memory allocation rather than creating |
| 27614 | ** a new one. */ |
| 27615 | assert( (pAccum->printfFlags&SQLITE_PRINTF_MALLOCED)==0 ); |
| 27616 | pAccum->zText = bufpt; |
| @@ -36968,11 +36975,13 @@ | |
| 36968 | static void unixShmBarrier( |
| 36969 | sqlite3_file *fd /* Database file holding the shared memory */ |
| 36970 | ){ |
| 36971 | UNUSED_PARAMETER(fd); |
| 36972 | sqlite3MemoryBarrier(); /* compiler-defined memory barrier */ |
| 36973 | assert( unixFileMutexNotheld((unixFile*)fd) ); |
| 36974 | unixEnterMutex(); /* Also mutex, for redundancy */ |
| 36975 | unixLeaveMutex(); |
| 36976 | } |
| 36977 | |
| 36978 | /* |
| @@ -46285,12 +46294,12 @@ | |
| 46285 | ** block of memory. |
| 46286 | ** |
| 46287 | ** This file also implements interface sqlite3_serialize() and |
| 46288 | ** sqlite3_deserialize(). |
| 46289 | */ |
| 46290 | #ifdef SQLITE_ENABLE_DESERIALIZE |
| 46291 | /* #include "sqliteInt.h" */ |
| 46292 | |
| 46293 | /* |
| 46294 | ** Forward declaration of objects used by this utility |
| 46295 | */ |
| 46296 | typedef struct sqlite3_vfs MemVfs; |
| @@ -60507,11 +60516,11 @@ | |
| 60507 | ** Other threads might append new content to the WAL and wal-index but |
| 60508 | ** that extra content is ignored by the current thread. |
| 60509 | ** |
| 60510 | ** If the database contents have changes since the previous read |
| 60511 | ** transaction, then *pChanged is set to 1 before returning. The |
| 60512 | ** Pager layer will use this to know that is cache is stale and |
| 60513 | ** needs to be flushed. |
| 60514 | */ |
| 60515 | SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){ |
| 60516 | int rc; /* Return code */ |
| 60517 | int cnt = 0; /* Number of TryBeginRead attempts */ |
| @@ -78538,11 +78547,11 @@ | |
| 78538 | ** error, then it might not have been halted properly. So halt |
| 78539 | ** it now. |
| 78540 | */ |
| 78541 | sqlite3VdbeHalt(p); |
| 78542 | |
| 78543 | /* If the VDBE has be run even partially, then transfer the error code |
| 78544 | ** and error message from the VDBE into the main database structure. But |
| 78545 | ** if the VDBE has just been set to run but has not actually executed any |
| 78546 | ** instructions yet, leave the main database error information unchanged. |
| 78547 | */ |
| 78548 | if( p->pc>=0 ){ |
| @@ -101161,11 +101170,11 @@ | |
| 101161 | ** bTemp is not true, database "temp", can still be parsed. This is |
| 101162 | ** called at the end of the generation of an ALTER TABLE ... RENAME ... |
| 101163 | ** statement to ensure that the operation has not rendered any schema |
| 101164 | ** objects unusable. |
| 101165 | */ |
| 101166 | void renameTestSchema(Parse *pParse, const char *zDb, int bTemp){ |
| 101167 | sqlite3NestedParse(pParse, |
| 101168 | "SELECT 1 " |
| 101169 | "FROM \"%w\".%s " |
| 101170 | "WHERE name NOT LIKE 'sqlite_%%'" |
| 101171 | " AND sql NOT LIKE 'create virtual%%'" |
| @@ -101188,11 +101197,11 @@ | |
| 101188 | |
| 101189 | /* |
| 101190 | ** Generate code to reload the schema for database iDb. And, if iDb!=1, for |
| 101191 | ** the temp database as well. |
| 101192 | */ |
| 101193 | void renameReloadSchema(Parse *pParse, int iDb){ |
| 101194 | Vdbe *v = pParse->pVdbe; |
| 101195 | if( v ){ |
| 101196 | sqlite3ChangeCookie(pParse, iDb); |
| 101197 | sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, iDb, 0); |
| 101198 | if( iDb!=1 ) sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, 1, 0); |
| @@ -101768,11 +101777,11 @@ | |
| 101768 | ** if( x==y ) ... |
| 101769 | ** |
| 101770 | ** Technically, as x no longer points into a valid object or to the byte |
| 101771 | ** following a valid object, it may not be used in comparison operations. |
| 101772 | */ |
| 101773 | void renameTokenCheckAll(Parse *pParse, void *pPtr){ |
| 101774 | if( pParse->nErr==0 && pParse->db->mallocFailed==0 ){ |
| 101775 | RenameToken *p; |
| 101776 | u8 i = 0; |
| 101777 | for(p=pParse->pRename; p; p=p->pNext){ |
| 101778 | if( p->p ){ |
| @@ -101840,10 +101849,28 @@ | |
| 101840 | memset(&sWalker, 0, sizeof(Walker)); |
| 101841 | sWalker.pParse = pParse; |
| 101842 | sWalker.xExprCallback = renameUnmapExprCb; |
| 101843 | sqlite3WalkExpr(&sWalker, pExpr); |
| 101844 | } |
| 101845 | |
| 101846 | /* |
| 101847 | ** Free the list of RenameToken objects given in the second argument |
| 101848 | */ |
| 101849 | static void renameTokenFree(sqlite3 *db, RenameToken *pToken){ |
| @@ -107746,10 +107773,13 @@ | |
| 107746 | /* Use sqlite3EndTable() to add the view to the SQLITE_MASTER table */ |
| 107747 | sqlite3EndTable(pParse, 0, &sEnd, 0, 0); |
| 107748 | |
| 107749 | create_view_fail: |
| 107750 | sqlite3SelectDelete(db, pSelect); |
| 107751 | sqlite3ExprListDelete(db, pCNames); |
| 107752 | return; |
| 107753 | } |
| 107754 | #endif /* SQLITE_OMIT_VIEW */ |
| 107755 | |
| @@ -135329,15 +135359,12 @@ | |
| 135329 | static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){ |
| 135330 | int rc = WRC_Continue; |
| 135331 | struct CCurHint *pHint = pWalker->u.pCCurHint; |
| 135332 | if( pExpr->op==TK_COLUMN ){ |
| 135333 | if( pExpr->iTable!=pHint->iTabCur ){ |
| 135334 | Vdbe *v = pWalker->pParse->pVdbe; |
| 135335 | int reg = ++pWalker->pParse->nMem; /* Register for column value */ |
| 135336 | sqlite3ExprCodeGetColumnOfTable( |
| 135337 | v, pExpr->pTab, pExpr->iTable, pExpr->iColumn, reg |
| 135338 | ); |
| 135339 | pExpr->op = TK_REGISTER; |
| 135340 | pExpr->iTable = reg; |
| 135341 | }else if( pHint->pIdx!=0 ){ |
| 135342 | pExpr->iTable = pHint->iIdxCur; |
| 135343 | pExpr->iColumn = sqlite3ColumnOfIndex(pHint->pIdx, pExpr->iColumn); |
| @@ -177353,15 +177380,15 @@ | |
| 177353 | jsonAppendChar(pStr, ']'); |
| 177354 | if( pStr->bErr ){ |
| 177355 | if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx); |
| 177356 | assert( pStr->bStatic ); |
| 177357 | }else if( isFinal ){ |
| 177358 | sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed, |
| 177359 | pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free); |
| 177360 | pStr->bStatic = 1; |
| 177361 | }else{ |
| 177362 | sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed, SQLITE_TRANSIENT); |
| 177363 | pStr->nUsed--; |
| 177364 | } |
| 177365 | }else{ |
| 177366 | sqlite3_result_text(ctx, "[]", 2, SQLITE_STATIC); |
| 177367 | } |
| @@ -177406,11 +177433,11 @@ | |
| 177406 | }else if( z[i]=='\\' ){ |
| 177407 | i++; |
| 177408 | } |
| 177409 | } |
| 177410 | pStr->nUsed -= i; |
| 177411 | memmove(&z[1], &z[i+1], pStr->nUsed-1); |
| 177412 | } |
| 177413 | #else |
| 177414 | # define jsonGroupInverse 0 |
| 177415 | #endif |
| 177416 | |
| @@ -177452,15 +177479,15 @@ | |
| 177452 | jsonAppendChar(pStr, '}'); |
| 177453 | if( pStr->bErr ){ |
| 177454 | if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx); |
| 177455 | assert( pStr->bStatic ); |
| 177456 | }else if( isFinal ){ |
| 177457 | sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed, |
| 177458 | pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free); |
| 177459 | pStr->bStatic = 1; |
| 177460 | }else{ |
| 177461 | sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed, SQLITE_TRANSIENT); |
| 177462 | pStr->nUsed--; |
| 177463 | } |
| 177464 | }else{ |
| 177465 | sqlite3_result_text(ctx, "{}", 2, SQLITE_STATIC); |
| 177466 | } |
| @@ -181310,11 +181337,11 @@ | |
| 181310 | ** DROP TABLE <tablename>; -- Would fail with SQLITE_LOCKED |
| 181311 | ** COMMIT; |
| 181312 | */ |
| 181313 | static int rtreeSavepoint(sqlite3_vtab *pVtab, int iSavepoint){ |
| 181314 | Rtree *pRtree = (Rtree *)pVtab; |
| 181315 | int iwt = pRtree->inWrTrans; |
| 181316 | UNUSED_PARAMETER(iSavepoint); |
| 181317 | pRtree->inWrTrans = 0; |
| 181318 | nodeBlobReset(pRtree); |
| 181319 | pRtree->inWrTrans = iwt; |
| 181320 | return SQLITE_OK; |
| @@ -182450,11 +182477,11 @@ | |
| 182450 | continue; |
| 182451 | } |
| 182452 | break; |
| 182453 | } |
| 182454 | if( z[j-1]<'0' ) return 0; |
| 182455 | if( pVal ) *pVal = atof((const char*)p->z); |
| 182456 | p->z += j; |
| 182457 | return 1; |
| 182458 | } |
| 182459 | |
| 182460 | /* |
| @@ -182705,12 +182732,12 @@ | |
| 182705 | int ii; |
| 182706 | if( p ){ |
| 182707 | for(ii=0; ii<p->nVertex; ii++){ |
| 182708 | x0 = p->a[ii*2]; |
| 182709 | y0 = p->a[ii*2+1]; |
| 182710 | x1 = A*x0 + B*y0 + E; |
| 182711 | y1 = C*x0 + D*y0 + F; |
| 182712 | p->a[ii*2] = x1; |
| 182713 | p->a[ii*2+1] = y1; |
| 182714 | } |
| 182715 | sqlite3_result_blob(context, p->hdr, |
| 182716 | 4+8*p->nVertex, SQLITE_TRANSIENT); |
| @@ -182781,15 +182808,15 @@ | |
| 182781 | int ii; |
| 182782 | mnX = mxX = p->a[0]; |
| 182783 | mnY = mxY = p->a[1]; |
| 182784 | for(ii=1; ii<p->nVertex; ii++){ |
| 182785 | double r = p->a[ii*2]; |
| 182786 | if( r<mnX ) mnX = r; |
| 182787 | else if( r>mxX ) mxX = r; |
| 182788 | r = p->a[ii*2+1]; |
| 182789 | if( r<mnY ) mnY = r; |
| 182790 | else if( r>mxY ) mxY = r; |
| 182791 | } |
| 182792 | if( pRc ) *pRc = SQLITE_OK; |
| 182793 | if( aCoord==0 ){ |
| 182794 | geopolyBboxFill: |
| 182795 | pOut = sqlite3_realloc(p, sizeof(GeoPoly)+sizeof(GeoCoord)*6); |
| @@ -197385,11 +197412,11 @@ | |
| 197385 | ** "place". |
| 197386 | ** |
| 197387 | ** This way, even if the tokenizer does not provide synonyms |
| 197388 | ** when tokenizing query text (it should not - to do would be |
| 197389 | ** inefficient), it doesn't matter if the user queries for |
| 197390 | ** 'first + place' or '1st + place', as there are entires in the |
| 197391 | ** FTS index corresponding to both forms of the first token. |
| 197392 | ** </ol> |
| 197393 | ** |
| 197394 | ** Whether it is parsing document or query text, any call to xToken that |
| 197395 | ** specifies a <i>tflags</i> argument with the FTS5_TOKEN_COLOCATED bit |
| @@ -197413,11 +197440,11 @@ | |
| 197413 | ** |
| 197414 | ** In many cases, method (1) above is the best approach. It does not add |
| 197415 | ** extra data to the FTS index or require FTS5 to query for multiple terms, |
| 197416 | ** so it is efficient in terms of disk space and query speed. However, it |
| 197417 | ** does not support prefix queries very well. If, as suggested above, the |
| 197418 | ** token "first" is subsituted for "1st" by the tokenizer, then the query: |
| 197419 | ** |
| 197420 | ** <codeblock> |
| 197421 | ** ... MATCH '1s*'</codeblock> |
| 197422 | ** |
| 197423 | ** will not match documents that contain the token "1st" (as the tokenizer |
| @@ -214387,11 +214414,11 @@ | |
| 214387 | int nArg, /* Number of args */ |
| 214388 | sqlite3_value **apUnused /* Function arguments */ |
| 214389 | ){ |
| 214390 | assert( nArg==0 ); |
| 214391 | UNUSED_PARAM2(nArg, apUnused); |
| 214392 | sqlite3_result_text(pCtx, "fts5: 2018-09-10 16:38:25 564fa75195c5179d0bc86431aaff06136fc65ec63aa9839cd1114b1fbfac928b", -1, SQLITE_TRANSIENT); |
| 214393 | } |
| 214394 | |
| 214395 | static int fts5Init(sqlite3 *db){ |
| 214396 | static const sqlite3_module fts5Mod = { |
| 214397 | /* iVersion */ 2, |
| @@ -219097,12 +219124,12 @@ | |
| 219097 | } |
| 219098 | #endif /* SQLITE_CORE */ |
| 219099 | #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */ |
| 219100 | |
| 219101 | /************** End of stmt.c ************************************************/ |
| 219102 | #if __LINE__!=219102 |
| 219103 | #undef SQLITE_SOURCE_ID |
| 219104 | #define SQLITE_SOURCE_ID "2018-09-10 19:34:06 74c381b573817d0212153278b5ee5d2238a27a727dcf7ee769365c47bb9falt2" |
| 219105 | #endif |
| 219106 | /* Return the source-id for this library */ |
| 219107 | SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } |
| 219108 | /************************** End of sqlite3.c ******************************/ |
| 219109 |
| --- src/sqlite3.c | |
| +++ src/sqlite3.c | |
| @@ -1156,11 +1156,11 @@ | |
| 1156 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 1157 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 1158 | */ |
| 1159 | #define SQLITE_VERSION "3.25.0" |
| 1160 | #define SQLITE_VERSION_NUMBER 3025000 |
| 1161 | #define SQLITE_SOURCE_ID "2018-09-15 04:01:47 b63af6c3bd33152742648d5d2e8dc5d5fcbcdd27df409272b6aea00a6f761760" |
| 1162 | |
| 1163 | /* |
| 1164 | ** CAPI3REF: Run-Time Library Version Numbers |
| 1165 | ** KEYWORDS: sqlite3_version sqlite3_sourceid |
| 1166 | ** |
| @@ -2113,22 +2113,23 @@ | |
| 2113 | ** The [SQLITE_FCNTL_DATA_VERSION] opcode is used to detect changes to |
| 2114 | ** a database file. The argument is a pointer to a 32-bit unsigned integer. |
| 2115 | ** The "data version" for the pager is written into the pointer. The |
| 2116 | ** "data version" changes whenever any change occurs to the corresponding |
| 2117 | ** database file, either through SQL statements on the same database |
| 2118 | ** connection or through transactions committed by separate database |
| 2119 | ** connections possibly in other processes. The [sqlite3_total_changes()] |
| 2120 | ** interface can be used to find if any database on the connection has changed, |
| 2121 | ** but that interface responds to changes on TEMP as well as MAIN and does |
| 2122 | ** not provide a mechanism to detect changes to MAIN only. Also, the |
| 2123 | ** [sqlite3_total_changes()] interface responds to internal changes only and |
| 2124 | ** omits changes made by other database connections. The |
| 2125 | ** [PRAGMA data_version] command provide a mechanism to detect changes to |
| 2126 | ** a single attached database that occur due to other database connections, |
| 2127 | ** but omits changes implemented by the database connection on which it is |
| 2128 | ** called. This file control is the only mechanism to detect changes that |
| 2129 | ** happen either internally or externally and that are associated with |
| 2130 | ** a particular attached database. |
| 2131 | ** </ul> |
| 2132 | */ |
| 2133 | #define SQLITE_FCNTL_LOCKSTATE 1 |
| 2134 | #define SQLITE_FCNTL_GET_LOCKPROXYFILE 2 |
| 2135 | #define SQLITE_FCNTL_SET_LOCKPROXYFILE 3 |
| @@ -5762,11 +5763,11 @@ | |
| 5763 | ** SQL function or aggregate, pass NULL pointers for all three function |
| 5764 | ** callbacks. |
| 5765 | ** |
| 5766 | ** ^The sixth, seventh, eighth and ninth parameters (xStep, xFinal, xValue |
| 5767 | ** and xInverse) passed to sqlite3_create_window_function are pointers to |
| 5768 | ** C-language callbacks that implement the new function. xStep and xFinal |
| 5769 | ** must both be non-NULL. xValue and xInverse may either both be NULL, in |
| 5770 | ** which case a regular aggregate function is created, or must both be |
| 5771 | ** non-NULL, in which case the new function may be used as either an aggregate |
| 5772 | ** or aggregate window function. More details regarding the implementation |
| 5773 | ** of aggregate window functions are |
| @@ -10288,11 +10289,11 @@ | |
| 10289 | ** |
| 10290 | ** The SQLITE_DESERIALIZE_FREEONCLOSE means that the database serialization |
| 10291 | ** in the P argument is held in memory obtained from [sqlite3_malloc64()] |
| 10292 | ** and that SQLite should take ownership of this memory and automatically |
| 10293 | ** free it when it has finished using it. Without this flag, the caller |
| 10294 | ** is responsible for freeing any dynamically allocated memory. |
| 10295 | ** |
| 10296 | ** The SQLITE_DESERIALIZE_RESIZEABLE flag means that SQLite is allowed to |
| 10297 | ** grow the size of the database using calls to [sqlite3_realloc64()]. This |
| 10298 | ** flag should only be used if SQLITE_DESERIALIZE_FREEONCLOSE is also used. |
| 10299 | ** Without this flag, the deserialized database cannot increase in size beyond |
| @@ -12466,11 +12467,11 @@ | |
| 12467 | ** "place". |
| 12468 | ** |
| 12469 | ** This way, even if the tokenizer does not provide synonyms |
| 12470 | ** when tokenizing query text (it should not - to do would be |
| 12471 | ** inefficient), it doesn't matter if the user queries for |
| 12472 | ** 'first + place' or '1st + place', as there are entries in the |
| 12473 | ** FTS index corresponding to both forms of the first token. |
| 12474 | ** </ol> |
| 12475 | ** |
| 12476 | ** Whether it is parsing document or query text, any call to xToken that |
| 12477 | ** specifies a <i>tflags</i> argument with the FTS5_TOKEN_COLOCATED bit |
| @@ -12494,11 +12495,11 @@ | |
| 12495 | ** |
| 12496 | ** In many cases, method (1) above is the best approach. It does not add |
| 12497 | ** extra data to the FTS index or require FTS5 to query for multiple terms, |
| 12498 | ** so it is efficient in terms of disk space and query speed. However, it |
| 12499 | ** does not support prefix queries very well. If, as suggested above, the |
| 12500 | ** token "first" is substituted for "1st" by the tokenizer, then the query: |
| 12501 | ** |
| 12502 | ** <codeblock> |
| 12503 | ** ... MATCH '1s*'</codeblock> |
| 12504 | ** |
| 12505 | ** will not match documents that contain the token "1st" (as the tokenizer |
| @@ -18972,10 +18973,11 @@ | |
| 18973 | SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *, Token *); |
| 18974 | SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *, SrcList *); |
| 18975 | SQLITE_PRIVATE void *sqlite3RenameTokenMap(Parse*, void*, Token*); |
| 18976 | SQLITE_PRIVATE void sqlite3RenameTokenRemap(Parse*, void *pTo, void *pFrom); |
| 18977 | SQLITE_PRIVATE void sqlite3RenameExprUnmap(Parse*, Expr*); |
| 18978 | SQLITE_PRIVATE void sqlite3RenameExprlistUnmap(Parse*, ExprList*); |
| 18979 | SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq(Parse*, u8, CollSeq *, const char*); |
| 18980 | SQLITE_PRIVATE char sqlite3AffinityType(const char*, Column*); |
| 18981 | SQLITE_PRIVATE void sqlite3Analyze(Parse*, Token*, Token*); |
| 18982 | SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler*, sqlite3_file*); |
| 18983 | SQLITE_PRIVATE int sqlite3FindDb(sqlite3*, Token*); |
| @@ -27606,11 +27608,16 @@ | |
| 27608 | bufpt = va_arg(ap,char*); |
| 27609 | } |
| 27610 | if( bufpt==0 ){ |
| 27611 | bufpt = ""; |
| 27612 | }else if( xtype==etDYNSTRING ){ |
| 27613 | if( pAccum->nChar==0 |
| 27614 | && pAccum->mxAlloc |
| 27615 | && width==0 |
| 27616 | && precision<0 |
| 27617 | && pAccum->accError==0 |
| 27618 | ){ |
| 27619 | /* Special optimization for sqlite3_mprintf("%z..."): |
| 27620 | ** Extend an existing memory allocation rather than creating |
| 27621 | ** a new one. */ |
| 27622 | assert( (pAccum->printfFlags&SQLITE_PRINTF_MALLOCED)==0 ); |
| 27623 | pAccum->zText = bufpt; |
| @@ -36968,11 +36975,13 @@ | |
| 36975 | static void unixShmBarrier( |
| 36976 | sqlite3_file *fd /* Database file holding the shared memory */ |
| 36977 | ){ |
| 36978 | UNUSED_PARAMETER(fd); |
| 36979 | sqlite3MemoryBarrier(); /* compiler-defined memory barrier */ |
| 36980 | assert( fd->pMethods->xLock==nolockLock |
| 36981 | || unixFileMutexNotheld((unixFile*)fd) |
| 36982 | ); |
| 36983 | unixEnterMutex(); /* Also mutex, for redundancy */ |
| 36984 | unixLeaveMutex(); |
| 36985 | } |
| 36986 | |
| 36987 | /* |
| @@ -46285,12 +46294,12 @@ | |
| 46294 | ** block of memory. |
| 46295 | ** |
| 46296 | ** This file also implements interface sqlite3_serialize() and |
| 46297 | ** sqlite3_deserialize(). |
| 46298 | */ |
| 46299 | /* #include "sqliteInt.h" */ |
| 46300 | #ifdef SQLITE_ENABLE_DESERIALIZE |
| 46301 | |
| 46302 | /* |
| 46303 | ** Forward declaration of objects used by this utility |
| 46304 | */ |
| 46305 | typedef struct sqlite3_vfs MemVfs; |
| @@ -60507,11 +60516,11 @@ | |
| 60516 | ** Other threads might append new content to the WAL and wal-index but |
| 60517 | ** that extra content is ignored by the current thread. |
| 60518 | ** |
| 60519 | ** If the database contents have changes since the previous read |
| 60520 | ** transaction, then *pChanged is set to 1 before returning. The |
| 60521 | ** Pager layer will use this to know that its cache is stale and |
| 60522 | ** needs to be flushed. |
| 60523 | */ |
| 60524 | SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){ |
| 60525 | int rc; /* Return code */ |
| 60526 | int cnt = 0; /* Number of TryBeginRead attempts */ |
| @@ -78538,11 +78547,11 @@ | |
| 78547 | ** error, then it might not have been halted properly. So halt |
| 78548 | ** it now. |
| 78549 | */ |
| 78550 | sqlite3VdbeHalt(p); |
| 78551 | |
| 78552 | /* If the VDBE has been run even partially, then transfer the error code |
| 78553 | ** and error message from the VDBE into the main database structure. But |
| 78554 | ** if the VDBE has just been set to run but has not actually executed any |
| 78555 | ** instructions yet, leave the main database error information unchanged. |
| 78556 | */ |
| 78557 | if( p->pc>=0 ){ |
| @@ -101161,11 +101170,11 @@ | |
| 101170 | ** bTemp is not true, database "temp", can still be parsed. This is |
| 101171 | ** called at the end of the generation of an ALTER TABLE ... RENAME ... |
| 101172 | ** statement to ensure that the operation has not rendered any schema |
| 101173 | ** objects unusable. |
| 101174 | */ |
| 101175 | static void renameTestSchema(Parse *pParse, const char *zDb, int bTemp){ |
| 101176 | sqlite3NestedParse(pParse, |
| 101177 | "SELECT 1 " |
| 101178 | "FROM \"%w\".%s " |
| 101179 | "WHERE name NOT LIKE 'sqlite_%%'" |
| 101180 | " AND sql NOT LIKE 'create virtual%%'" |
| @@ -101188,11 +101197,11 @@ | |
| 101197 | |
| 101198 | /* |
| 101199 | ** Generate code to reload the schema for database iDb. And, if iDb!=1, for |
| 101200 | ** the temp database as well. |
| 101201 | */ |
| 101202 | static void renameReloadSchema(Parse *pParse, int iDb){ |
| 101203 | Vdbe *v = pParse->pVdbe; |
| 101204 | if( v ){ |
| 101205 | sqlite3ChangeCookie(pParse, iDb); |
| 101206 | sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, iDb, 0); |
| 101207 | if( iDb!=1 ) sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, 1, 0); |
| @@ -101768,11 +101777,11 @@ | |
| 101777 | ** if( x==y ) ... |
| 101778 | ** |
| 101779 | ** Technically, as x no longer points into a valid object or to the byte |
| 101780 | ** following a valid object, it may not be used in comparison operations. |
| 101781 | */ |
| 101782 | static void renameTokenCheckAll(Parse *pParse, void *pPtr){ |
| 101783 | if( pParse->nErr==0 && pParse->db->mallocFailed==0 ){ |
| 101784 | RenameToken *p; |
| 101785 | u8 i = 0; |
| 101786 | for(p=pParse->pRename; p; p=p->pNext){ |
| 101787 | if( p->p ){ |
| @@ -101840,10 +101849,28 @@ | |
| 101849 | memset(&sWalker, 0, sizeof(Walker)); |
| 101850 | sWalker.pParse = pParse; |
| 101851 | sWalker.xExprCallback = renameUnmapExprCb; |
| 101852 | sqlite3WalkExpr(&sWalker, pExpr); |
| 101853 | } |
| 101854 | |
| 101855 | /* |
| 101856 | ** Remove all nodes that are part of expression-list pEList from the |
| 101857 | ** rename list. |
| 101858 | */ |
| 101859 | SQLITE_PRIVATE void sqlite3RenameExprlistUnmap(Parse *pParse, ExprList *pEList){ |
| 101860 | if( pEList ){ |
| 101861 | int i; |
| 101862 | Walker sWalker; |
| 101863 | memset(&sWalker, 0, sizeof(Walker)); |
| 101864 | sWalker.pParse = pParse; |
| 101865 | sWalker.xExprCallback = renameUnmapExprCb; |
| 101866 | sqlite3WalkExprList(&sWalker, pEList); |
| 101867 | for(i=0; i<pEList->nExpr; i++){ |
| 101868 | sqlite3RenameTokenRemap(pParse, 0, (void*)pEList->a[i].zName); |
| 101869 | } |
| 101870 | } |
| 101871 | } |
| 101872 | |
| 101873 | /* |
| 101874 | ** Free the list of RenameToken objects given in the second argument |
| 101875 | */ |
| 101876 | static void renameTokenFree(sqlite3 *db, RenameToken *pToken){ |
| @@ -107746,10 +107773,13 @@ | |
| 107773 | /* Use sqlite3EndTable() to add the view to the SQLITE_MASTER table */ |
| 107774 | sqlite3EndTable(pParse, 0, &sEnd, 0, 0); |
| 107775 | |
| 107776 | create_view_fail: |
| 107777 | sqlite3SelectDelete(db, pSelect); |
| 107778 | if( IN_RENAME_OBJECT ){ |
| 107779 | sqlite3RenameExprlistUnmap(pParse, pCNames); |
| 107780 | } |
| 107781 | sqlite3ExprListDelete(db, pCNames); |
| 107782 | return; |
| 107783 | } |
| 107784 | #endif /* SQLITE_OMIT_VIEW */ |
| 107785 | |
| @@ -135329,15 +135359,12 @@ | |
| 135359 | static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){ |
| 135360 | int rc = WRC_Continue; |
| 135361 | struct CCurHint *pHint = pWalker->u.pCCurHint; |
| 135362 | if( pExpr->op==TK_COLUMN ){ |
| 135363 | if( pExpr->iTable!=pHint->iTabCur ){ |
| 135364 | int reg = ++pWalker->pParse->nMem; /* Register for column value */ |
| 135365 | sqlite3ExprCode(pWalker->pParse, pExpr, reg); |
| 135366 | pExpr->op = TK_REGISTER; |
| 135367 | pExpr->iTable = reg; |
| 135368 | }else if( pHint->pIdx!=0 ){ |
| 135369 | pExpr->iTable = pHint->iIdxCur; |
| 135370 | pExpr->iColumn = sqlite3ColumnOfIndex(pHint->pIdx, pExpr->iColumn); |
| @@ -177353,15 +177380,15 @@ | |
| 177380 | jsonAppendChar(pStr, ']'); |
| 177381 | if( pStr->bErr ){ |
| 177382 | if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx); |
| 177383 | assert( pStr->bStatic ); |
| 177384 | }else if( isFinal ){ |
| 177385 | sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, |
| 177386 | pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free); |
| 177387 | pStr->bStatic = 1; |
| 177388 | }else{ |
| 177389 | sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT); |
| 177390 | pStr->nUsed--; |
| 177391 | } |
| 177392 | }else{ |
| 177393 | sqlite3_result_text(ctx, "[]", 2, SQLITE_STATIC); |
| 177394 | } |
| @@ -177406,11 +177433,11 @@ | |
| 177433 | }else if( z[i]=='\\' ){ |
| 177434 | i++; |
| 177435 | } |
| 177436 | } |
| 177437 | pStr->nUsed -= i; |
| 177438 | memmove(&z[1], &z[i+1], (size_t)pStr->nUsed-1); |
| 177439 | } |
| 177440 | #else |
| 177441 | # define jsonGroupInverse 0 |
| 177442 | #endif |
| 177443 | |
| @@ -177452,15 +177479,15 @@ | |
| 177479 | jsonAppendChar(pStr, '}'); |
| 177480 | if( pStr->bErr ){ |
| 177481 | if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx); |
| 177482 | assert( pStr->bStatic ); |
| 177483 | }else if( isFinal ){ |
| 177484 | sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, |
| 177485 | pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free); |
| 177486 | pStr->bStatic = 1; |
| 177487 | }else{ |
| 177488 | sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT); |
| 177489 | pStr->nUsed--; |
| 177490 | } |
| 177491 | }else{ |
| 177492 | sqlite3_result_text(ctx, "{}", 2, SQLITE_STATIC); |
| 177493 | } |
| @@ -181310,11 +181337,11 @@ | |
| 181337 | ** DROP TABLE <tablename>; -- Would fail with SQLITE_LOCKED |
| 181338 | ** COMMIT; |
| 181339 | */ |
| 181340 | static int rtreeSavepoint(sqlite3_vtab *pVtab, int iSavepoint){ |
| 181341 | Rtree *pRtree = (Rtree *)pVtab; |
| 181342 | u8 iwt = pRtree->inWrTrans; |
| 181343 | UNUSED_PARAMETER(iSavepoint); |
| 181344 | pRtree->inWrTrans = 0; |
| 181345 | nodeBlobReset(pRtree); |
| 181346 | pRtree->inWrTrans = iwt; |
| 181347 | return SQLITE_OK; |
| @@ -182450,11 +182477,11 @@ | |
| 182477 | continue; |
| 182478 | } |
| 182479 | break; |
| 182480 | } |
| 182481 | if( z[j-1]<'0' ) return 0; |
| 182482 | if( pVal ) *pVal = (GeoCoord)atof((const char*)p->z); |
| 182483 | p->z += j; |
| 182484 | return 1; |
| 182485 | } |
| 182486 | |
| 182487 | /* |
| @@ -182705,12 +182732,12 @@ | |
| 182732 | int ii; |
| 182733 | if( p ){ |
| 182734 | for(ii=0; ii<p->nVertex; ii++){ |
| 182735 | x0 = p->a[ii*2]; |
| 182736 | y0 = p->a[ii*2+1]; |
| 182737 | x1 = (GeoCoord)(A*x0 + B*y0 + E); |
| 182738 | y1 = (GeoCoord)(C*x0 + D*y0 + F); |
| 182739 | p->a[ii*2] = x1; |
| 182740 | p->a[ii*2+1] = y1; |
| 182741 | } |
| 182742 | sqlite3_result_blob(context, p->hdr, |
| 182743 | 4+8*p->nVertex, SQLITE_TRANSIENT); |
| @@ -182781,15 +182808,15 @@ | |
| 182808 | int ii; |
| 182809 | mnX = mxX = p->a[0]; |
| 182810 | mnY = mxY = p->a[1]; |
| 182811 | for(ii=1; ii<p->nVertex; ii++){ |
| 182812 | double r = p->a[ii*2]; |
| 182813 | if( r<mnX ) mnX = (float)r; |
| 182814 | else if( r>mxX ) mxX = (float)r; |
| 182815 | r = p->a[ii*2+1]; |
| 182816 | if( r<mnY ) mnY = (float)r; |
| 182817 | else if( r>mxY ) mxY = (float)r; |
| 182818 | } |
| 182819 | if( pRc ) *pRc = SQLITE_OK; |
| 182820 | if( aCoord==0 ){ |
| 182821 | geopolyBboxFill: |
| 182822 | pOut = sqlite3_realloc(p, sizeof(GeoPoly)+sizeof(GeoCoord)*6); |
| @@ -197385,11 +197412,11 @@ | |
| 197412 | ** "place". |
| 197413 | ** |
| 197414 | ** This way, even if the tokenizer does not provide synonyms |
| 197415 | ** when tokenizing query text (it should not - to do would be |
| 197416 | ** inefficient), it doesn't matter if the user queries for |
| 197417 | ** 'first + place' or '1st + place', as there are entries in the |
| 197418 | ** FTS index corresponding to both forms of the first token. |
| 197419 | ** </ol> |
| 197420 | ** |
| 197421 | ** Whether it is parsing document or query text, any call to xToken that |
| 197422 | ** specifies a <i>tflags</i> argument with the FTS5_TOKEN_COLOCATED bit |
| @@ -197413,11 +197440,11 @@ | |
| 197440 | ** |
| 197441 | ** In many cases, method (1) above is the best approach. It does not add |
| 197442 | ** extra data to the FTS index or require FTS5 to query for multiple terms, |
| 197443 | ** so it is efficient in terms of disk space and query speed. However, it |
| 197444 | ** does not support prefix queries very well. If, as suggested above, the |
| 197445 | ** token "first" is substituted for "1st" by the tokenizer, then the query: |
| 197446 | ** |
| 197447 | ** <codeblock> |
| 197448 | ** ... MATCH '1s*'</codeblock> |
| 197449 | ** |
| 197450 | ** will not match documents that contain the token "1st" (as the tokenizer |
| @@ -214387,11 +214414,11 @@ | |
| 214414 | int nArg, /* Number of args */ |
| 214415 | sqlite3_value **apUnused /* Function arguments */ |
| 214416 | ){ |
| 214417 | assert( nArg==0 ); |
| 214418 | UNUSED_PARAM2(nArg, apUnused); |
| 214419 | sqlite3_result_text(pCtx, "fts5: 2018-09-15 04:01:47 b63af6c3bd33152742648d5d2e8dc5d5fcbcdd27df409272b6aea00a6f761760", -1, SQLITE_TRANSIENT); |
| 214420 | } |
| 214421 | |
| 214422 | static int fts5Init(sqlite3 *db){ |
| 214423 | static const sqlite3_module fts5Mod = { |
| 214424 | /* iVersion */ 2, |
| @@ -219097,12 +219124,12 @@ | |
| 219124 | } |
| 219125 | #endif /* SQLITE_CORE */ |
| 219126 | #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */ |
| 219127 | |
| 219128 | /************** End of stmt.c ************************************************/ |
| 219129 | #if __LINE__!=219129 |
| 219130 | #undef SQLITE_SOURCE_ID |
| 219131 | #define SQLITE_SOURCE_ID "2018-09-15 04:01:47 b63af6c3bd33152742648d5d2e8dc5d5fcbcdd27df409272b6aea00a6f76alt2" |
| 219132 | #endif |
| 219133 | /* Return the source-id for this library */ |
| 219134 | SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } |
| 219135 | /************************** End of sqlite3.c ******************************/ |
| 219136 |
+11
-10
| --- src/sqlite3.h | ||
| +++ src/sqlite3.h | ||
| @@ -123,11 +123,11 @@ | ||
| 123 | 123 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 124 | 124 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 125 | 125 | */ |
| 126 | 126 | #define SQLITE_VERSION "3.25.0" |
| 127 | 127 | #define SQLITE_VERSION_NUMBER 3025000 |
| 128 | -#define SQLITE_SOURCE_ID "2018-09-10 19:34:06 74c381b573817d0212153278b5ee5d2238a27a727dcf7ee769365c47bb9fc40d" | |
| 128 | +#define SQLITE_SOURCE_ID "2018-09-15 04:01:47 b63af6c3bd33152742648d5d2e8dc5d5fcbcdd27df409272b6aea00a6f761760" | |
| 129 | 129 | |
| 130 | 130 | /* |
| 131 | 131 | ** CAPI3REF: Run-Time Library Version Numbers |
| 132 | 132 | ** KEYWORDS: sqlite3_version sqlite3_sourceid |
| 133 | 133 | ** |
| @@ -1080,22 +1080,23 @@ | ||
| 1080 | 1080 | ** The [SQLITE_FCNTL_DATA_VERSION] opcode is used to detect changes to |
| 1081 | 1081 | ** a database file. The argument is a pointer to a 32-bit unsigned integer. |
| 1082 | 1082 | ** The "data version" for the pager is written into the pointer. The |
| 1083 | 1083 | ** "data version" changes whenever any change occurs to the corresponding |
| 1084 | 1084 | ** database file, either through SQL statements on the same database |
| 1085 | -** connection, or through transactions committed by separate database | |
| 1085 | +** connection or through transactions committed by separate database | |
| 1086 | 1086 | ** connections possibly in other processes. The [sqlite3_total_changes()] |
| 1087 | 1087 | ** interface can be used to find if any database on the connection has changed, |
| 1088 | -** but that interface response to changes on TEMP as well as MAIN and does | |
| 1088 | +** but that interface responds to changes on TEMP as well as MAIN and does | |
| 1089 | 1089 | ** not provide a mechanism to detect changes to MAIN only. Also, the |
| 1090 | -** [sqlite3_total_changes()] interface response to internal changes only and | |
| 1090 | +** [sqlite3_total_changes()] interface responds to internal changes only and | |
| 1091 | 1091 | ** omits changes made by other database connections. The |
| 1092 | 1092 | ** [PRAGMA data_version] command provide a mechanism to detect changes to |
| 1093 | 1093 | ** a single attached database that occur due to other database connections, |
| 1094 | -** but omits changes implemented by the database connection for which it is | |
| 1094 | +** but omits changes implemented by the database connection on which it is | |
| 1095 | 1095 | ** called. This file control is the only mechanism to detect changes that |
| 1096 | -** happen either internally or externally on a single database. | |
| 1096 | +** happen either internally or externally and that are associated with | |
| 1097 | +** a particular attached database. | |
| 1097 | 1098 | ** </ul> |
| 1098 | 1099 | */ |
| 1099 | 1100 | #define SQLITE_FCNTL_LOCKSTATE 1 |
| 1100 | 1101 | #define SQLITE_FCNTL_GET_LOCKPROXYFILE 2 |
| 1101 | 1102 | #define SQLITE_FCNTL_SET_LOCKPROXYFILE 3 |
| @@ -4729,11 +4730,11 @@ | ||
| 4729 | 4730 | ** SQL function or aggregate, pass NULL pointers for all three function |
| 4730 | 4731 | ** callbacks. |
| 4731 | 4732 | ** |
| 4732 | 4733 | ** ^The sixth, seventh, eighth and ninth parameters (xStep, xFinal, xValue |
| 4733 | 4734 | ** and xInverse) passed to sqlite3_create_window_function are pointers to |
| 4734 | -** C-lanugage callbacks that implement the new function. xStep and xFinal | |
| 4735 | +** C-language callbacks that implement the new function. xStep and xFinal | |
| 4735 | 4736 | ** must both be non-NULL. xValue and xInverse may either both be NULL, in |
| 4736 | 4737 | ** which case a regular aggregate function is created, or must both be |
| 4737 | 4738 | ** non-NULL, in which case the new function may be used as either an aggregate |
| 4738 | 4739 | ** or aggregate window function. More details regarding the implementation |
| 4739 | 4740 | ** of aggregate window functions are |
| @@ -9255,11 +9256,11 @@ | ||
| 9255 | 9256 | ** |
| 9256 | 9257 | ** The SQLITE_DESERIALIZE_FREEONCLOSE means that the database serialization |
| 9257 | 9258 | ** in the P argument is held in memory obtained from [sqlite3_malloc64()] |
| 9258 | 9259 | ** and that SQLite should take ownership of this memory and automatically |
| 9259 | 9260 | ** free it when it has finished using it. Without this flag, the caller |
| 9260 | -** is resposible for freeing any dynamically allocated memory. | |
| 9261 | +** is responsible for freeing any dynamically allocated memory. | |
| 9261 | 9262 | ** |
| 9262 | 9263 | ** The SQLITE_DESERIALIZE_RESIZEABLE flag means that SQLite is allowed to |
| 9263 | 9264 | ** grow the size of the database using calls to [sqlite3_realloc64()]. This |
| 9264 | 9265 | ** flag should only be used if SQLITE_DESERIALIZE_FREEONCLOSE is also used. |
| 9265 | 9266 | ** Without this flag, the deserialized database cannot increase in size beyond |
| @@ -11433,11 +11434,11 @@ | ||
| 11433 | 11434 | ** "place". |
| 11434 | 11435 | ** |
| 11435 | 11436 | ** This way, even if the tokenizer does not provide synonyms |
| 11436 | 11437 | ** when tokenizing query text (it should not - to do would be |
| 11437 | 11438 | ** inefficient), it doesn't matter if the user queries for |
| 11438 | -** 'first + place' or '1st + place', as there are entires in the | |
| 11439 | +** 'first + place' or '1st + place', as there are entries in the | |
| 11439 | 11440 | ** FTS index corresponding to both forms of the first token. |
| 11440 | 11441 | ** </ol> |
| 11441 | 11442 | ** |
| 11442 | 11443 | ** Whether it is parsing document or query text, any call to xToken that |
| 11443 | 11444 | ** specifies a <i>tflags</i> argument with the FTS5_TOKEN_COLOCATED bit |
| @@ -11461,11 +11462,11 @@ | ||
| 11461 | 11462 | ** |
| 11462 | 11463 | ** In many cases, method (1) above is the best approach. It does not add |
| 11463 | 11464 | ** extra data to the FTS index or require FTS5 to query for multiple terms, |
| 11464 | 11465 | ** so it is efficient in terms of disk space and query speed. However, it |
| 11465 | 11466 | ** does not support prefix queries very well. If, as suggested above, the |
| 11466 | -** token "first" is subsituted for "1st" by the tokenizer, then the query: | |
| 11467 | +** token "first" is substituted for "1st" by the tokenizer, then the query: | |
| 11467 | 11468 | ** |
| 11468 | 11469 | ** <codeblock> |
| 11469 | 11470 | ** ... MATCH '1s*'</codeblock> |
| 11470 | 11471 | ** |
| 11471 | 11472 | ** will not match documents that contain the token "1st" (as the tokenizer |
| 11472 | 11473 |
| --- src/sqlite3.h | |
| +++ src/sqlite3.h | |
| @@ -123,11 +123,11 @@ | |
| 123 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 124 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 125 | */ |
| 126 | #define SQLITE_VERSION "3.25.0" |
| 127 | #define SQLITE_VERSION_NUMBER 3025000 |
| 128 | #define SQLITE_SOURCE_ID "2018-09-10 19:34:06 74c381b573817d0212153278b5ee5d2238a27a727dcf7ee769365c47bb9fc40d" |
| 129 | |
| 130 | /* |
| 131 | ** CAPI3REF: Run-Time Library Version Numbers |
| 132 | ** KEYWORDS: sqlite3_version sqlite3_sourceid |
| 133 | ** |
| @@ -1080,22 +1080,23 @@ | |
| 1080 | ** The [SQLITE_FCNTL_DATA_VERSION] opcode is used to detect changes to |
| 1081 | ** a database file. The argument is a pointer to a 32-bit unsigned integer. |
| 1082 | ** The "data version" for the pager is written into the pointer. The |
| 1083 | ** "data version" changes whenever any change occurs to the corresponding |
| 1084 | ** database file, either through SQL statements on the same database |
| 1085 | ** connection, or through transactions committed by separate database |
| 1086 | ** connections possibly in other processes. The [sqlite3_total_changes()] |
| 1087 | ** interface can be used to find if any database on the connection has changed, |
| 1088 | ** but that interface response to changes on TEMP as well as MAIN and does |
| 1089 | ** not provide a mechanism to detect changes to MAIN only. Also, the |
| 1090 | ** [sqlite3_total_changes()] interface response to internal changes only and |
| 1091 | ** omits changes made by other database connections. The |
| 1092 | ** [PRAGMA data_version] command provide a mechanism to detect changes to |
| 1093 | ** a single attached database that occur due to other database connections, |
| 1094 | ** but omits changes implemented by the database connection for which it is |
| 1095 | ** called. This file control is the only mechanism to detect changes that |
| 1096 | ** happen either internally or externally on a single database. |
| 1097 | ** </ul> |
| 1098 | */ |
| 1099 | #define SQLITE_FCNTL_LOCKSTATE 1 |
| 1100 | #define SQLITE_FCNTL_GET_LOCKPROXYFILE 2 |
| 1101 | #define SQLITE_FCNTL_SET_LOCKPROXYFILE 3 |
| @@ -4729,11 +4730,11 @@ | |
| 4729 | ** SQL function or aggregate, pass NULL pointers for all three function |
| 4730 | ** callbacks. |
| 4731 | ** |
| 4732 | ** ^The sixth, seventh, eighth and ninth parameters (xStep, xFinal, xValue |
| 4733 | ** and xInverse) passed to sqlite3_create_window_function are pointers to |
| 4734 | ** C-lanugage callbacks that implement the new function. xStep and xFinal |
| 4735 | ** must both be non-NULL. xValue and xInverse may either both be NULL, in |
| 4736 | ** which case a regular aggregate function is created, or must both be |
| 4737 | ** non-NULL, in which case the new function may be used as either an aggregate |
| 4738 | ** or aggregate window function. More details regarding the implementation |
| 4739 | ** of aggregate window functions are |
| @@ -9255,11 +9256,11 @@ | |
| 9255 | ** |
| 9256 | ** The SQLITE_DESERIALIZE_FREEONCLOSE means that the database serialization |
| 9257 | ** in the P argument is held in memory obtained from [sqlite3_malloc64()] |
| 9258 | ** and that SQLite should take ownership of this memory and automatically |
| 9259 | ** free it when it has finished using it. Without this flag, the caller |
| 9260 | ** is resposible for freeing any dynamically allocated memory. |
| 9261 | ** |
| 9262 | ** The SQLITE_DESERIALIZE_RESIZEABLE flag means that SQLite is allowed to |
| 9263 | ** grow the size of the database using calls to [sqlite3_realloc64()]. This |
| 9264 | ** flag should only be used if SQLITE_DESERIALIZE_FREEONCLOSE is also used. |
| 9265 | ** Without this flag, the deserialized database cannot increase in size beyond |
| @@ -11433,11 +11434,11 @@ | |
| 11433 | ** "place". |
| 11434 | ** |
| 11435 | ** This way, even if the tokenizer does not provide synonyms |
| 11436 | ** when tokenizing query text (it should not - to do would be |
| 11437 | ** inefficient), it doesn't matter if the user queries for |
| 11438 | ** 'first + place' or '1st + place', as there are entires in the |
| 11439 | ** FTS index corresponding to both forms of the first token. |
| 11440 | ** </ol> |
| 11441 | ** |
| 11442 | ** Whether it is parsing document or query text, any call to xToken that |
| 11443 | ** specifies a <i>tflags</i> argument with the FTS5_TOKEN_COLOCATED bit |
| @@ -11461,11 +11462,11 @@ | |
| 11461 | ** |
| 11462 | ** In many cases, method (1) above is the best approach. It does not add |
| 11463 | ** extra data to the FTS index or require FTS5 to query for multiple terms, |
| 11464 | ** so it is efficient in terms of disk space and query speed. However, it |
| 11465 | ** does not support prefix queries very well. If, as suggested above, the |
| 11466 | ** token "first" is subsituted for "1st" by the tokenizer, then the query: |
| 11467 | ** |
| 11468 | ** <codeblock> |
| 11469 | ** ... MATCH '1s*'</codeblock> |
| 11470 | ** |
| 11471 | ** will not match documents that contain the token "1st" (as the tokenizer |
| 11472 |
| --- src/sqlite3.h | |
| +++ src/sqlite3.h | |
| @@ -123,11 +123,11 @@ | |
| 123 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 124 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 125 | */ |
| 126 | #define SQLITE_VERSION "3.25.0" |
| 127 | #define SQLITE_VERSION_NUMBER 3025000 |
| 128 | #define SQLITE_SOURCE_ID "2018-09-15 04:01:47 b63af6c3bd33152742648d5d2e8dc5d5fcbcdd27df409272b6aea00a6f761760" |
| 129 | |
| 130 | /* |
| 131 | ** CAPI3REF: Run-Time Library Version Numbers |
| 132 | ** KEYWORDS: sqlite3_version sqlite3_sourceid |
| 133 | ** |
| @@ -1080,22 +1080,23 @@ | |
| 1080 | ** The [SQLITE_FCNTL_DATA_VERSION] opcode is used to detect changes to |
| 1081 | ** a database file. The argument is a pointer to a 32-bit unsigned integer. |
| 1082 | ** The "data version" for the pager is written into the pointer. The |
| 1083 | ** "data version" changes whenever any change occurs to the corresponding |
| 1084 | ** database file, either through SQL statements on the same database |
| 1085 | ** connection or through transactions committed by separate database |
| 1086 | ** connections possibly in other processes. The [sqlite3_total_changes()] |
| 1087 | ** interface can be used to find if any database on the connection has changed, |
| 1088 | ** but that interface responds to changes on TEMP as well as MAIN and does |
| 1089 | ** not provide a mechanism to detect changes to MAIN only. Also, the |
| 1090 | ** [sqlite3_total_changes()] interface responds to internal changes only and |
| 1091 | ** omits changes made by other database connections. The |
| 1092 | ** [PRAGMA data_version] command provide a mechanism to detect changes to |
| 1093 | ** a single attached database that occur due to other database connections, |
| 1094 | ** but omits changes implemented by the database connection on which it is |
| 1095 | ** called. This file control is the only mechanism to detect changes that |
| 1096 | ** happen either internally or externally and that are associated with |
| 1097 | ** a particular attached database. |
| 1098 | ** </ul> |
| 1099 | */ |
| 1100 | #define SQLITE_FCNTL_LOCKSTATE 1 |
| 1101 | #define SQLITE_FCNTL_GET_LOCKPROXYFILE 2 |
| 1102 | #define SQLITE_FCNTL_SET_LOCKPROXYFILE 3 |
| @@ -4729,11 +4730,11 @@ | |
| 4730 | ** SQL function or aggregate, pass NULL pointers for all three function |
| 4731 | ** callbacks. |
| 4732 | ** |
| 4733 | ** ^The sixth, seventh, eighth and ninth parameters (xStep, xFinal, xValue |
| 4734 | ** and xInverse) passed to sqlite3_create_window_function are pointers to |
| 4735 | ** C-language callbacks that implement the new function. xStep and xFinal |
| 4736 | ** must both be non-NULL. xValue and xInverse may either both be NULL, in |
| 4737 | ** which case a regular aggregate function is created, or must both be |
| 4738 | ** non-NULL, in which case the new function may be used as either an aggregate |
| 4739 | ** or aggregate window function. More details regarding the implementation |
| 4740 | ** of aggregate window functions are |
| @@ -9255,11 +9256,11 @@ | |
| 9256 | ** |
| 9257 | ** The SQLITE_DESERIALIZE_FREEONCLOSE means that the database serialization |
| 9258 | ** in the P argument is held in memory obtained from [sqlite3_malloc64()] |
| 9259 | ** and that SQLite should take ownership of this memory and automatically |
| 9260 | ** free it when it has finished using it. Without this flag, the caller |
| 9261 | ** is responsible for freeing any dynamically allocated memory. |
| 9262 | ** |
| 9263 | ** The SQLITE_DESERIALIZE_RESIZEABLE flag means that SQLite is allowed to |
| 9264 | ** grow the size of the database using calls to [sqlite3_realloc64()]. This |
| 9265 | ** flag should only be used if SQLITE_DESERIALIZE_FREEONCLOSE is also used. |
| 9266 | ** Without this flag, the deserialized database cannot increase in size beyond |
| @@ -11433,11 +11434,11 @@ | |
| 11434 | ** "place". |
| 11435 | ** |
| 11436 | ** This way, even if the tokenizer does not provide synonyms |
| 11437 | ** when tokenizing query text (it should not - to do would be |
| 11438 | ** inefficient), it doesn't matter if the user queries for |
| 11439 | ** 'first + place' or '1st + place', as there are entries in the |
| 11440 | ** FTS index corresponding to both forms of the first token. |
| 11441 | ** </ol> |
| 11442 | ** |
| 11443 | ** Whether it is parsing document or query text, any call to xToken that |
| 11444 | ** specifies a <i>tflags</i> argument with the FTS5_TOKEN_COLOCATED bit |
| @@ -11461,11 +11462,11 @@ | |
| 11462 | ** |
| 11463 | ** In many cases, method (1) above is the best approach. It does not add |
| 11464 | ** extra data to the FTS index or require FTS5 to query for multiple terms, |
| 11465 | ** so it is efficient in terms of disk space and query speed. However, it |
| 11466 | ** does not support prefix queries very well. If, as suggested above, the |
| 11467 | ** token "first" is substituted for "1st" by the tokenizer, then the query: |
| 11468 | ** |
| 11469 | ** <codeblock> |
| 11470 | ** ... MATCH '1s*'</codeblock> |
| 11471 | ** |
| 11472 | ** will not match documents that contain the token "1st" (as the tokenizer |
| 11473 |
+5
-5
| --- win/Makefile.PellesCGMake | ||
| +++ win/Makefile.PellesCGMake | ||
| @@ -184,14 +184,14 @@ | ||
| 184 | 184 | |
| 185 | 185 | # cleanup |
| 186 | 186 | |
| 187 | 187 | .PHONY: clean |
| 188 | 188 | clean: |
| 189 | - del /F $(TRANSLATEDOBJ) $(SQLITEOBJ) $(THOBJ) $(ZLIBOBJ) $(UTILS_OBJ) version.obj | |
| 190 | - del /F $(TRANSLATEDSRC) | |
| 191 | - del /F *.h headers | |
| 192 | - del /F $(RESOURCE) | |
| 189 | + -del /F $(TRANSLATEDOBJ) $(SQLITEOBJ) $(THOBJ) $(ZLIBOBJ) $(UTILS_OBJ) version.obj | |
| 190 | + -del /F $(TRANSLATEDSRC) | |
| 191 | + -del /F *.h headers | |
| 192 | + -del /F $(RESOURCE) | |
| 193 | 193 | |
| 194 | 194 | .PHONY: clobber |
| 195 | 195 | clobber: clean |
| 196 | - del /F *.exe | |
| 196 | + -del /F *.exe | |
| 197 | 197 | |
| 198 | 198 |
| --- win/Makefile.PellesCGMake | |
| +++ win/Makefile.PellesCGMake | |
| @@ -184,14 +184,14 @@ | |
| 184 | |
| 185 | # cleanup |
| 186 | |
| 187 | .PHONY: clean |
| 188 | clean: |
| 189 | del /F $(TRANSLATEDOBJ) $(SQLITEOBJ) $(THOBJ) $(ZLIBOBJ) $(UTILS_OBJ) version.obj |
| 190 | del /F $(TRANSLATEDSRC) |
| 191 | del /F *.h headers |
| 192 | del /F $(RESOURCE) |
| 193 | |
| 194 | .PHONY: clobber |
| 195 | clobber: clean |
| 196 | del /F *.exe |
| 197 | |
| 198 |
| --- win/Makefile.PellesCGMake | |
| +++ win/Makefile.PellesCGMake | |
| @@ -184,14 +184,14 @@ | |
| 184 | |
| 185 | # cleanup |
| 186 | |
| 187 | .PHONY: clean |
| 188 | clean: |
| 189 | -del /F $(TRANSLATEDOBJ) $(SQLITEOBJ) $(THOBJ) $(ZLIBOBJ) $(UTILS_OBJ) version.obj |
| 190 | -del /F $(TRANSLATEDSRC) |
| 191 | -del /F *.h headers |
| 192 | -del /F $(RESOURCE) |
| 193 | |
| 194 | .PHONY: clobber |
| 195 | clobber: clean |
| 196 | -del /F *.exe |
| 197 | |
| 198 |
+28
-28
| --- win/Makefile.msc | ||
| +++ win/Makefile.msc | ||
| @@ -1022,40 +1022,40 @@ | ||
| 1022 | 1022 | |
| 1023 | 1023 | "$(OX)\builtin_data.h": "$(OBJDIR)\mkbuiltin$E" "$(OX)\builtin_data.reslist" |
| 1024 | 1024 | "$(OBJDIR)\mkbuiltin$E" --prefix "$(SRCDIR)/" --reslist "$(OX)\builtin_data.reslist" > $@ |
| 1025 | 1025 | |
| 1026 | 1026 | cleanx: |
| 1027 | - del "$(OX)\*.obj" 2>NUL | |
| 1028 | - del "$(OBJDIR)\*.obj" 2>NUL | |
| 1029 | - del "$(OX)\*_.c" 2>NUL | |
| 1030 | - del "$(OX)\*.h" 2>NUL | |
| 1031 | - del "$(OX)\*.ilk" 2>NUL | |
| 1032 | - del "$(OX)\*.map" 2>NUL | |
| 1033 | - del "$(OX)\*.res" 2>NUL | |
| 1034 | - del "$(OX)\*.reslist" 2>NUL | |
| 1035 | - del "$(OX)\headers" 2>NUL | |
| 1036 | - del "$(OX)\linkopts" 2>NUL | |
| 1037 | - del "$(OX)\vc*.pdb" 2>NUL | |
| 1027 | + -del "$(OX)\*.obj" 2>NUL | |
| 1028 | + -del "$(OBJDIR)\*.obj" 2>NUL | |
| 1029 | + -del "$(OX)\*_.c" 2>NUL | |
| 1030 | + -del "$(OX)\*.h" 2>NUL | |
| 1031 | + -del "$(OX)\*.ilk" 2>NUL | |
| 1032 | + -del "$(OX)\*.map" 2>NUL | |
| 1033 | + -del "$(OX)\*.res" 2>NUL | |
| 1034 | + -del "$(OX)\*.reslist" 2>NUL | |
| 1035 | + -del "$(OX)\headers" 2>NUL | |
| 1036 | + -del "$(OX)\linkopts" 2>NUL | |
| 1037 | + -del "$(OX)\vc*.pdb" 2>NUL | |
| 1038 | 1038 | |
| 1039 | 1039 | clean: cleanx |
| 1040 | - del "$(APPNAME)" 2>NUL | |
| 1041 | - del "$(PDBNAME)" 2>NUL | |
| 1042 | - del "$(APPMANIFEST)" 2>NUL | |
| 1043 | - del "$(OBJDIR)\translate$E" 2>NUL | |
| 1044 | - del "$(OBJDIR)\translate$P" 2>NUL | |
| 1045 | - del "$(OBJDIR)\mkindex$E" 2>NUL | |
| 1046 | - del "$(OBJDIR)\mkindex$P" 2>NUL | |
| 1047 | - del "$(OBJDIR)\makeheaders$E" 2>NUL | |
| 1048 | - del "$(OBJDIR)\makeheaders$P" 2>NUL | |
| 1049 | - del "$(OBJDIR)\mkversion$E" 2>NUL | |
| 1050 | - del "$(OBJDIR)\mkversion$P" 2>NUL | |
| 1051 | - del "$(OBJDIR)\mkcss$E" 2>NUL | |
| 1052 | - del "$(OBJDIR)\mkcss$P" 2>NUL | |
| 1053 | - del "$(OBJDIR)\codecheck1$E" 2>NUL | |
| 1054 | - del "$(OBJDIR)\codecheck1$P" 2>NUL | |
| 1055 | - del "$(OBJDIR)\mkbuiltin$E" 2>NUL | |
| 1056 | - del "$(OBJDIR)\mkbuiltin$P" 2>NUL | |
| 1040 | + -del "$(APPNAME)" 2>NUL | |
| 1041 | + -del "$(PDBNAME)" 2>NUL | |
| 1042 | + -del "$(APPMANIFEST)" 2>NUL | |
| 1043 | + -del "$(OBJDIR)\translate$E" 2>NUL | |
| 1044 | + -del "$(OBJDIR)\translate$P" 2>NUL | |
| 1045 | + -del "$(OBJDIR)\mkindex$E" 2>NUL | |
| 1046 | + -del "$(OBJDIR)\mkindex$P" 2>NUL | |
| 1047 | + -del "$(OBJDIR)\makeheaders$E" 2>NUL | |
| 1048 | + -del "$(OBJDIR)\makeheaders$P" 2>NUL | |
| 1049 | + -del "$(OBJDIR)\mkversion$E" 2>NUL | |
| 1050 | + -del "$(OBJDIR)\mkversion$P" 2>NUL | |
| 1051 | + -del "$(OBJDIR)\mkcss$E" 2>NUL | |
| 1052 | + -del "$(OBJDIR)\mkcss$P" 2>NUL | |
| 1053 | + -del "$(OBJDIR)\codecheck1$E" 2>NUL | |
| 1054 | + -del "$(OBJDIR)\codecheck1$P" 2>NUL | |
| 1055 | + -del "$(OBJDIR)\mkbuiltin$E" 2>NUL | |
| 1056 | + -del "$(OBJDIR)\mkbuiltin$P" 2>NUL | |
| 1057 | 1057 | |
| 1058 | 1058 | realclean: clean |
| 1059 | 1059 | |
| 1060 | 1060 | "$(OBJDIR)\json$O" : "$(SRCDIR)\json_detail.h" |
| 1061 | 1061 | "$(OBJDIR)\json_artifact$O" : "$(SRCDIR)\json_detail.h" |
| 1062 | 1062 |
| --- win/Makefile.msc | |
| +++ win/Makefile.msc | |
| @@ -1022,40 +1022,40 @@ | |
| 1022 | |
| 1023 | "$(OX)\builtin_data.h": "$(OBJDIR)\mkbuiltin$E" "$(OX)\builtin_data.reslist" |
| 1024 | "$(OBJDIR)\mkbuiltin$E" --prefix "$(SRCDIR)/" --reslist "$(OX)\builtin_data.reslist" > $@ |
| 1025 | |
| 1026 | cleanx: |
| 1027 | del "$(OX)\*.obj" 2>NUL |
| 1028 | del "$(OBJDIR)\*.obj" 2>NUL |
| 1029 | del "$(OX)\*_.c" 2>NUL |
| 1030 | del "$(OX)\*.h" 2>NUL |
| 1031 | del "$(OX)\*.ilk" 2>NUL |
| 1032 | del "$(OX)\*.map" 2>NUL |
| 1033 | del "$(OX)\*.res" 2>NUL |
| 1034 | del "$(OX)\*.reslist" 2>NUL |
| 1035 | del "$(OX)\headers" 2>NUL |
| 1036 | del "$(OX)\linkopts" 2>NUL |
| 1037 | del "$(OX)\vc*.pdb" 2>NUL |
| 1038 | |
| 1039 | clean: cleanx |
| 1040 | del "$(APPNAME)" 2>NUL |
| 1041 | del "$(PDBNAME)" 2>NUL |
| 1042 | del "$(APPMANIFEST)" 2>NUL |
| 1043 | del "$(OBJDIR)\translate$E" 2>NUL |
| 1044 | del "$(OBJDIR)\translate$P" 2>NUL |
| 1045 | del "$(OBJDIR)\mkindex$E" 2>NUL |
| 1046 | del "$(OBJDIR)\mkindex$P" 2>NUL |
| 1047 | del "$(OBJDIR)\makeheaders$E" 2>NUL |
| 1048 | del "$(OBJDIR)\makeheaders$P" 2>NUL |
| 1049 | del "$(OBJDIR)\mkversion$E" 2>NUL |
| 1050 | del "$(OBJDIR)\mkversion$P" 2>NUL |
| 1051 | del "$(OBJDIR)\mkcss$E" 2>NUL |
| 1052 | del "$(OBJDIR)\mkcss$P" 2>NUL |
| 1053 | del "$(OBJDIR)\codecheck1$E" 2>NUL |
| 1054 | del "$(OBJDIR)\codecheck1$P" 2>NUL |
| 1055 | del "$(OBJDIR)\mkbuiltin$E" 2>NUL |
| 1056 | del "$(OBJDIR)\mkbuiltin$P" 2>NUL |
| 1057 | |
| 1058 | realclean: clean |
| 1059 | |
| 1060 | "$(OBJDIR)\json$O" : "$(SRCDIR)\json_detail.h" |
| 1061 | "$(OBJDIR)\json_artifact$O" : "$(SRCDIR)\json_detail.h" |
| 1062 |
| --- win/Makefile.msc | |
| +++ win/Makefile.msc | |
| @@ -1022,40 +1022,40 @@ | |
| 1022 | |
| 1023 | "$(OX)\builtin_data.h": "$(OBJDIR)\mkbuiltin$E" "$(OX)\builtin_data.reslist" |
| 1024 | "$(OBJDIR)\mkbuiltin$E" --prefix "$(SRCDIR)/" --reslist "$(OX)\builtin_data.reslist" > $@ |
| 1025 | |
| 1026 | cleanx: |
| 1027 | -del "$(OX)\*.obj" 2>NUL |
| 1028 | -del "$(OBJDIR)\*.obj" 2>NUL |
| 1029 | -del "$(OX)\*_.c" 2>NUL |
| 1030 | -del "$(OX)\*.h" 2>NUL |
| 1031 | -del "$(OX)\*.ilk" 2>NUL |
| 1032 | -del "$(OX)\*.map" 2>NUL |
| 1033 | -del "$(OX)\*.res" 2>NUL |
| 1034 | -del "$(OX)\*.reslist" 2>NUL |
| 1035 | -del "$(OX)\headers" 2>NUL |
| 1036 | -del "$(OX)\linkopts" 2>NUL |
| 1037 | -del "$(OX)\vc*.pdb" 2>NUL |
| 1038 | |
| 1039 | clean: cleanx |
| 1040 | -del "$(APPNAME)" 2>NUL |
| 1041 | -del "$(PDBNAME)" 2>NUL |
| 1042 | -del "$(APPMANIFEST)" 2>NUL |
| 1043 | -del "$(OBJDIR)\translate$E" 2>NUL |
| 1044 | -del "$(OBJDIR)\translate$P" 2>NUL |
| 1045 | -del "$(OBJDIR)\mkindex$E" 2>NUL |
| 1046 | -del "$(OBJDIR)\mkindex$P" 2>NUL |
| 1047 | -del "$(OBJDIR)\makeheaders$E" 2>NUL |
| 1048 | -del "$(OBJDIR)\makeheaders$P" 2>NUL |
| 1049 | -del "$(OBJDIR)\mkversion$E" 2>NUL |
| 1050 | -del "$(OBJDIR)\mkversion$P" 2>NUL |
| 1051 | -del "$(OBJDIR)\mkcss$E" 2>NUL |
| 1052 | -del "$(OBJDIR)\mkcss$P" 2>NUL |
| 1053 | -del "$(OBJDIR)\codecheck1$E" 2>NUL |
| 1054 | -del "$(OBJDIR)\codecheck1$P" 2>NUL |
| 1055 | -del "$(OBJDIR)\mkbuiltin$E" 2>NUL |
| 1056 | -del "$(OBJDIR)\mkbuiltin$P" 2>NUL |
| 1057 | |
| 1058 | realclean: clean |
| 1059 | |
| 1060 | "$(OBJDIR)\json$O" : "$(SRCDIR)\json_detail.h" |
| 1061 | "$(OBJDIR)\json_artifact$O" : "$(SRCDIR)\json_detail.h" |
| 1062 |
+28
-28
| --- win/Makefile.msc | ||
| +++ win/Makefile.msc | ||
| @@ -1022,40 +1022,40 @@ | ||
| 1022 | 1022 | |
| 1023 | 1023 | "$(OX)\builtin_data.h": "$(OBJDIR)\mkbuiltin$E" "$(OX)\builtin_data.reslist" |
| 1024 | 1024 | "$(OBJDIR)\mkbuiltin$E" --prefix "$(SRCDIR)/" --reslist "$(OX)\builtin_data.reslist" > $@ |
| 1025 | 1025 | |
| 1026 | 1026 | cleanx: |
| 1027 | - del "$(OX)\*.obj" 2>NUL | |
| 1028 | - del "$(OBJDIR)\*.obj" 2>NUL | |
| 1029 | - del "$(OX)\*_.c" 2>NUL | |
| 1030 | - del "$(OX)\*.h" 2>NUL | |
| 1031 | - del "$(OX)\*.ilk" 2>NUL | |
| 1032 | - del "$(OX)\*.map" 2>NUL | |
| 1033 | - del "$(OX)\*.res" 2>NUL | |
| 1034 | - del "$(OX)\*.reslist" 2>NUL | |
| 1035 | - del "$(OX)\headers" 2>NUL | |
| 1036 | - del "$(OX)\linkopts" 2>NUL | |
| 1037 | - del "$(OX)\vc*.pdb" 2>NUL | |
| 1027 | + -del "$(OX)\*.obj" 2>NUL | |
| 1028 | + -del "$(OBJDIR)\*.obj" 2>NUL | |
| 1029 | + -del "$(OX)\*_.c" 2>NUL | |
| 1030 | + -del "$(OX)\*.h" 2>NUL | |
| 1031 | + -del "$(OX)\*.ilk" 2>NUL | |
| 1032 | + -del "$(OX)\*.map" 2>NUL | |
| 1033 | + -del "$(OX)\*.res" 2>NUL | |
| 1034 | + -del "$(OX)\*.reslist" 2>NUL | |
| 1035 | + -del "$(OX)\headers" 2>NUL | |
| 1036 | + -del "$(OX)\linkopts" 2>NUL | |
| 1037 | + -del "$(OX)\vc*.pdb" 2>NUL | |
| 1038 | 1038 | |
| 1039 | 1039 | clean: cleanx |
| 1040 | - del "$(APPNAME)" 2>NUL | |
| 1041 | - del "$(PDBNAME)" 2>NUL | |
| 1042 | - del "$(APPMANIFEST)" 2>NUL | |
| 1043 | - del "$(OBJDIR)\translate$E" 2>NUL | |
| 1044 | - del "$(OBJDIR)\translate$P" 2>NUL | |
| 1045 | - del "$(OBJDIR)\mkindex$E" 2>NUL | |
| 1046 | - del "$(OBJDIR)\mkindex$P" 2>NUL | |
| 1047 | - del "$(OBJDIR)\makeheaders$E" 2>NUL | |
| 1048 | - del "$(OBJDIR)\makeheaders$P" 2>NUL | |
| 1049 | - del "$(OBJDIR)\mkversion$E" 2>NUL | |
| 1050 | - del "$(OBJDIR)\mkversion$P" 2>NUL | |
| 1051 | - del "$(OBJDIR)\mkcss$E" 2>NUL | |
| 1052 | - del "$(OBJDIR)\mkcss$P" 2>NUL | |
| 1053 | - del "$(OBJDIR)\codecheck1$E" 2>NUL | |
| 1054 | - del "$(OBJDIR)\codecheck1$P" 2>NUL | |
| 1055 | - del "$(OBJDIR)\mkbuiltin$E" 2>NUL | |
| 1056 | - del "$(OBJDIR)\mkbuiltin$P" 2>NUL | |
| 1040 | + -del "$(APPNAME)" 2>NUL | |
| 1041 | + -del "$(PDBNAME)" 2>NUL | |
| 1042 | + -del "$(APPMANIFEST)" 2>NUL | |
| 1043 | + -del "$(OBJDIR)\translate$E" 2>NUL | |
| 1044 | + -del "$(OBJDIR)\translate$P" 2>NUL | |
| 1045 | + -del "$(OBJDIR)\mkindex$E" 2>NUL | |
| 1046 | + -del "$(OBJDIR)\mkindex$P" 2>NUL | |
| 1047 | + -del "$(OBJDIR)\makeheaders$E" 2>NUL | |
| 1048 | + -del "$(OBJDIR)\makeheaders$P" 2>NUL | |
| 1049 | + -del "$(OBJDIR)\mkversion$E" 2>NUL | |
| 1050 | + -del "$(OBJDIR)\mkversion$P" 2>NUL | |
| 1051 | + -del "$(OBJDIR)\mkcss$E" 2>NUL | |
| 1052 | + -del "$(OBJDIR)\mkcss$P" 2>NUL | |
| 1053 | + -del "$(OBJDIR)\codecheck1$E" 2>NUL | |
| 1054 | + -del "$(OBJDIR)\codecheck1$P" 2>NUL | |
| 1055 | + -del "$(OBJDIR)\mkbuiltin$E" 2>NUL | |
| 1056 | + -del "$(OBJDIR)\mkbuiltin$P" 2>NUL | |
| 1057 | 1057 | |
| 1058 | 1058 | realclean: clean |
| 1059 | 1059 | |
| 1060 | 1060 | "$(OBJDIR)\json$O" : "$(SRCDIR)\json_detail.h" |
| 1061 | 1061 | "$(OBJDIR)\json_artifact$O" : "$(SRCDIR)\json_detail.h" |
| 1062 | 1062 |
| --- win/Makefile.msc | |
| +++ win/Makefile.msc | |
| @@ -1022,40 +1022,40 @@ | |
| 1022 | |
| 1023 | "$(OX)\builtin_data.h": "$(OBJDIR)\mkbuiltin$E" "$(OX)\builtin_data.reslist" |
| 1024 | "$(OBJDIR)\mkbuiltin$E" --prefix "$(SRCDIR)/" --reslist "$(OX)\builtin_data.reslist" > $@ |
| 1025 | |
| 1026 | cleanx: |
| 1027 | del "$(OX)\*.obj" 2>NUL |
| 1028 | del "$(OBJDIR)\*.obj" 2>NUL |
| 1029 | del "$(OX)\*_.c" 2>NUL |
| 1030 | del "$(OX)\*.h" 2>NUL |
| 1031 | del "$(OX)\*.ilk" 2>NUL |
| 1032 | del "$(OX)\*.map" 2>NUL |
| 1033 | del "$(OX)\*.res" 2>NUL |
| 1034 | del "$(OX)\*.reslist" 2>NUL |
| 1035 | del "$(OX)\headers" 2>NUL |
| 1036 | del "$(OX)\linkopts" 2>NUL |
| 1037 | del "$(OX)\vc*.pdb" 2>NUL |
| 1038 | |
| 1039 | clean: cleanx |
| 1040 | del "$(APPNAME)" 2>NUL |
| 1041 | del "$(PDBNAME)" 2>NUL |
| 1042 | del "$(APPMANIFEST)" 2>NUL |
| 1043 | del "$(OBJDIR)\translate$E" 2>NUL |
| 1044 | del "$(OBJDIR)\translate$P" 2>NUL |
| 1045 | del "$(OBJDIR)\mkindex$E" 2>NUL |
| 1046 | del "$(OBJDIR)\mkindex$P" 2>NUL |
| 1047 | del "$(OBJDIR)\makeheaders$E" 2>NUL |
| 1048 | del "$(OBJDIR)\makeheaders$P" 2>NUL |
| 1049 | del "$(OBJDIR)\mkversion$E" 2>NUL |
| 1050 | del "$(OBJDIR)\mkversion$P" 2>NUL |
| 1051 | del "$(OBJDIR)\mkcss$E" 2>NUL |
| 1052 | del "$(OBJDIR)\mkcss$P" 2>NUL |
| 1053 | del "$(OBJDIR)\codecheck1$E" 2>NUL |
| 1054 | del "$(OBJDIR)\codecheck1$P" 2>NUL |
| 1055 | del "$(OBJDIR)\mkbuiltin$E" 2>NUL |
| 1056 | del "$(OBJDIR)\mkbuiltin$P" 2>NUL |
| 1057 | |
| 1058 | realclean: clean |
| 1059 | |
| 1060 | "$(OBJDIR)\json$O" : "$(SRCDIR)\json_detail.h" |
| 1061 | "$(OBJDIR)\json_artifact$O" : "$(SRCDIR)\json_detail.h" |
| 1062 |
| --- win/Makefile.msc | |
| +++ win/Makefile.msc | |
| @@ -1022,40 +1022,40 @@ | |
| 1022 | |
| 1023 | "$(OX)\builtin_data.h": "$(OBJDIR)\mkbuiltin$E" "$(OX)\builtin_data.reslist" |
| 1024 | "$(OBJDIR)\mkbuiltin$E" --prefix "$(SRCDIR)/" --reslist "$(OX)\builtin_data.reslist" > $@ |
| 1025 | |
| 1026 | cleanx: |
| 1027 | -del "$(OX)\*.obj" 2>NUL |
| 1028 | -del "$(OBJDIR)\*.obj" 2>NUL |
| 1029 | -del "$(OX)\*_.c" 2>NUL |
| 1030 | -del "$(OX)\*.h" 2>NUL |
| 1031 | -del "$(OX)\*.ilk" 2>NUL |
| 1032 | -del "$(OX)\*.map" 2>NUL |
| 1033 | -del "$(OX)\*.res" 2>NUL |
| 1034 | -del "$(OX)\*.reslist" 2>NUL |
| 1035 | -del "$(OX)\headers" 2>NUL |
| 1036 | -del "$(OX)\linkopts" 2>NUL |
| 1037 | -del "$(OX)\vc*.pdb" 2>NUL |
| 1038 | |
| 1039 | clean: cleanx |
| 1040 | -del "$(APPNAME)" 2>NUL |
| 1041 | -del "$(PDBNAME)" 2>NUL |
| 1042 | -del "$(APPMANIFEST)" 2>NUL |
| 1043 | -del "$(OBJDIR)\translate$E" 2>NUL |
| 1044 | -del "$(OBJDIR)\translate$P" 2>NUL |
| 1045 | -del "$(OBJDIR)\mkindex$E" 2>NUL |
| 1046 | -del "$(OBJDIR)\mkindex$P" 2>NUL |
| 1047 | -del "$(OBJDIR)\makeheaders$E" 2>NUL |
| 1048 | -del "$(OBJDIR)\makeheaders$P" 2>NUL |
| 1049 | -del "$(OBJDIR)\mkversion$E" 2>NUL |
| 1050 | -del "$(OBJDIR)\mkversion$P" 2>NUL |
| 1051 | -del "$(OBJDIR)\mkcss$E" 2>NUL |
| 1052 | -del "$(OBJDIR)\mkcss$P" 2>NUL |
| 1053 | -del "$(OBJDIR)\codecheck1$E" 2>NUL |
| 1054 | -del "$(OBJDIR)\codecheck1$P" 2>NUL |
| 1055 | -del "$(OBJDIR)\mkbuiltin$E" 2>NUL |
| 1056 | -del "$(OBJDIR)\mkbuiltin$P" 2>NUL |
| 1057 | |
| 1058 | realclean: clean |
| 1059 | |
| 1060 | "$(OBJDIR)\json$O" : "$(SRCDIR)\json_detail.h" |
| 1061 | "$(OBJDIR)\json_artifact$O" : "$(SRCDIR)\json_detail.h" |
| 1062 |
+721
-143
| --- www/alerts.md | ||
| +++ www/alerts.md | ||
| @@ -1,168 +1,740 @@ | ||
| 1 | -Email Alerts | |
| 2 | -============ | |
| 3 | - | |
| 4 | -The email alert system is a work-in-progress. | |
| 5 | -This documentation was last updated on 2018-08-12. | |
| 6 | -Check back later for updates. | |
| 7 | - | |
| 8 | -Email Alerts And Notifications | |
| ------------------------------- | ||
| 9 | - | |
| 10 | -Beginning with version 2.7, Fossil supports the ability to send | |
| 11 | -email messages to subscribers alerting them to changes in the repository. | |
| 12 | -Subscribers can request an email notification of the following kinds | |
| 13 | -of changes: | |
| 14 | - | |
| 15 | - * New check-ins | |
| 16 | - * Changes to any ticket | |
| 17 | - * Changes to any wiki page | |
| 18 | - * New forum posts | |
| 1 | +# Email Alerts | |
| 2 | + | |
| 3 | +## Overview | |
| 4 | + | |
| 5 | +Beginning with version 2.7, Fossil can send email messages to | |
| 6 | +subscribers to alert them to changes in the repository: | |
| 7 | + | |
| 8 | + * New [checkins](/help?cmd=ci) | |
| 9 | + * [Ticket](./tickets.wiki) changes | |
| 10 | + * [Wiki](./wikitheory.wiki) page changes | |
| 11 | + * New and edited [forum](./forum.wiki) posts | |
| 19 | 12 | * Announcements |
| 20 | 13 | |
| 21 | -Subscribers can either elect to receive emails as soon as these events happen, | |
| 14 | +Subscribers can elect to receive emails as soon as these events happen, | |
| 22 | 15 | or they can receive a daily digest of the events instead. |
| 23 | 16 | |
| 24 | -Email alerts are sent by a [Fossil server](./server.wiki). You must | |
| 25 | -have a server [set up to make use of email alerts](#setup). Email | |
| 26 | -alerts do not currently work if you are only using Fossil from the | |
| 17 | +Email alerts are sent by a [Fossil server](./server.wiki), which must be | |
| 18 | +[set up](#quick) by the Fossil administrator to send email. | |
| 19 | + | |
| 20 | +Email alerts do not currently work if you are only using Fossil from the | |
| 27 | 21 | command line. |
| 28 | 22 | |
| 29 | -Users and Subscribers | |
| ---------------------- | ||
| 30 | - | |
| 31 | -Fossil makes a distinction between "users" and "subscribers". A | |
| 32 | -user is someone with a username and password — someone who can | |
| 33 | -log in. A subscriber is someone who receives email alerts. Users | |
| 34 | -can also be subscribers and subscribers can be users, but that does | |
| 35 | -not have to be the case. It is possible to be a user without being | |
| 36 | -a subscriber and to be a subscriber without being a user. | |
| 37 | - | |
| 38 | -In the repository database file, users are tracked with the USER table | |
| 39 | -and subscribers are tracked via the SUBSCRIBER table. | |
| 40 | - | |
| 41 | -<a id="setup"></a> | |
| 42 | -Activating Email Alerts | |
| ------------------------ | ||
| 43 | - | |
| 44 | -Email alerts are turned off by default. To activate them, log into | |
| 45 | -the Fossil server as an administrator and visit the | |
| 46 | -[Admin/Notification](/setup_notification) | |
| 47 | -setup page. ([`/setup_notification`](/setup_notification)) | |
| 48 | - | |
| 49 | -Important: Email alerts are configured using Admin/Notification, not | |
| 50 | -Admin/Email-Server. The Email-Server setup screen is used to configure | |
| 51 | -a different subsystem within Fossil. | |
| 52 | - | |
| 53 | -The Admin/Notification setup screen lets you configure how Fossil should | |
| 54 | -send email for alerts. There are some required fields at the top of the | |
| 55 | -screen for elements such as the "From:" address for outgoing emails, | |
| 56 | -the URL for the Fossil server, and a nickname for the repository that | |
| 57 | -will appear in the "Subject:" line of outgoing emails. But the key | |
| 58 | -setup parameter is the "Email Send Method". | |
| 59 | - | |
| 60 | -Fossil supports multiple methods for sending email alerts: | |
| 61 | - | |
| 62 | - 1. Pipe the email message text into a command, such as `sendmail`. | |
| 63 | - 2. Store email messages as individual files in a directory and let | |
| 64 | - some other process set up by the administrator take care of | |
| 65 | - reading and forwarding those files. | |
| 66 | - 3. Store email messages as entries in an SQLite database where | |
| 67 | - some external process and read and forward the emails. | |
| 68 | - 4. Send emails to an SMTP Relay. | |
| 69 | - 5. Send emails directly to the recipients via SMTP. | |
| 70 | - | |
| 71 | -As of 2018-08-08, method (5) is not yet supported, but there are plans | |
| 72 | -to add support soon. | |
| 73 | - | |
| 74 | -The self-hosting Fossil repository at <https://www.fossil-scm.org/> currently | |
| 75 | -uses method (3). Outgoing email messages are added to an SQLite database | |
| 76 | -file. A separate daemon process continously monitors that database file, | |
| 77 | -extracts email messages as they are added, and hands them off to | |
| 78 | -"procmail" to be sent on to the final recipient. The self-hosting | |
| 79 | -Fossil repository uses this technique rather than method (1) because | |
| 80 | -it is running inside of a restrictive chroot jail which is unable to | |
| 81 | -hand off messages to "procmail" directly. The daemon that monitors the | |
| 82 | -email database is a [short TCL script](/file/tools/email-sender.tcl). | |
| 83 | -That daemon is started automatically by adding this line: | |
| 84 | - | |
| 85 | - /usr/bin/tclsh /home/www/fossil/email-sender.tcl & | |
| 86 | - | |
| 87 | -To the `/etc/rc.local` file of the Ubuntu server that hosts the | |
| 88 | -repository. | |
| 89 | - | |
| 90 | -After making necessary changes to the Admin/Notification page, test | |
| 91 | -those changes by clicking the "[Send Announcement](/announce)" link | |
| 92 | -at the top of the page. Fill in your email address in the "To:" | |
| 93 | -line and a test message below, and press "Send Message" to verify that | |
| 94 | -outgoing email is working. | |
| 95 | - | |
| 96 | -<a id="cap7"></a> | |
| 97 | -Once email notification is working, one must also adjust user permissions | |
| 98 | -to allow users to subscribe to email notification. On the | |
| 99 | -Setup/User page, under the permissions for each user, is a new capability | |
| 100 | -called "Email Alerts". The corresponding capability letter is "7". | |
| 101 | -That new "7" capability must be enabled in order for | |
| 102 | -users to be able to become subscribers. To allow anonymous passers-by | |
| 103 | -on the internet to subscribe, simply enable "Email Alerts" for the | |
| 104 | -"nobody" user category. To require that the user solve a simple CAPTCHA | |
| 105 | -first, add it to the "anonymous" user category instead. | |
| 106 | - | |
| 107 | -Signing Up For Email Notification | |
| ---------------------------------- | ||
| 108 | - | |
| 109 | -Users and/or anonymous passers-by can visit the | |
| 110 | -[`/subscribe`](/subscribe) page to sign | |
| 111 | -up for email notification. | |
| 112 | - | |
| 113 | -If your users are getting the following complaint from Fossil: | |
| 23 | +A bit of terminology: Fossil uses the terms "email alerts" and | |
| 24 | +"notifications" interchangeably. We stick to the former term in this | |
| 25 | +document except when referring to parts of the Fossil UI still using the | |
| 26 | +latter term. | |
| 27 | + | |
| 28 | + | |
| 29 | +## Setup Prerequisites | |
| 30 | + | |
| 31 | +Much of this document describes how to set up Fossil's email alert | |
| 32 | +system. To follow this guide, you will need a Fossil UI browser window | |
| 33 | +open to the [Admin → Notification](/setup_notification) Fossil UI screen | |
| 34 | +on the the Fossil server that will be sending these email alerts, logged | |
| 35 | +in as a user with Admin capability. It is not possible to work on a | |
| 36 | +clone of the server's repository and push the configuration changes up | |
| 37 | +to that repo as an Admin user, [on purpose](#backup). | |
| 38 | + | |
| 39 | +**Important:** Do not confuse that screen with Admin → Email-Server, | |
| 40 | +which sets up a different subsystem within Fossil. That feature is | |
| 41 | +related to this document's topic, but it is currently incomplete, so we | |
| 42 | +do not cover it at this time. | |
| 43 | + | |
| 44 | +<a id="cd"></a> | |
| 45 | +You will also need a CLI window open with its working directory changed | |
| 46 | +to a checkout directory of the Fossil repository you are setting up to | |
| 47 | +send email. If you don't `cd` to such a checkout directory first, | |
| 48 | +you'll need to add `-R /path/to/repo.fossil` to each `fossil` command | |
| 49 | +below to tell Fossil which repository you mean it to apply the command | |
| 50 | +to. | |
| 51 | + | |
| 52 | +There are other prerequisites for email service, but since they vary | |
| 53 | +depending on the configuration you choose, we'll cover these inline | |
| 54 | +below. | |
| 55 | + | |
| 56 | + | |
| 57 | +<a id="quick"></a> | |
| 58 | +## Quick Email Service Setup | |
| 59 | + | |
| 60 | +If you've already got a working Postfix, Exim, or Sendmail server on the | |
| 61 | +machine running your Fossil instance(s), and you aren't using Fossil's | |
| 62 | +`chroot` feature to wall Fossil off from the rest of the machine, it's | |
| 63 | +fairly simple to set up email alerts. | |
| 64 | + | |
| 65 | +(Otherwise, skip [ahead](#advanced) to the sections on advanced email | |
| 66 | +service setup.) | |
| 67 | + | |
| 68 | +This is our "quick setup" option even though setting up an SMTP mail | |
| 69 | +server is not trival, because there are many other reasons to have such | |
| 70 | +a server set up already: internal project email service, `cron` | |
| 71 | +notifications, server status monitoring notifications... | |
| 72 | + | |
| 73 | +With that out of the way, the Fossil-specific steps are easy: | |
| 74 | + | |
| 75 | +1. Go to [Admin → Notification](/setup_notification) and fill out all | |
| 76 | + of the **Required** fields: | |
| 77 | + | |
| 78 | + * **Canonical server URL** — Use the suggested URL | |
| 79 | + | |
| 80 | + * **"From" email address** — `[email protected]` is | |
| 81 | + traditional, but suit yourself | |
| 82 | + | |
| 83 | + * **Repository nickname** — See the suggested examples on the web page. | |
| 84 | + | |
| 85 | +2. Set "Email Send Method" to "Pipe to a command" | |
| 86 | + | |
| 87 | +3. Set the "Administrator email address" to a suitable valid email | |
| 88 | + address on that machine. It could be the same value you used for | |
| 89 | + the "From" address above, or it could be a different value like | |
| 90 | + `[email protected]`. | |
| 91 | + | |
| 92 | +Save your changes. | |
| 93 | + | |
| 94 | +At the command line, say | |
| 95 | + | |
| 96 | + $ fossil set email-send-command | |
| 97 | + | |
| 98 | +If that gives a blank value instead of `sendmail -ti`, say | |
| 99 | + | |
| 100 | + $ fossil set email-send-command "sendmail -ti" | |
| 101 | + | |
| 102 | +to force the setting. That works around a [known | |
| 103 | +bug](https://fossil-scm.org/forum/forumpost/840b676410) which may be | |
| 104 | +squished by the time you read this. | |
| 105 | + | |
| 106 | +If you're running Postfix or Exim, you might think that command is | |
| 107 | +wrong, since you aren't running Sendmail. These mail servers provide a | |
| 108 | +`sendmail` command for compatibility with software like Fossil that has | |
| 109 | +no good reason to care exactly which SMTP server implementation is | |
| 110 | +running at a given site. There may be other SMTP servers that also | |
| 111 | +provide a compatible `sendmail` command, in which case they may work | |
| 112 | +with Fossil using the same steps as above. | |
| 113 | + | |
| 114 | +<a id="status"></a> | |
| 115 | +If you reload the Admin → Notification page, the Status section at the | |
| 116 | +top should show: | |
| 117 | + | |
| 118 | + Outgoing Email: Piped to command "sendmail -ti" | |
| 119 | + Pending Alerts: 0 normal, 0 digest | |
| 120 | + Subscribers: 0 active, 0 total | |
| 121 | + | |
| 122 | +Before you move on to the next section, you might like to read up on | |
| 123 | +[some subtleties](#pipe) with the "pipe to a command" method that we did | |
| 124 | +not cover above. | |
| 125 | + | |
| 126 | + | |
| 127 | +<a id="usage"></a> | |
| 128 | +## Usage and Testing | |
| 129 | + | |
| 130 | +Now that email service from Fossil is set up, you can test it and begin | |
| 131 | +using it. | |
| 132 | + | |
| 133 | + | |
| 134 | +<a id="sub" name="subscribe"></a> | |
| 135 | +### Subscribing to Alerts | |
| 136 | + | |
| 137 | +In the Status output above, we saw that there are no subscribers, so the | |
| 138 | +next step is to add the first one. | |
| 139 | + | |
| 140 | +Go to the `/subscribe` page on your Fossil instance to sign up for email | |
| 141 | +alerts. At the very least, you will need to sign up for "Forum Posts" | |
| 142 | +and "Announcements" to complete the testing steps below. | |
| 143 | + | |
| 144 | +If you're logged in with a Fossil repository user account and put the | |
| 145 | +same user name and email address into this forum as you used for your | |
| 146 | +user information under Admin → Users, Fossil will simply tie your alert | |
| 147 | +preferences to your login record, and the email address in your user's | |
| 148 | +Contact Info field will be considered already-verified. Otherwise, | |
| 149 | +Fossil will create an alert-only record, and you will have to verify the | |
| 150 | +email address before Fossil will send alerts to it. | |
| 151 | + | |
| 152 | +This shows a key aspect of the way Fossil's email alerts system works, | |
| 153 | +by the way: a user can be signed up for email alerts without having a | |
| 154 | +full-fledged Fossil user account. Only when both user names are the same | |
| 155 | +are the two records tied together under the hood. For more on this, see | |
| 156 | +[Users vs Subscribers below](#uvs). | |
| 157 | + | |
| 158 | +If you are seeing the following complaint from Fossil: | |
| 114 | 159 | |
| 115 | 160 | <blockquote> |
| 116 | 161 | Use a different login with greater privilege than FOO to access |
| 117 | 162 | /subscribe |
| 118 | 163 | </blockquote> |
| 119 | 164 | |
| 120 | -...then you forgot to [give capability 7](#cap7) to that user or to a | |
| 121 | -user category that the user is a member of. | |
| 165 | +...then the repository's administrator forgot to [give the Alerts capability](#cap7) | |
| 166 | +to that user or to a user category that the user is a member of. | |
| 122 | 167 | |
| 123 | -After signing up, a single verification email | |
| 124 | -is sent. The new subscriber must click a link on that email in order to | |
| 125 | -activate the subscription. | |
| 168 | +After a subscriber signs up for alerts for the first time, a single | |
| 169 | +verification email is sent to that subscriber's given email address. | |
| 170 | +The new subscriber must click a link in that email in order to activate | |
| 171 | +the subscription. | |
| 126 | 172 | |
| 127 | 173 | Subscription verification emails are only sent once. This is a defense |
| 128 | -against malicious robots that try to harass innocent internet users | |
| 129 | -by having subscription pages send multiple verification emails. | |
| 130 | -If the initial subscription verification does not go through correctly, | |
| 131 | -an administrator must intervene to reset the subscription. | |
| 132 | - | |
| 133 | -Every subscriber has a long random hexadecimal security code that serves | |
| 134 | -as their password. All email notifications contain a link back to the | |
| 135 | -Fossil server, incorporating this security code, which allows the | |
| 136 | -subscriber to adjust their subscription options. | |
| 137 | - | |
| 138 | -Administrator Activities | |
| ------------------------- | ||
| 139 | - | |
| 140 | -The repository administrator has unlimited control over individual | |
| 141 | -subscriptions. The "[List Subscribers](/subscribers)" button at the top | |
| 142 | -of the Setup/Notification screen gives a list of subscribers. Clicking on | |
| 143 | -any subscriber link allows the administrator to adjust the subscription. | |
| 144 | - | |
| 145 | -To unsubscribe, first select the "unsubscribe" checkbox, then press the | |
| 146 | -"Unsubscribe" button. | |
| 147 | - | |
| 148 | -The "verified" checkbox determines whether or not an email address has | |
| 149 | -been verified. This can be enabled or disabled manually by the | |
| 150 | -administrator. | |
| 151 | - | |
| 152 | -Cloning, Syncing, and Backups | |
| ------------------------------ | ||
| 153 | - | |
| 154 | -The Setup/Notification settings are not replicated using clone or sync. | |
| 155 | -In a network of peer repositories, you only want one repository sending | |
| 156 | -email notifications. If you were to replicate the email notification | |
| 157 | -settings to a separate repository, then subscribers would get multiple | |
| 158 | -notifications for each event, which would be bad. | |
| 174 | +against malicious robots that try to harass innocent Internet users by | |
| 175 | +having subscription pages send multiple verification emails. If the | |
| 176 | +initial subscription verification does not go through correctly, an | |
| 177 | +administrator must [intervene](#admin) to reset the subscription. | |
| 178 | + | |
| 179 | +Every subscriber-only email address has a [long random hexadecimal | |
| 180 | +security code](#scode) that serves in place of a password. All email | |
| 181 | +alerts contain a link in their footer back to the Fossil server, | |
| 182 | +incorporating this security code, which allows the subscriber to adjust | |
| 183 | +their subscription options. If a user doesn't have any of those emails, | |
| 184 | +they can request a link via email by visiting the `/alerts` or | |
| 185 | +`/unsubscribe` page on the repository. | |
| 186 | + | |
| 187 | +Those with Fossil repository logins can adjust their email alert | |
| 188 | +settings by visiting the `/alerts` page on the repository. With the | |
| 189 | +default skin, you can get there by clicking the "Logout" link in the | |
| 190 | +upper right corner of any Fossil UI page then clicking the "Email | |
| 191 | +Alerts" link. That link is also available via the Sitemap (`/sitemap`) | |
| 192 | +and via the default skin's hamburger menu (☰). | |
| 193 | + | |
| 194 | + | |
| 195 | +<a id="unsub" name="unsubscribe"></a> | |
| 196 | +### Unsubscribing | |
| 197 | + | |
| 198 | +To unsubscribe from alerts, visit the `/alerts` page on the repository, | |
| 199 | +click the "Unsubscribe" button, then check the "Unsbuscribe" checkbox to | |
| 200 | +verify your action and press the "Unsubscribe" button a second time. | |
| 201 | + | |
| 202 | +This interlock is intended to prevent accidental unsubscription. | |
| 203 | + | |
| 204 | + | |
| 205 | +<a id="test"></a> | |
| 206 | +### Test Email Service | |
| 207 | + | |
| 208 | +The easiest way to test email sending from Fossil is via the "[Send | |
| 209 | +Announcement](/announce)" link at the top of the "Email Notification | |
| 210 | +Setup" page. Put your email address in the "To:" line and a test | |
| 211 | +message below, then press "Send Message" to verify that outgoing email | |
| 212 | +is working. | |
| 213 | + | |
| 214 | +Another method is from the command line: | |
| 215 | + | |
| 216 | + $ fossil alerts test-message [email protected] --body README.md --subject Test | |
| 217 | + | |
| 218 | +That should send you an email with "Test" in the subject line and the | |
| 219 | +contents of your project's `README.md` file in the body. | |
| 220 | + | |
| 221 | +That command assumes that your project contains a "readme" file, but of | |
| 222 | +course it does, because you have followed the [Programming Style Guide | |
| 223 | +Checklist][cl], right? Right. | |
| 224 | + | |
| 225 | +[cl]: https://sendgrid.com/blog/programming-style-guide-checklist/ | |
| 226 | + | |
| 227 | + | |
| 228 | +<a id="cap7"></a> | |
| 229 | +### User Capabilities | |
| 230 | + | |
| 231 | +Once email alerts are working, one must also adjust user permissions to | |
| 232 | +allow users to subscribe to email alerts. In the capability list for | |
| 233 | +each user on the Admin → Users page is a new capability called "Email | |
| 234 | +Alerts". The corresponding capability letter is "7", which you must | |
| 235 | +give to any user that needs to use the subscription setup pages, | |
| 236 | +`/subscribe` and `/alerts`. | |
| 237 | + | |
| 238 | +To allow any passer-by on the Internet to subscribe, give the "Email | |
| 239 | +Alerts" capability to the "nobody" user category. To require that a | |
| 240 | +person solve a simple CAPTCHA first, give that capability to the | |
| 241 | +"anonymous" user category instead. | |
| 242 | + | |
| 243 | + | |
| 244 | +<a id="first" name="frist"></a> | |
| 245 | +### First Post | |
| 246 | + | |
| 247 | +I suggest taking the time to compose a suitable introductory message | |
| 248 | +especially for your project's forum, one which a new user would find | |
| 249 | +helpful. | |
| 250 | + | |
| 251 | +Wait a few seconds, and you should receive an email alert with the | |
| 252 | +post's subject and body text in the email. | |
| 253 | + | |
| 254 | + | |
| 255 | +<a id="trouble"></a> | |
| 256 | +### Troubleshooting | |
| 257 | + | |
| 258 | +If email alerts aren't working, there are several useful commands you | |
| 259 | +can give to figure out why. | |
| 260 | + | |
| 261 | +(Be sure to [`cd` into a repo checkout directory](#cd) first!) | |
| 262 | + | |
| 263 | + $ fossil alerts status | |
| 264 | + | |
| 265 | +This should give much the same information as you saw [above](#status). | |
| 266 | +One difference is that, since you've created a forum post, the | |
| 267 | +`pending-alerts` value should only be zero if you did in fact get the | |
| 268 | +requested email alert. If it's zero, check your mailer's spam folder. If | |
| 269 | +it's nonzero, continue with these troubleshooting steps. | |
| 270 | + | |
| 271 | + $ fossil backoffice | |
| 272 | + | |
| 273 | +That forces Fossil to run its ["back office" process](./backoffice.md). | |
| 274 | +Its only purpose at the time of this writing is to push out alert | |
| 275 | +emails, but it might do other things later. Sometimes it can get stuck | |
| 276 | +and needs to be kicked. For that reason, you might want to set up a | |
| 277 | +crontab entry to make sure it runs occasionally. | |
| 278 | + | |
| 279 | + $ fossil alerts send | |
| 280 | + | |
| 281 | +This should also kick off the backoffice processing, if there are any | |
| 282 | +pending alerts to send out. | |
| 283 | + | |
| 284 | + $ fossil alert pending | |
| 285 | + | |
| 286 | +Show any pending alerts. The number of lines output here should equal | |
| 287 | +the [status output above](#status). | |
| 288 | + | |
| 289 | + $ fossil test-add-alerts f5900 | |
| 290 | + $ fossil alert send | |
| 291 | + | |
| 292 | +Manually create an email alert and push it out immediately. | |
| 293 | + | |
| 294 | +The `f` in the first command's final parameter means you're scheduling a | |
| 295 | +"forum" alert. The integer is the ID of a forum post, which you can find | |
| 296 | +by visiting `/timeline?showid` on your Fossil instance. | |
| 297 | + | |
| 298 | +The second command above is necessary because the `test-add-alerts` | |
| 299 | +command doesn't kick off a backoffice run. | |
| 300 | + | |
| 301 | + $ fossil ale send | |
| 302 | + | |
| 303 | +This only does the same thing as the final command above, rather than | |
| 304 | +send you an ale, as you might be hoping. Sorry. | |
| 305 | + | |
| 306 | + | |
| 307 | +<a id="advanced"></a> | |
| 308 | +## Advanced Email Setups | |
| 309 | + | |
| 310 | +Fossil offers several methods of sending email: | |
| 311 | + | |
| 312 | + 1. Pipe the email message text into a command. | |
| 313 | + 2. Store email messages as entries in a SQLite database. | |
| 314 | + 3. Store email messages as individual files in a directory. | |
| 315 | + 4. Send emails to an SMTP relay. | |
| 316 | + 5. Send emails directly to the recipients via SMTP. | |
| 317 | + | |
| 318 | +This wide range of options allows Fossil to talk to pretty much any | |
| 319 | +SMTP setup. | |
| 320 | + | |
| 321 | +The first four options let Fossil delegate email handling to an existing | |
| 322 | +[MTA][mta] so that Fossil does not need to implement the [roughly two | |
| 323 | +dozen][mprotos] separate [RFCs][rfcs] required in order to properly | |
| 324 | +support SMTP email in this complex world we've built. As well, this | |
| 325 | +design choice means you do not need to do duplicate configuration, such | |
| 326 | +as to point Fossil at your server's TLS certificate in order to support | |
| 327 | +users behind mail servers that require STARTTLS encryption. | |
| 328 | + | |
| 329 | +[mprotos]: http://sqlite.1065341.n5.nabble.com/Many-ML-emails-going-to-GMail-s-SPAM-tp98685p98722.html | |
| 330 | +[rfcs]: https://en.wikipedia.org/wiki/Request_for_Comments | |
| 331 | + | |
| 332 | + | |
| 333 | +<a id="pipe"></a> | |
| 334 | +### Method 1: Pipe to a Command | |
| 335 | + | |
| 336 | +This is our ["quick setup" option](#quick) above, but there are some | |
| 337 | +details we ignored which we'll cover now. | |
| 338 | + | |
| 339 | +Fossil pipes the email message in [RFC 822 format][rfc822] to the | |
| 340 | +standard input of the command you gave as the "Email Send Method", | |
| 341 | +defaulting to `sendmail -ti`. This constitutes a protocol between Fossil | |
| 342 | +and the SMTP [message transfer agent (MTA)][mta]. Any other MTA which | |
| 343 | +speaks the same protocol can be used in place of the most common | |
| 344 | +options: Sendmail, Exim, and Postfix. | |
| 345 | + | |
| 346 | +The `-t` option tells the command to expect the list of email recipients | |
| 347 | +in a `To` header in the RFC 822 message presented on its standard input. | |
| 348 | +Without this option, the `sendmail` command expects to receive the | |
| 349 | +recipient list on the command line, but that's not possible with the | |
| 350 | +current design of this email sending method. Therefore, if you're | |
| 351 | +attempting to use a less common MTA which cannot parse the recipient | |
| 352 | +list from the `To` header in the email message, you might need to look | |
| 353 | +for a different MTA. | |
| 354 | + | |
| 355 | +The `-i` option is only needed for MTAs that take a dot/period at the | |
| 356 | +beginning of a line of standard input text as "end of message." Fossil | |
| 357 | +doesn't attempt to escape such dots, so if the line wrapping happens to | |
| 358 | +occur such that a dot or period in an alert message is at the beginning | |
| 359 | +of a line, you'll get a truncated email message without this option. | |
| 360 | +Statistically, this will happen about once every 70 or so messages, so | |
| 361 | +it is important to give this option if your MTA treats leading dots on a | |
| 362 | +line this way. | |
| 363 | + | |
| 364 | +<a id="msmtp"></a> | |
| 365 | +We believe the [`msmtp`][msmtp] SMTP client is compatible with this | |
| 366 | +protocol if you give it the `-t` option. To our knowledge, this remains | |
| 367 | +untested, but if it works, this would be a useful option on a server | |
| 368 | +hosting a Fossil repository which doesn't otherwise require a separate | |
| 369 | +SMTP server for other purposes. | |
| 370 | + | |
| 371 | +It is probably also possible to configure [`procmail`][pmdoc] to work | |
| 372 | +with this protocol. If you know how to do it, a patch to this document | |
| 373 | +or a how-to on [the Fossil forum][ff] would be appreciated. | |
| 374 | + | |
| 375 | +[ff]: https://fossil-scm.org/forum/ | |
| 376 | +[msmtp]: https://marlam.de/msmtp/ | |
| 377 | +[mta]: https://en.wikipedia.org/wiki/Message_transfer_agent | |
| 378 | +[pmdoc]: http://pm-doc.sourceforge.net/doc/ | |
| 379 | +[rfc822]: https://www.w3.org/Protocols/rfc822/ | |
| 380 | + | |
| 381 | + | |
| 382 | +<a id="db"></a> | |
| 383 | +### Method 2: Store in a Database | |
| 384 | + | |
| 385 | +The self-hosting Fossil repository at <https://www.fossil-scm.org/> | |
| 386 | +currently uses this method rather than [the pipe method](#pipe) because | |
| 387 | +it is running inside of a restrictive [chroot jail][cj] which is unable | |
| 388 | +to hand off messages to the local MTA directly. | |
| 389 | + | |
| 390 | +When you configure a Fossil server this way, it adds outgoing email | |
| 391 | +messages to a SQLite database file. A separate daemon process can then | |
| 392 | +extract those messages for further disposition. | |
| 393 | + | |
| 394 | +Fossil includes a copy of [the daemon](/file/tools/email-sender.tcl) | |
| 395 | +used on `fossil-scm.org`: it is just a short Tcl script that | |
| 396 | +continuously monitors this database for new messages and hands any that | |
| 397 | +it finds off to a local MTA using the same [pipe to MTA protocol](#pipe) | |
| 398 | +as above. | |
| 399 | + | |
| 400 | +In this way, outbound email alerts escape the chroot jail without | |
| 401 | +requiring that we insert a separate MTA configuration inside that jail. | |
| 402 | +We only need to arrange that the same SQLite DB file be visible both | |
| 403 | +inside and outside the chroot jail, which we do by naming the database | |
| 404 | +file in the "Store Emails In This Database" setting under Admin → | |
| 405 | +Notification. The Tcl script has this path hard-coded as | |
| 406 | +`/home/www/fossil/emailqueue.db`, but you will probably need to adjust | |
| 407 | +that for your local purposes. | |
| 408 | + | |
| 409 | +This method may work with other similar technologies besides `chroot`: | |
| 410 | +Docker containers, LXC containers, BSD jails, Solaris zones, etc. | |
| 411 | + | |
| 412 | +With suitable file share mappings, this method may even work with | |
| 413 | +virtual machine or distributed computing setups where the MTA and Fossil | |
| 414 | +servers are not on the same machine, though beware the [risk of DB | |
| 415 | +corruption][rdbc] if used with a file sharing technology that doesn't | |
| 416 | +use proper file locking. | |
| 417 | + | |
| 418 | +You can start this Tcl script as a daemon automatically on most Unix and | |
| 419 | +Unix-like systems by adding the following line to the `/etc/rc.local` | |
| 420 | +file of the server that hosts the repository sending email alerts: | |
| 421 | + | |
| 422 | + /usr/bin/tclsh /home/www/fossil/email-sender.tcl & | |
| 423 | + | |
| 424 | +[cj]: https://en.wikipedia.org/wiki/Chroot | |
| 425 | +[rdbc]: https://www.sqlite.org/howtocorrupt.html#_filesystems_with_broken_or_missing_lock_implementations | |
| 426 | + | |
| 427 | + | |
| 428 | +<a id="dir"></a> | |
| 429 | +### Method 3: Store in a Directory | |
| 430 | + | |
| 431 | +This method is functionally very similar to [the DB method](#db), | |
| 432 | +differing only in that messages are written to a directory in the | |
| 433 | +filesystem. You should therefore read that section and make the minor | |
| 434 | +adjustments required by the storage method. | |
| 435 | + | |
| 436 | +This method may work over a file sharing mechanism that doesn't do file | |
| 437 | +locking properly, as long as the reading process is somehow restricted | |
| 438 | +from reading a message file as it's being written. | |
| 439 | + | |
| 440 | +It might be useful in testing and debugging to temporarily switch to | |
| 441 | +this method, since you can easily read the generated email messages | |
| 442 | +without needing to involve [an MTA][mta]. | |
| 443 | + | |
| 444 | + | |
| 445 | +<a id="relay"></a> | |
| 446 | +### Method 4: SMTP Relay | |
| 447 | + | |
| 448 | +In this configuration, the Fossil server contacts an open SMTP relay and | |
| 449 | +sends the messages to it. This method is only appropriate when: | |
| 450 | + | |
| 451 | +1. You have a local MTA that doesn't accept [the pipe | |
| 452 | + protocol](#pipe). | |
| 453 | + | |
| 454 | +2. The MTA is willing to accept anonymous submissions, since Fossil | |
| 455 | + currently has no way to authenticate itself to the MTA. This is [an | |
| 456 | + unsafe configuration][omr] in most cases, but some SMTP servers make | |
| 457 | + an exception for connections coming from a `localhost` or LAN | |
| 458 | + address, choosing to accept such submissions as inherently safe. | |
| 459 | + | |
| 460 | +If you have a local MTA meeting criterion #1 but not #2, we'd suggest | |
| 461 | +using a more powerful SMTP client such as [msmtp](#msmtp) along with one | |
| 462 | +of the other methods above. | |
| 463 | + | |
| 464 | +[omr]: https://en.wikipedia.org/wiki/Open_mail_relay | |
| 465 | + | |
| 466 | + | |
| 467 | +<a id="direct"></a> | |
| 468 | +### Method 5: Direct SMTP Send | |
| 469 | + | |
| 470 | +As of Fossil 2.7, the code to support this method is incomplete, so you | |
| 471 | +cannot currently select it as an option in Admin → Notification. | |
| 472 | + | |
| 473 | + | |
| 474 | +<a id="uvs"></a> | |
| 475 | +## Users vs Subscribers | |
| 476 | + | |
| 477 | +Fossil makes a distinction between "users" and "subscribers". A user is | |
| 478 | +someone with a username and password: that is, someone who can log into | |
| 479 | +the Fossi repository. A subscriber is someone who receives email | |
| 480 | +alerts. Users can also be subscribers and subscribers can be users, but | |
| 481 | +that does not have to be the case. It is possible to be a user without | |
| 482 | +being a subscriber and to be a subscriber without being a user. | |
| 483 | + | |
| 484 | +In the repository database file, users are tracked with the `user` table | |
| 485 | +and subscribers are tracked via the `subscriber` table. | |
| 486 | + | |
| 487 | + | |
| 488 | +<a id="admin"></a> | |
| 489 | +## Administrator Activities | |
| 490 | + | |
| 491 | +The "[List Subscribers](/subscribers)" button at the top of the Admin → | |
| 492 | +Notification screen gives a list of subscribers, which gives a Fossil | |
| 493 | +server administrator a lot of power over those subscriptions. | |
| 494 | + | |
| 495 | +Clicking an email address in this subscriber list opens the same | |
| 496 | +`/alerts` page that the user can see for their own subscription, but | |
| 497 | +with more information and functionality than normal users get: | |
| 498 | + | |
| 499 | +* Subscription creation and modification timestamps. | |
| 500 | + | |
| 501 | +* The IP address the user had when they last made a change via either | |
| 502 | + `/subscribe` or `/alert`. | |
| 503 | + | |
| 504 | +* The user's login name, if they are not [a mere subscriber](#uvs). A | |
| 505 | + Fossil Admin user is allowed to modify this, either to tie a | |
| 506 | + subscription-only record to an existing Fossil user account or to | |
| 507 | + break that tie. | |
| 508 | + | |
| 509 | +* The "Do not call" checkbox allows a Fossil Admin user to mark a given | |
| 510 | + email address so that Fossil never sends email to that address. This | |
| 511 | + is distinct from unsubscribing that email address because it prevents | |
| 512 | + Fossil from accepting a new subscription for that address. | |
| 513 | + | |
| 514 | +* The Verified checkbox is initially unchecked for subscriber-only | |
| 515 | + email addresses until the user clicks the link in the verification | |
| 516 | + email. This checkbox lets the Fossil Admin user manually verify the | |
| 517 | + user, such as in the case where the verification email message got | |
| 518 | + lost. Unchecking this box does not cause another verification email | |
| 519 | + to be sent. | |
| 520 | + | |
| 521 | +This screen also allows a Fossil Admin user to perform other activities | |
| 522 | +on behalf of a subscriber which they could do themselves, such as to | |
| 523 | +[unsubscribe](#unsub) them. | |
| 524 | + | |
| 525 | + | |
| 526 | +<a id="backup"></a> | |
| 527 | +## Cloning, Syncing, and Backups | |
| 528 | + | |
| 529 | +The Admin → Notification settings are not replicated using clone or | |
| 530 | +sync, and it is not possible to push such settings from one repository | |
| 531 | +to another. In a network of peer repositories, you only want one | |
| 532 | +repository sending email alerts. If you were to replicate the email | |
| 533 | +alert settings to a separate repository, then subscribers would get | |
| 534 | +multiple alerts for each event, which would be bad. | |
| 159 | 535 | |
| 160 | 536 | However, the subscriber list can be synced for backup purposes. Use the |
| 161 | 537 | [`fossil config pull subscriber`](/help?cmd=configuration) command to |
| 162 | 538 | pull the latest subscriber list from a server into a backup repository. |
| 539 | + | |
| 540 | +The `push`, `export`, and `import` commands all work similarly. | |
| 541 | + | |
| 542 | + | |
| 543 | +<a id="pages" name="commands"></a> | |
| 544 | +## Controlling the Email Alert System | |
| 545 | + | |
| 546 | +This section collects the list of Fossil UI pages and CLI commands that | |
| 547 | +control the email alert system, some of which have not been mentioned so | |
| 548 | +far: | |
| 549 | + | |
| 550 | +Commands: | |
| 551 | + | |
| 552 | + * The [`alerts`](/help?cmd=alerts) command | |
| 553 | + * The [`test-alert`](/help?cmd=test-alert) command | |
| 554 | + * The [`test-add-alerts`](/help?cmd=test-add-alerts) command | |
| 555 | + | |
| 556 | +Web pages available to users and subscribers: | |
| 557 | + | |
| 558 | + * The [`/subscribe`](/help?cmd=/subscribe) page | |
| 559 | + * The [`/alerts`](/help?cmd=/alerts) page | |
| 560 | + * The [`/unsubscribe`](/help?cmd=/unsubscribe) page | |
| 561 | + * The [`/contact_admin`](/help?cmd=/contact_admin) page | |
| 562 | + | |
| 563 | +Administrator-only web pages: | |
| 564 | + | |
| 565 | + * The [`/setup_notification`](/help?cmd=/setup_notification) page | |
| 566 | + * The [`/subscribers`](/help?cmd=/subscribers) page | |
| 567 | + | |
| 568 | + | |
| 569 | +<a id="design"></a> | |
| 570 | +## Design of Email Alerts | |
| 571 | + | |
| 572 | +This section describes the low-level design of the email alert system in | |
| 573 | +Fossil. This expands on the high-level administion focused material | |
| 574 | +above with minimal repetition. | |
| 575 | + | |
| 576 | +This section assumes expert-level systems knowledge. If the material | |
| 577 | +above sufficed for your purposes, feel free to skip this section, which | |
| 578 | +runs to the end of this document. | |
| 579 | + | |
| 580 | + | |
| 581 | +<a id="datades"></a> | |
| 582 | +### Data Design | |
| 583 | + | |
| 584 | +There are three new tables in the repository database, starting with | |
| 585 | +Fossil 2.7. These tables are not created in new repositories by | |
| 586 | +default. The tables only come into existence as needed when email | |
| 587 | +alerts are configured and used. | |
| 588 | + | |
| 589 | + | |
| 590 | + * <b>SUBSCRIBER</b> → | |
| 591 | + The subscriber table records the email address for people who | |
| 592 | + want to receive email notifications. Each subscriber has a | |
| 593 | + `subscriberCode` which is a random 32-byte blob that uniquely | |
| 594 | + identifies the subscriber. There are also fields to indicate | |
| 595 | + what kinds of notifications the subscriber wishes to receive, | |
| 596 | + whether or not the email address of the subscriber has been | |
| 597 | + verified, etc. | |
| 598 | + | |
| 599 | + * <b>PENDING\_ALERT</b> → | |
| 600 | + The PENDING\_ALERT table contains records that define events | |
| 601 | + about which alert emails might need to be sent. | |
| 602 | + A pending\_alert always refers to an entry in the | |
| 603 | + EVENT table. The EVENT table is part of the standard schema | |
| 604 | + and records timeline entries. In other words, there is one | |
| 605 | + row in the EVENT table for each possible timeline entry. The | |
| 606 | + PENDING\_ALERT table refers to EVENT table entries for which | |
| 607 | + we might need to send alert emails. | |
| 608 | + | |
| 609 | + * <b>EMAIL\_BOUNCE</b> → | |
| 610 | + This table is intended to record email bounce history so that | |
| 611 | + subscribers with excessive bounces can be turned off. That | |
| 612 | + logic has not yet been implemented so the EMAIL\_BOUNCE table | |
| 613 | + is currently unused. | |
| 614 | + | |
| 615 | +As pointed out above, ["subscribers" are distinct from "users"](#uvs). | |
| 616 | +The SUBSCRIBER.SUNAME field is the optional linkage between users and | |
| 617 | +subscribers. | |
| 618 | + | |
| 619 | + | |
| 620 | +<a id="stdout"></a> | |
| 621 | +### The "stdout" Method | |
| 622 | + | |
| 623 | +The [list of mail sending methods](#advanced) above left out an | |
| 624 | +internal-only method called "stdout" which simply writes the text of the | |
| 625 | +email message on standard output. The "stdout" method is used for | |
| 626 | +testing and debugging. If you need something similar and can't modify | |
| 627 | +your local Fossil instance to use this method, you might temporarily | |
| 628 | +switch to [the "dir" method](#dir) instead. | |
| 629 | + | |
| 630 | + | |
| 631 | +<a id="msgfmt"></a> | |
| 632 | +### Message Format | |
| 633 | + | |
| 634 | +The email messages generated by Fossil have a [well-formed | |
| 635 | +header][rfc822]. The downstream processing is expected to extract the | |
| 636 | +"To:", "From:", "Subject:" and whatever other attributes it needs from | |
| 637 | +the email header text. | |
| 638 | + | |
| 639 | +These emails use the `text/plain` MIME type with the UTF-8 character | |
| 640 | +set. We currently use a transfer encoding of `quoted-printable`, but | |
| 641 | +there is commented-out code in Fossil to switch to `base64` encoding, | |
| 642 | +which Fossil used in the early days leading up to the 2.7 release. | |
| 643 | + | |
| 644 | +If you switch Fossil back to `base64` mode, you may want to build a | |
| 645 | +utility program that ships in the Fossil source tree named | |
| 646 | +["tools/decode-email.c"](/file/tools/decode-email.c) which can decode | |
| 647 | +these messages into a human-readable format. | |
| 648 | + | |
| 649 | + | |
| 650 | +<a id="inbound" name="bounces"></a> | |
| 651 | +### Dealing with Inbound Email | |
| 652 | + | |
| 653 | +Inbound email messages — for example, bounces from failed alert emails — | |
| 654 | +should be relayed to the `fossil email inbound` command. That command | |
| 655 | +is currently a no-op place-holder. At some point, we will need to | |
| 656 | +design and write a bounce-message processing system for Fossil. | |
| 657 | + | |
| 658 | + | |
| 659 | +<a id="password" name="scode" name="verification"></a> | |
| 660 | +### Passwords vs Subscriber Codes | |
| 661 | + | |
| 662 | +When anonymous passers-by on the Internet sign up for email alerts, | |
| 663 | +their email address must first be verified. An email message is sent to | |
| 664 | +the address supplied inviting the user to click on a link. The link | |
| 665 | +includes a pseudorandom 128-bit blob encoded as 32 hexadecimal digits, | |
| 666 | +which serves in place of a password for that email address. (This is | |
| 667 | +stored in the database as `subscriber.subscriberCode`.) If anyone visits | |
| 668 | +the link, the email address is verified. | |
| 669 | + | |
| 670 | +Knowledge of the `subscriberCode` is sufficient to control a | |
| 671 | +subscription. | |
| 672 | + | |
| 673 | +Because this code is included in plain text in email alert messages, it | |
| 674 | +is not as secure as a separate password, but it has several virtues: | |
| 675 | + | |
| 676 | +* It is easier for the average subscriber to deal with in that they | |
| 677 | + don't have to come up with yet another password and store it safely. | |
| 678 | + | |
| 679 | +* If the `subscriberCode` is stolen, the worst that can happen is that | |
| 680 | + the thief can change that email address's subscription settings. | |
| 681 | + Contrast a password which may be shared with other services, which | |
| 682 | + then compromises those other services. | |
| 683 | + | |
| 684 | +* No PII other than the subscriber's email address is available to an | |
| 685 | + attacker with the `subscriberCode`. Nor can knowledge of the | |
| 686 | + `subscriberCode` lead to a email flood or other annoyance attack, as | |
| 687 | + far as I can see. | |
| 688 | + | |
| 689 | +If the `subscriberCodes` for a Fossil repository are ever compromised, | |
| 690 | +new ones can be generated as follows: | |
| 691 | + | |
| 692 | + UPDATE subscriber SET subscriberCode=randomblob(32); | |
| 693 | + | |
| 694 | +Since this then affects all new email alerts going out from Fossil, your | |
| 695 | +end users may never even realize that they're getting new codes, as long | |
| 696 | +as they don't click on the URLs in the footer of old alert messages. | |
| 697 | + | |
| 698 | +With that in mind, a Fossil server administrator could choose to | |
| 699 | +randomize the `subscriberCodes` periodically, such as just before the | |
| 700 | +daily digest emails are sent out each day. | |
| 701 | + | |
| 702 | +**Important:** All of the above is distinct from the passwords for users | |
| 703 | +with a Fossil repository login. Such users also have subscriber codes, | |
| 704 | +but those codes can only be used to modify the user's email alert | |
| 705 | +settings. That code cannot allow a user to log into the user's Fossil | |
| 706 | +repository account. | |
| 707 | + | |
| 708 | + | |
| 709 | +<a id="processing"></a> | |
| 710 | +### Internal Processing Flow | |
| 711 | + | |
| 712 | +Almost all of the email alert code is found in the | |
| 713 | +[`src/alerts.c`](/file/src/alerts.c) source file. | |
| 714 | + | |
| 715 | +When email alerts are enabled, a trigger is created in the schema | |
| 716 | +(`email_trigger1`) that adds a new entry to the `PENDING_ALERT` table | |
| 717 | +every time a row is added to the `EVENT` table. During a `fossil | |
| 718 | +rebuild`, the `EVENT` table is rebuilt from scratch; since we do not | |
| 719 | +want users to get alerts for every historical check-in, the trigger is | |
| 720 | +disabled during `rebuild`. | |
| 721 | + | |
| 722 | +Email alerts are sent out by the `alert_send_alerts()` function, which | |
| 723 | +is normally called automatically due to the `email-autoexec` setting, | |
| 724 | +which defaults to enabled. If that setting is disabled or if the user | |
| 725 | +simply wants to force email alerts to be sent immediately, they can give | |
| 726 | +a `fossil alert send` command, such as via a `cron` script. Each time | |
| 727 | +this function is called, the alert messages are moved further down the | |
| 728 | +chain, so you cannot cause duplicate alerts by calling it too often. | |
| 729 | + | |
| 730 | +Digests are handled by recording the time of the last digest in the | |
| 731 | +`email-last-digest` setting, and only sending a new digest if the | |
| 732 | +current time is one day or later after the last digest. | |
| 733 | + | |
| 734 | +Individual emails are sent to each subscriber. I (drh) ran tests and | |
| 735 | +found that I could send about 1200 emails/second, which is fast enough | |
| 736 | +that I do not need to resort to trying to notify multiple subscribers | |
| 737 | +with a single email. Because each subscriber gets a separate email, the | |
| 738 | +system can include information in the email that is unique to the | |
| 739 | +subscriber, such as a link to the page to edit their subscription. That | |
| 740 | +link includes the `subscriberCode`. | |
| 163 | 741 |
| --- www/alerts.md | |
| +++ www/alerts.md | |
| @@ -1,168 +1,740 @@ | |
| 1 | Email Alerts |
| 2 | ============ |
| 3 | |
| 4 | The email alert system is a work-in-progress. |
| 5 | This documentation was last updated on 2018-08-12. |
| 6 | Check back later for updates. |
| 7 | |
| 8 | Email Alerts And Notifications |
| ------------------------------- | |
| 9 | |
| 10 | Beginning with version 2.7, Fossil supports the ability to send |
| 11 | email messages to subscribers alerting them to changes in the repository. |
| 12 | Subscribers can request an email notification of the following kinds |
| 13 | of changes: |
| 14 | |
| 15 | * New check-ins |
| 16 | * Changes to any ticket |
| 17 | * Changes to any wiki page |
| 18 | * New forum posts |
| 19 | * Announcements |
| 20 | |
| 21 | Subscribers can either elect to receive emails as soon as these events happen, |
| 22 | or they can receive a daily digest of the events instead. |
| 23 | |
| 24 | Email alerts are sent by a [Fossil server](./server.wiki). You must |
| 25 | have a server [set up to make use of email alerts](#setup). Email |
| 26 | alerts do not currently work if you are only using Fossil from the |
| 27 | command line. |
| 28 | |
| 29 | Users and Subscribers |
| ---------------------- | |
| 30 | |
| 31 | Fossil makes a distinction between "users" and "subscribers". A |
| 32 | user is someone with a username and password — someone who can |
| 33 | log in. A subscriber is someone who receives email alerts. Users |
| 34 | can also be subscribers and subscribers can be users, but that does |
| 35 | not have to be the case. It is possible to be a user without being |
| 36 | a subscriber and to be a subscriber without being a user. |
| 37 | |
| 38 | In the repository database file, users are tracked with the USER table |
| 39 | and subscribers are tracked via the SUBSCRIBER table. |
| 40 | |
| 41 | <a id="setup"></a> |
| 42 | Activating Email Alerts |
| ------------------------ | |
| 43 | |
| 44 | Email alerts are turned off by default. To activate them, log into |
| 45 | the Fossil server as an administrator and visit the |
| 46 | [Admin/Notification](/setup_notification) |
| 47 | setup page. ([`/setup_notification`](/setup_notification)) |
| 48 | |
| 49 | Important: Email alerts are configured using Admin/Notification, not |
| 50 | Admin/Email-Server. The Email-Server setup screen is used to configure |
| 51 | a different subsystem within Fossil. |
| 52 | |
| 53 | The Admin/Notification setup screen lets you configure how Fossil should |
| 54 | send email for alerts. There are some required fields at the top of the |
| 55 | screen for elements such as the "From:" address for outgoing emails, |
| 56 | the URL for the Fossil server, and a nickname for the repository that |
| 57 | will appear in the "Subject:" line of outgoing emails. But the key |
| 58 | setup parameter is the "Email Send Method". |
| 59 | |
| 60 | Fossil supports multiple methods for sending email alerts: |
| 61 | |
| 62 | 1. Pipe the email message text into a command, such as `sendmail`. |
| 63 | 2. Store email messages as individual files in a directory and let |
| 64 | some other process set up by the administrator take care of |
| 65 | reading and forwarding those files. |
| 66 | 3. Store email messages as entries in an SQLite database where |
| 67 | some external process and read and forward the emails. |
| 68 | 4. Send emails to an SMTP Relay. |
| 69 | 5. Send emails directly to the recipients via SMTP. |
| 70 | |
| 71 | As of 2018-08-08, method (5) is not yet supported, but there are plans |
| 72 | to add support soon. |
| 73 | |
| 74 | The self-hosting Fossil repository at <https://www.fossil-scm.org/> currently |
| 75 | uses method (3). Outgoing email messages are added to an SQLite database |
| 76 | file. A separate daemon process continously monitors that database file, |
| 77 | extracts email messages as they are added, and hands them off to |
| 78 | "procmail" to be sent on to the final recipient. The self-hosting |
| 79 | Fossil repository uses this technique rather than method (1) because |
| 80 | it is running inside of a restrictive chroot jail which is unable to |
| 81 | hand off messages to "procmail" directly. The daemon that monitors the |
| 82 | email database is a [short TCL script](/file/tools/email-sender.tcl). |
| 83 | That daemon is started automatically by adding this line: |
| 84 | |
| 85 | /usr/bin/tclsh /home/www/fossil/email-sender.tcl & |
| 86 | |
| 87 | To the `/etc/rc.local` file of the Ubuntu server that hosts the |
| 88 | repository. |
| 89 | |
| 90 | After making necessary changes to the Admin/Notification page, test |
| 91 | those changes by clicking the "[Send Announcement](/announce)" link |
| 92 | at the top of the page. Fill in your email address in the "To:" |
| 93 | line and a test message below, and press "Send Message" to verify that |
| 94 | outgoing email is working. |
| 95 | |
| 96 | <a id="cap7"></a> |
| 97 | Once email notification is working, one must also adjust user permissions |
| 98 | to allow users to subscribe to email notification. On the |
| 99 | Setup/User page, under the permissions for each user, is a new capability |
| 100 | called "Email Alerts". The corresponding capability letter is "7". |
| 101 | That new "7" capability must be enabled in order for |
| 102 | users to be able to become subscribers. To allow anonymous passers-by |
| 103 | on the internet to subscribe, simply enable "Email Alerts" for the |
| 104 | "nobody" user category. To require that the user solve a simple CAPTCHA |
| 105 | first, add it to the "anonymous" user category instead. |
| 106 | |
| 107 | Signing Up For Email Notification |
| ---------------------------------- | |
| 108 | |
| 109 | Users and/or anonymous passers-by can visit the |
| 110 | [`/subscribe`](/subscribe) page to sign |
| 111 | up for email notification. |
| 112 | |
| 113 | If your users are getting the following complaint from Fossil: |
| 114 | |
| 115 | <blockquote> |
| 116 | Use a different login with greater privilege than FOO to access |
| 117 | /subscribe |
| 118 | </blockquote> |
| 119 | |
| 120 | ...then you forgot to [give capability 7](#cap7) to that user or to a |
| 121 | user category that the user is a member of. |
| 122 | |
| 123 | After signing up, a single verification email |
| 124 | is sent. The new subscriber must click a link on that email in order to |
| 125 | activate the subscription. |
| 126 | |
| 127 | Subscription verification emails are only sent once. This is a defense |
| 128 | against malicious robots that try to harass innocent internet users |
| 129 | by having subscription pages send multiple verification emails. |
| 130 | If the initial subscription verification does not go through correctly, |
| 131 | an administrator must intervene to reset the subscription. |
| 132 | |
| 133 | Every subscriber has a long random hexadecimal security code that serves |
| 134 | as their password. All email notifications contain a link back to the |
| 135 | Fossil server, incorporating this security code, which allows the |
| 136 | subscriber to adjust their subscription options. |
| 137 | |
| 138 | Administrator Activities |
| ------------------------- | |
| 139 | |
| 140 | The repository administrator has unlimited control over individual |
| 141 | subscriptions. The "[List Subscribers](/subscribers)" button at the top |
| 142 | of the Setup/Notification screen gives a list of subscribers. Clicking on |
| 143 | any subscriber link allows the administrator to adjust the subscription. |
| 144 | |
| 145 | To unsubscribe, first select the "unsubscribe" checkbox, then press the |
| 146 | "Unsubscribe" button. |
| 147 | |
| 148 | The "verified" checkbox determines whether or not an email address has |
| 149 | been verified. This can be enabled or disabled manually by the |
| 150 | administrator. |
| 151 | |
| 152 | Cloning, Syncing, and Backups |
| ------------------------------ | |
| 153 | |
| 154 | The Setup/Notification settings are not replicated using clone or sync. |
| 155 | In a network of peer repositories, you only want one repository sending |
| 156 | email notifications. If you were to replicate the email notification |
| 157 | settings to a separate repository, then subscribers would get multiple |
| 158 | notifications for each event, which would be bad. |
| 159 | |
| 160 | However, the subscriber list can be synced for backup purposes. Use the |
| 161 | [`fossil config pull subscriber`](/help?cmd=configuration) command to |
| 162 | pull the latest subscriber list from a server into a backup repository. |
| 163 |
| --- www/alerts.md | |
| +++ www/alerts.md | |
| @@ -1,168 +1,740 @@ | |
| ------------------------------- | |
| 1 | # Email Alerts |
| 2 | |
| 3 | ## Overview |
| 4 | |
| 5 | Beginning with version 2.7, Fossil can send email messages to |
| 6 | subscribers to alert them to changes in the repository: |
| 7 | |
| 8 | * New [checkins](/help?cmd=ci) |
| 9 | * [Ticket](./tickets.wiki) changes |
| 10 | * [Wiki](./wikitheory.wiki) page changes |
| 11 | * New and edited [forum](./forum.wiki) posts |
| 12 | * Announcements |
| 13 | |
| 14 | Subscribers can elect to receive emails as soon as these events happen, |
| 15 | or they can receive a daily digest of the events instead. |
| 16 | |
| 17 | Email alerts are sent by a [Fossil server](./server.wiki), which must be |
| 18 | [set up](#quick) by the Fossil administrator to send email. |
| 19 | |
| 20 | Email alerts do not currently work if you are only using Fossil from the |
| 21 | command line. |
| 22 | |
| ---------------------- | |
| ------------------------ | |
| ---------------------------------- | |
| 23 | A bit of terminology: Fossil uses the terms "email alerts" and |
| 24 | "notifications" interchangeably. We stick to the former term in this |
| 25 | document except when referring to parts of the Fossil UI still using the |
| 26 | latter term. |
| 27 | |
| 28 | |
| 29 | ## Setup Prerequisites |
| 30 | |
| 31 | Much of this document describes how to set up Fossil's email alert |
| 32 | system. To follow this guide, you will need a Fossil UI browser window |
| 33 | open to the [Admin → Notification](/setup_notification) Fossil UI screen |
| 34 | on the the Fossil server that will be sending these email alerts, logged |
| 35 | in as a user with Admin capability. It is not possible to work on a |
| 36 | clone of the server's repository and push the configuration changes up |
| 37 | to that repo as an Admin user, [on purpose](#backup). |
| 38 | |
| 39 | **Important:** Do not confuse that screen with Admin → Email-Server, |
| 40 | which sets up a different subsystem within Fossil. That feature is |
| 41 | related to this document's topic, but it is currently incomplete, so we |
| 42 | do not cover it at this time. |
| 43 | |
| 44 | <a id="cd"></a> |
| 45 | You will also need a CLI window open with its working directory changed |
| 46 | to a checkout directory of the Fossil repository you are setting up to |
| 47 | send email. If you don't `cd` to such a checkout directory first, |
| 48 | you'll need to add `-R /path/to/repo.fossil` to each `fossil` command |
| 49 | below to tell Fossil which repository you mean it to apply the command |
| 50 | to. |
| 51 | |
| 52 | There are other prerequisites for email service, but since they vary |
| 53 | depending on the configuration you choose, we'll cover these inline |
| 54 | below. |
| 55 | |
| 56 | |
| 57 | <a id="quick"></a> |
| 58 | ## Quick Email Service Setup |
| 59 | |
| 60 | If you've already got a working Postfix, Exim, or Sendmail server on the |
| 61 | machine running your Fossil instance(s), and you aren't using Fossil's |
| 62 | `chroot` feature to wall Fossil off from the rest of the machine, it's |
| 63 | fairly simple to set up email alerts. |
| 64 | |
| 65 | (Otherwise, skip [ahead](#advanced) to the sections on advanced email |
| 66 | service setup.) |
| 67 | |
| 68 | This is our "quick setup" option even though setting up an SMTP mail |
| 69 | server is not trival, because there are many other reasons to have such |
| 70 | a server set up already: internal project email service, `cron` |
| 71 | notifications, server status monitoring notifications... |
| 72 | |
| 73 | With that out of the way, the Fossil-specific steps are easy: |
| 74 | |
| 75 | 1. Go to [Admin → Notification](/setup_notification) and fill out all |
| 76 | of the **Required** fields: |
| 77 | |
| 78 | * **Canonical server URL** — Use the suggested URL |
| 79 | |
| 80 | * **"From" email address** — `[email protected]` is |
| 81 | traditional, but suit yourself |
| 82 | |
| 83 | * **Repository nickname** — See the suggested examples on the web page. |
| 84 | |
| 85 | 2. Set "Email Send Method" to "Pipe to a command" |
| 86 | |
| 87 | 3. Set the "Administrator email address" to a suitable valid email |
| 88 | address on that machine. It could be the same value you used for |
| 89 | the "From" address above, or it could be a different value like |
| 90 | `[email protected]`. |
| 91 | |
| 92 | Save your changes. |
| 93 | |
| 94 | At the command line, say |
| 95 | |
| 96 | $ fossil set email-send-command |
| 97 | |
| 98 | If that gives a blank value instead of `sendmail -ti`, say |
| 99 | |
| 100 | $ fossil set email-send-command "sendmail -ti" |
| 101 | |
| 102 | to force the setting. That works around a [known |
| 103 | bug](https://fossil-scm.org/forum/forumpost/840b676410) which may be |
| 104 | squished by the time you read this. |
| 105 | |
| 106 | If you're running Postfix or Exim, you might think that command is |
| 107 | wrong, since you aren't running Sendmail. These mail servers provide a |
| 108 | `sendmail` command for compatibility with software like Fossil that has |
| 109 | no good reason to care exactly which SMTP server implementation is |
| 110 | running at a given site. There may be other SMTP servers that also |
| 111 | provide a compatible `sendmail` command, in which case they may work |
| 112 | with Fossil using the same steps as above. |
| 113 | |
| 114 | <a id="status"></a> |
| 115 | If you reload the Admin → Notification page, the Status section at the |
| 116 | top should show: |
| 117 | |
| 118 | Outgoing Email: Piped to command "sendmail -ti" |
| 119 | Pending Alerts: 0 normal, 0 digest |
| 120 | Subscribers: 0 active, 0 total |
| 121 | |
| 122 | Before you move on to the next section, you might like to read up on |
| 123 | [some subtleties](#pipe) with the "pipe to a command" method that we did |
| 124 | not cover above. |
| 125 | |
| 126 | |
| 127 | <a id="usage"></a> |
| 128 | ## Usage and Testing |
| 129 | |
| 130 | Now that email service from Fossil is set up, you can test it and begin |
| 131 | using it. |
| 132 | |
| 133 | |
| 134 | <a id="sub" name="subscribe"></a> |
| 135 | ### Subscribing to Alerts |
| 136 | |
| 137 | In the Status output above, we saw that there are no subscribers, so the |
| 138 | next step is to add the first one. |
| 139 | |
| 140 | Go to the `/subscribe` page on your Fossil instance to sign up for email |
| 141 | alerts. At the very least, you will need to sign up for "Forum Posts" |
| 142 | and "Announcements" to complete the testing steps below. |
| 143 | |
| 144 | If you're logged in with a Fossil repository user account and put the |
| 145 | same user name and email address into this forum as you used for your |
| 146 | user information under Admin → Users, Fossil will simply tie your alert |
| 147 | preferences to your login record, and the email address in your user's |
| 148 | Contact Info field will be considered already-verified. Otherwise, |
| 149 | Fossil will create an alert-only record, and you will have to verify the |
| 150 | email address before Fossil will send alerts to it. |
| 151 | |
| 152 | This shows a key aspect of the way Fossil's email alerts system works, |
| 153 | by the way: a user can be signed up for email alerts without having a |
| 154 | full-fledged Fossil user account. Only when both user names are the same |
| 155 | are the two records tied together under the hood. For more on this, see |
| 156 | [Users vs Subscribers below](#uvs). |
| 157 | |
| 158 | If you are seeing the following complaint from Fossil: |
| 159 | |
| 160 | <blockquote> |
| 161 | Use a different login with greater privilege than FOO to access |
| 162 | /subscribe |
| 163 | </blockquote> |
| 164 | |
| 165 | ...then the repository's administrator forgot to [give the Alerts capability](#cap7) |
| 166 | to that user or to a user category that the user is a member of. |
| 167 | |
| 168 | After a subscriber signs up for alerts for the first time, a single |
| 169 | verification email is sent to that subscriber's given email address. |
| 170 | The new subscriber must click a link in that email in order to activate |
| 171 | the subscription. |
| 172 | |
| 173 | Subscription verification emails are only sent once. This is a defense |
| ------------------------- | |
| ------------------------------ | |
| 174 | against malicious robots that try to harass innocent Internet users by |
| 175 | having subscription pages send multiple verification emails. If the |
| 176 | initial subscription verification does not go through correctly, an |
| 177 | administrator must [intervene](#admin) to reset the subscription. |
| 178 | |
| 179 | Every subscriber-only email address has a [long random hexadecimal |
| 180 | security code](#scode) that serves in place of a password. All email |
| 181 | alerts contain a link in their footer back to the Fossil server, |
| 182 | incorporating this security code, which allows the subscriber to adjust |
| 183 | their subscription options. If a user doesn't have any of those emails, |
| 184 | they can request a link via email by visiting the `/alerts` or |
| 185 | `/unsubscribe` page on the repository. |
| 186 | |
| 187 | Those with Fossil repository logins can adjust their email alert |
| 188 | settings by visiting the `/alerts` page on the repository. With the |
| 189 | default skin, you can get there by clicking the "Logout" link in the |
| 190 | upper right corner of any Fossil UI page then clicking the "Email |
| 191 | Alerts" link. That link is also available via the Sitemap (`/sitemap`) |
| 192 | and via the default skin's hamburger menu (☰). |
| 193 | |
| 194 | |
| 195 | <a id="unsub" name="unsubscribe"></a> |
| 196 | ### Unsubscribing |
| 197 | |
| 198 | To unsubscribe from alerts, visit the `/alerts` page on the repository, |
| 199 | click the "Unsubscribe" button, then check the "Unsbuscribe" checkbox to |
| 200 | verify your action and press the "Unsubscribe" button a second time. |
| 201 | |
| 202 | This interlock is intended to prevent accidental unsubscription. |
| 203 | |
| 204 | |
| 205 | <a id="test"></a> |
| 206 | ### Test Email Service |
| 207 | |
| 208 | The easiest way to test email sending from Fossil is via the "[Send |
| 209 | Announcement](/announce)" link at the top of the "Email Notification |
| 210 | Setup" page. Put your email address in the "To:" line and a test |
| 211 | message below, then press "Send Message" to verify that outgoing email |
| 212 | is working. |
| 213 | |
| 214 | Another method is from the command line: |
| 215 | |
| 216 | $ fossil alerts test-message [email protected] --body README.md --subject Test |
| 217 | |
| 218 | That should send you an email with "Test" in the subject line and the |
| 219 | contents of your project's `README.md` file in the body. |
| 220 | |
| 221 | That command assumes that your project contains a "readme" file, but of |
| 222 | course it does, because you have followed the [Programming Style Guide |
| 223 | Checklist][cl], right? Right. |
| 224 | |
| 225 | [cl]: https://sendgrid.com/blog/programming-style-guide-checklist/ |
| 226 | |
| 227 | |
| 228 | <a id="cap7"></a> |
| 229 | ### User Capabilities |
| 230 | |
| 231 | Once email alerts are working, one must also adjust user permissions to |
| 232 | allow users to subscribe to email alerts. In the capability list for |
| 233 | each user on the Admin → Users page is a new capability called "Email |
| 234 | Alerts". The corresponding capability letter is "7", which you must |
| 235 | give to any user that needs to use the subscription setup pages, |
| 236 | `/subscribe` and `/alerts`. |
| 237 | |
| 238 | To allow any passer-by on the Internet to subscribe, give the "Email |
| 239 | Alerts" capability to the "nobody" user category. To require that a |
| 240 | person solve a simple CAPTCHA first, give that capability to the |
| 241 | "anonymous" user category instead. |
| 242 | |
| 243 | |
| 244 | <a id="first" name="frist"></a> |
| 245 | ### First Post |
| 246 | |
| 247 | I suggest taking the time to compose a suitable introductory message |
| 248 | especially for your project's forum, one which a new user would find |
| 249 | helpful. |
| 250 | |
| 251 | Wait a few seconds, and you should receive an email alert with the |
| 252 | post's subject and body text in the email. |
| 253 | |
| 254 | |
| 255 | <a id="trouble"></a> |
| 256 | ### Troubleshooting |
| 257 | |
| 258 | If email alerts aren't working, there are several useful commands you |
| 259 | can give to figure out why. |
| 260 | |
| 261 | (Be sure to [`cd` into a repo checkout directory](#cd) first!) |
| 262 | |
| 263 | $ fossil alerts status |
| 264 | |
| 265 | This should give much the same information as you saw [above](#status). |
| 266 | One difference is that, since you've created a forum post, the |
| 267 | `pending-alerts` value should only be zero if you did in fact get the |
| 268 | requested email alert. If it's zero, check your mailer's spam folder. If |
| 269 | it's nonzero, continue with these troubleshooting steps. |
| 270 | |
| 271 | $ fossil backoffice |
| 272 | |
| 273 | That forces Fossil to run its ["back office" process](./backoffice.md). |
| 274 | Its only purpose at the time of this writing is to push out alert |
| 275 | emails, but it might do other things later. Sometimes it can get stuck |
| 276 | and needs to be kicked. For that reason, you might want to set up a |
| 277 | crontab entry to make sure it runs occasionally. |
| 278 | |
| 279 | $ fossil alerts send |
| 280 | |
| 281 | This should also kick off the backoffice processing, if there are any |
| 282 | pending alerts to send out. |
| 283 | |
| 284 | $ fossil alert pending |
| 285 | |
| 286 | Show any pending alerts. The number of lines output here should equal |
| 287 | the [status output above](#status). |
| 288 | |
| 289 | $ fossil test-add-alerts f5900 |
| 290 | $ fossil alert send |
| 291 | |
| 292 | Manually create an email alert and push it out immediately. |
| 293 | |
| 294 | The `f` in the first command's final parameter means you're scheduling a |
| 295 | "forum" alert. The integer is the ID of a forum post, which you can find |
| 296 | by visiting `/timeline?showid` on your Fossil instance. |
| 297 | |
| 298 | The second command above is necessary because the `test-add-alerts` |
| 299 | command doesn't kick off a backoffice run. |
| 300 | |
| 301 | $ fossil ale send |
| 302 | |
| 303 | This only does the same thing as the final command above, rather than |
| 304 | send you an ale, as you might be hoping. Sorry. |
| 305 | |
| 306 | |
| 307 | <a id="advanced"></a> |
| 308 | ## Advanced Email Setups |
| 309 | |
| 310 | Fossil offers several methods of sending email: |
| 311 | |
| 312 | 1. Pipe the email message text into a command. |
| 313 | 2. Store email messages as entries in a SQLite database. |
| 314 | 3. Store email messages as individual files in a directory. |
| 315 | 4. Send emails to an SMTP relay. |
| 316 | 5. Send emails directly to the recipients via SMTP. |
| 317 | |
| 318 | This wide range of options allows Fossil to talk to pretty much any |
| 319 | SMTP setup. |
| 320 | |
| 321 | The first four options let Fossil delegate email handling to an existing |
| 322 | [MTA][mta] so that Fossil does not need to implement the [roughly two |
| 323 | dozen][mprotos] separate [RFCs][rfcs] required in order to properly |
| 324 | support SMTP email in this complex world we've built. As well, this |
| 325 | design choice means you do not need to do duplicate configuration, such |
| 326 | as to point Fossil at your server's TLS certificate in order to support |
| 327 | users behind mail servers that require STARTTLS encryption. |
| 328 | |
| 329 | [mprotos]: http://sqlite.1065341.n5.nabble.com/Many-ML-emails-going-to-GMail-s-SPAM-tp98685p98722.html |
| 330 | [rfcs]: https://en.wikipedia.org/wiki/Request_for_Comments |
| 331 | |
| 332 | |
| 333 | <a id="pipe"></a> |
| 334 | ### Method 1: Pipe to a Command |
| 335 | |
| 336 | This is our ["quick setup" option](#quick) above, but there are some |
| 337 | details we ignored which we'll cover now. |
| 338 | |
| 339 | Fossil pipes the email message in [RFC 822 format][rfc822] to the |
| 340 | standard input of the command you gave as the "Email Send Method", |
| 341 | defaulting to `sendmail -ti`. This constitutes a protocol between Fossil |
| 342 | and the SMTP [message transfer agent (MTA)][mta]. Any other MTA which |
| 343 | speaks the same protocol can be used in place of the most common |
| 344 | options: Sendmail, Exim, and Postfix. |
| 345 | |
| 346 | The `-t` option tells the command to expect the list of email recipients |
| 347 | in a `To` header in the RFC 822 message presented on its standard input. |
| 348 | Without this option, the `sendmail` command expects to receive the |
| 349 | recipient list on the command line, but that's not possible with the |
| 350 | current design of this email sending method. Therefore, if you're |
| 351 | attempting to use a less common MTA which cannot parse the recipient |
| 352 | list from the `To` header in the email message, you might need to look |
| 353 | for a different MTA. |
| 354 | |
| 355 | The `-i` option is only needed for MTAs that take a dot/period at the |
| 356 | beginning of a line of standard input text as "end of message." Fossil |
| 357 | doesn't attempt to escape such dots, so if the line wrapping happens to |
| 358 | occur such that a dot or period in an alert message is at the beginning |
| 359 | of a line, you'll get a truncated email message without this option. |
| 360 | Statistically, this will happen about once every 70 or so messages, so |
| 361 | it is important to give this option if your MTA treats leading dots on a |
| 362 | line this way. |
| 363 | |
| 364 | <a id="msmtp"></a> |
| 365 | We believe the [`msmtp`][msmtp] SMTP client is compatible with this |
| 366 | protocol if you give it the `-t` option. To our knowledge, this remains |
| 367 | untested, but if it works, this would be a useful option on a server |
| 368 | hosting a Fossil repository which doesn't otherwise require a separate |
| 369 | SMTP server for other purposes. |
| 370 | |
| 371 | It is probably also possible to configure [`procmail`][pmdoc] to work |
| 372 | with this protocol. If you know how to do it, a patch to this document |
| 373 | or a how-to on [the Fossil forum][ff] would be appreciated. |
| 374 | |
| 375 | [ff]: https://fossil-scm.org/forum/ |
| 376 | [msmtp]: https://marlam.de/msmtp/ |
| 377 | [mta]: https://en.wikipedia.org/wiki/Message_transfer_agent |
| 378 | [pmdoc]: http://pm-doc.sourceforge.net/doc/ |
| 379 | [rfc822]: https://www.w3.org/Protocols/rfc822/ |
| 380 | |
| 381 | |
| 382 | <a id="db"></a> |
| 383 | ### Method 2: Store in a Database |
| 384 | |
| 385 | The self-hosting Fossil repository at <https://www.fossil-scm.org/> |
| 386 | currently uses this method rather than [the pipe method](#pipe) because |
| 387 | it is running inside of a restrictive [chroot jail][cj] which is unable |
| 388 | to hand off messages to the local MTA directly. |
| 389 | |
| 390 | When you configure a Fossil server this way, it adds outgoing email |
| 391 | messages to a SQLite database file. A separate daemon process can then |
| 392 | extract those messages for further disposition. |
| 393 | |
| 394 | Fossil includes a copy of [the daemon](/file/tools/email-sender.tcl) |
| 395 | used on `fossil-scm.org`: it is just a short Tcl script that |
| 396 | continuously monitors this database for new messages and hands any that |
| 397 | it finds off to a local MTA using the same [pipe to MTA protocol](#pipe) |
| 398 | as above. |
| 399 | |
| 400 | In this way, outbound email alerts escape the chroot jail without |
| 401 | requiring that we insert a separate MTA configuration inside that jail. |
| 402 | We only need to arrange that the same SQLite DB file be visible both |
| 403 | inside and outside the chroot jail, which we do by naming the database |
| 404 | file in the "Store Emails In This Database" setting under Admin → |
| 405 | Notification. The Tcl script has this path hard-coded as |
| 406 | `/home/www/fossil/emailqueue.db`, but you will probably need to adjust |
| 407 | that for your local purposes. |
| 408 | |
| 409 | This method may work with other similar technologies besides `chroot`: |
| 410 | Docker containers, LXC containers, BSD jails, Solaris zones, etc. |
| 411 | |
| 412 | With suitable file share mappings, this method may even work with |
| 413 | virtual machine or distributed computing setups where the MTA and Fossil |
| 414 | servers are not on the same machine, though beware the [risk of DB |
| 415 | corruption][rdbc] if used with a file sharing technology that doesn't |
| 416 | use proper file locking. |
| 417 | |
| 418 | You can start this Tcl script as a daemon automatically on most Unix and |
| 419 | Unix-like systems by adding the following line to the `/etc/rc.local` |
| 420 | file of the server that hosts the repository sending email alerts: |
| 421 | |
| 422 | /usr/bin/tclsh /home/www/fossil/email-sender.tcl & |
| 423 | |
| 424 | [cj]: https://en.wikipedia.org/wiki/Chroot |
| 425 | [rdbc]: https://www.sqlite.org/howtocorrupt.html#_filesystems_with_broken_or_missing_lock_implementations |
| 426 | |
| 427 | |
| 428 | <a id="dir"></a> |
| 429 | ### Method 3: Store in a Directory |
| 430 | |
| 431 | This method is functionally very similar to [the DB method](#db), |
| 432 | differing only in that messages are written to a directory in the |
| 433 | filesystem. You should therefore read that section and make the minor |
| 434 | adjustments required by the storage method. |
| 435 | |
| 436 | This method may work over a file sharing mechanism that doesn't do file |
| 437 | locking properly, as long as the reading process is somehow restricted |
| 438 | from reading a message file as it's being written. |
| 439 | |
| 440 | It might be useful in testing and debugging to temporarily switch to |
| 441 | this method, since you can easily read the generated email messages |
| 442 | without needing to involve [an MTA][mta]. |
| 443 | |
| 444 | |
| 445 | <a id="relay"></a> |
| 446 | ### Method 4: SMTP Relay |
| 447 | |
| 448 | In this configuration, the Fossil server contacts an open SMTP relay and |
| 449 | sends the messages to it. This method is only appropriate when: |
| 450 | |
| 451 | 1. You have a local MTA that doesn't accept [the pipe |
| 452 | protocol](#pipe). |
| 453 | |
| 454 | 2. The MTA is willing to accept anonymous submissions, since Fossil |
| 455 | currently has no way to authenticate itself to the MTA. This is [an |
| 456 | unsafe configuration][omr] in most cases, but some SMTP servers make |
| 457 | an exception for connections coming from a `localhost` or LAN |
| 458 | address, choosing to accept such submissions as inherently safe. |
| 459 | |
| 460 | If you have a local MTA meeting criterion #1 but not #2, we'd suggest |
| 461 | using a more powerful SMTP client such as [msmtp](#msmtp) along with one |
| 462 | of the other methods above. |
| 463 | |
| 464 | [omr]: https://en.wikipedia.org/wiki/Open_mail_relay |
| 465 | |
| 466 | |
| 467 | <a id="direct"></a> |
| 468 | ### Method 5: Direct SMTP Send |
| 469 | |
| 470 | As of Fossil 2.7, the code to support this method is incomplete, so you |
| 471 | cannot currently select it as an option in Admin → Notification. |
| 472 | |
| 473 | |
| 474 | <a id="uvs"></a> |
| 475 | ## Users vs Subscribers |
| 476 | |
| 477 | Fossil makes a distinction between "users" and "subscribers". A user is |
| 478 | someone with a username and password: that is, someone who can log into |
| 479 | the Fossi repository. A subscriber is someone who receives email |
| 480 | alerts. Users can also be subscribers and subscribers can be users, but |
| 481 | that does not have to be the case. It is possible to be a user without |
| 482 | being a subscriber and to be a subscriber without being a user. |
| 483 | |
| 484 | In the repository database file, users are tracked with the `user` table |
| 485 | and subscribers are tracked via the `subscriber` table. |
| 486 | |
| 487 | |
| 488 | <a id="admin"></a> |
| 489 | ## Administrator Activities |
| 490 | |
| 491 | The "[List Subscribers](/subscribers)" button at the top of the Admin → |
| 492 | Notification screen gives a list of subscribers, which gives a Fossil |
| 493 | server administrator a lot of power over those subscriptions. |
| 494 | |
| 495 | Clicking an email address in this subscriber list opens the same |
| 496 | `/alerts` page that the user can see for their own subscription, but |
| 497 | with more information and functionality than normal users get: |
| 498 | |
| 499 | * Subscription creation and modification timestamps. |
| 500 | |
| 501 | * The IP address the user had when they last made a change via either |
| 502 | `/subscribe` or `/alert`. |
| 503 | |
| 504 | * The user's login name, if they are not [a mere subscriber](#uvs). A |
| 505 | Fossil Admin user is allowed to modify this, either to tie a |
| 506 | subscription-only record to an existing Fossil user account or to |
| 507 | break that tie. |
| 508 | |
| 509 | * The "Do not call" checkbox allows a Fossil Admin user to mark a given |
| 510 | email address so that Fossil never sends email to that address. This |
| 511 | is distinct from unsubscribing that email address because it prevents |
| 512 | Fossil from accepting a new subscription for that address. |
| 513 | |
| 514 | * The Verified checkbox is initially unchecked for subscriber-only |
| 515 | email addresses until the user clicks the link in the verification |
| 516 | email. This checkbox lets the Fossil Admin user manually verify the |
| 517 | user, such as in the case where the verification email message got |
| 518 | lost. Unchecking this box does not cause another verification email |
| 519 | to be sent. |
| 520 | |
| 521 | This screen also allows a Fossil Admin user to perform other activities |
| 522 | on behalf of a subscriber which they could do themselves, such as to |
| 523 | [unsubscribe](#unsub) them. |
| 524 | |
| 525 | |
| 526 | <a id="backup"></a> |
| 527 | ## Cloning, Syncing, and Backups |
| 528 | |
| 529 | The Admin → Notification settings are not replicated using clone or |
| 530 | sync, and it is not possible to push such settings from one repository |
| 531 | to another. In a network of peer repositories, you only want one |
| 532 | repository sending email alerts. If you were to replicate the email |
| 533 | alert settings to a separate repository, then subscribers would get |
| 534 | multiple alerts for each event, which would be bad. |
| 535 | |
| 536 | However, the subscriber list can be synced for backup purposes. Use the |
| 537 | [`fossil config pull subscriber`](/help?cmd=configuration) command to |
| 538 | pull the latest subscriber list from a server into a backup repository. |
| 539 | |
| 540 | The `push`, `export`, and `import` commands all work similarly. |
| 541 | |
| 542 | |
| 543 | <a id="pages" name="commands"></a> |
| 544 | ## Controlling the Email Alert System |
| 545 | |
| 546 | This section collects the list of Fossil UI pages and CLI commands that |
| 547 | control the email alert system, some of which have not been mentioned so |
| 548 | far: |
| 549 | |
| 550 | Commands: |
| 551 | |
| 552 | * The [`alerts`](/help?cmd=alerts) command |
| 553 | * The [`test-alert`](/help?cmd=test-alert) command |
| 554 | * The [`test-add-alerts`](/help?cmd=test-add-alerts) command |
| 555 | |
| 556 | Web pages available to users and subscribers: |
| 557 | |
| 558 | * The [`/subscribe`](/help?cmd=/subscribe) page |
| 559 | * The [`/alerts`](/help?cmd=/alerts) page |
| 560 | * The [`/unsubscribe`](/help?cmd=/unsubscribe) page |
| 561 | * The [`/contact_admin`](/help?cmd=/contact_admin) page |
| 562 | |
| 563 | Administrator-only web pages: |
| 564 | |
| 565 | * The [`/setup_notification`](/help?cmd=/setup_notification) page |
| 566 | * The [`/subscribers`](/help?cmd=/subscribers) page |
| 567 | |
| 568 | |
| 569 | <a id="design"></a> |
| 570 | ## Design of Email Alerts |
| 571 | |
| 572 | This section describes the low-level design of the email alert system in |
| 573 | Fossil. This expands on the high-level administion focused material |
| 574 | above with minimal repetition. |
| 575 | |
| 576 | This section assumes expert-level systems knowledge. If the material |
| 577 | above sufficed for your purposes, feel free to skip this section, which |
| 578 | runs to the end of this document. |
| 579 | |
| 580 | |
| 581 | <a id="datades"></a> |
| 582 | ### Data Design |
| 583 | |
| 584 | There are three new tables in the repository database, starting with |
| 585 | Fossil 2.7. These tables are not created in new repositories by |
| 586 | default. The tables only come into existence as needed when email |
| 587 | alerts are configured and used. |
| 588 | |
| 589 | |
| 590 | * <b>SUBSCRIBER</b> → |
| 591 | The subscriber table records the email address for people who |
| 592 | want to receive email notifications. Each subscriber has a |
| 593 | `subscriberCode` which is a random 32-byte blob that uniquely |
| 594 | identifies the subscriber. There are also fields to indicate |
| 595 | what kinds of notifications the subscriber wishes to receive, |
| 596 | whether or not the email address of the subscriber has been |
| 597 | verified, etc. |
| 598 | |
| 599 | * <b>PENDING\_ALERT</b> → |
| 600 | The PENDING\_ALERT table contains records that define events |
| 601 | about which alert emails might need to be sent. |
| 602 | A pending\_alert always refers to an entry in the |
| 603 | EVENT table. The EVENT table is part of the standard schema |
| 604 | and records timeline entries. In other words, there is one |
| 605 | row in the EVENT table for each possible timeline entry. The |
| 606 | PENDING\_ALERT table refers to EVENT table entries for which |
| 607 | we might need to send alert emails. |
| 608 | |
| 609 | * <b>EMAIL\_BOUNCE</b> → |
| 610 | This table is intended to record email bounce history so that |
| 611 | subscribers with excessive bounces can be turned off. That |
| 612 | logic has not yet been implemented so the EMAIL\_BOUNCE table |
| 613 | is currently unused. |
| 614 | |
| 615 | As pointed out above, ["subscribers" are distinct from "users"](#uvs). |
| 616 | The SUBSCRIBER.SUNAME field is the optional linkage between users and |
| 617 | subscribers. |
| 618 | |
| 619 | |
| 620 | <a id="stdout"></a> |
| 621 | ### The "stdout" Method |
| 622 | |
| 623 | The [list of mail sending methods](#advanced) above left out an |
| 624 | internal-only method called "stdout" which simply writes the text of the |
| 625 | email message on standard output. The "stdout" method is used for |
| 626 | testing and debugging. If you need something similar and can't modify |
| 627 | your local Fossil instance to use this method, you might temporarily |
| 628 | switch to [the "dir" method](#dir) instead. |
| 629 | |
| 630 | |
| 631 | <a id="msgfmt"></a> |
| 632 | ### Message Format |
| 633 | |
| 634 | The email messages generated by Fossil have a [well-formed |
| 635 | header][rfc822]. The downstream processing is expected to extract the |
| 636 | "To:", "From:", "Subject:" and whatever other attributes it needs from |
| 637 | the email header text. |
| 638 | |
| 639 | These emails use the `text/plain` MIME type with the UTF-8 character |
| 640 | set. We currently use a transfer encoding of `quoted-printable`, but |
| 641 | there is commented-out code in Fossil to switch to `base64` encoding, |
| 642 | which Fossil used in the early days leading up to the 2.7 release. |
| 643 | |
| 644 | If you switch Fossil back to `base64` mode, you may want to build a |
| 645 | utility program that ships in the Fossil source tree named |
| 646 | ["tools/decode-email.c"](/file/tools/decode-email.c) which can decode |
| 647 | these messages into a human-readable format. |
| 648 | |
| 649 | |
| 650 | <a id="inbound" name="bounces"></a> |
| 651 | ### Dealing with Inbound Email |
| 652 | |
| 653 | Inbound email messages — for example, bounces from failed alert emails — |
| 654 | should be relayed to the `fossil email inbound` command. That command |
| 655 | is currently a no-op place-holder. At some point, we will need to |
| 656 | design and write a bounce-message processing system for Fossil. |
| 657 | |
| 658 | |
| 659 | <a id="password" name="scode" name="verification"></a> |
| 660 | ### Passwords vs Subscriber Codes |
| 661 | |
| 662 | When anonymous passers-by on the Internet sign up for email alerts, |
| 663 | their email address must first be verified. An email message is sent to |
| 664 | the address supplied inviting the user to click on a link. The link |
| 665 | includes a pseudorandom 128-bit blob encoded as 32 hexadecimal digits, |
| 666 | which serves in place of a password for that email address. (This is |
| 667 | stored in the database as `subscriber.subscriberCode`.) If anyone visits |
| 668 | the link, the email address is verified. |
| 669 | |
| 670 | Knowledge of the `subscriberCode` is sufficient to control a |
| 671 | subscription. |
| 672 | |
| 673 | Because this code is included in plain text in email alert messages, it |
| 674 | is not as secure as a separate password, but it has several virtues: |
| 675 | |
| 676 | * It is easier for the average subscriber to deal with in that they |
| 677 | don't have to come up with yet another password and store it safely. |
| 678 | |
| 679 | * If the `subscriberCode` is stolen, the worst that can happen is that |
| 680 | the thief can change that email address's subscription settings. |
| 681 | Contrast a password which may be shared with other services, which |
| 682 | then compromises those other services. |
| 683 | |
| 684 | * No PII other than the subscriber's email address is available to an |
| 685 | attacker with the `subscriberCode`. Nor can knowledge of the |
| 686 | `subscriberCode` lead to a email flood or other annoyance attack, as |
| 687 | far as I can see. |
| 688 | |
| 689 | If the `subscriberCodes` for a Fossil repository are ever compromised, |
| 690 | new ones can be generated as follows: |
| 691 | |
| 692 | UPDATE subscriber SET subscriberCode=randomblob(32); |
| 693 | |
| 694 | Since this then affects all new email alerts going out from Fossil, your |
| 695 | end users may never even realize that they're getting new codes, as long |
| 696 | as they don't click on the URLs in the footer of old alert messages. |
| 697 | |
| 698 | With that in mind, a Fossil server administrator could choose to |
| 699 | randomize the `subscriberCodes` periodically, such as just before the |
| 700 | daily digest emails are sent out each day. |
| 701 | |
| 702 | **Important:** All of the above is distinct from the passwords for users |
| 703 | with a Fossil repository login. Such users also have subscriber codes, |
| 704 | but those codes can only be used to modify the user's email alert |
| 705 | settings. That code cannot allow a user to log into the user's Fossil |
| 706 | repository account. |
| 707 | |
| 708 | |
| 709 | <a id="processing"></a> |
| 710 | ### Internal Processing Flow |
| 711 | |
| 712 | Almost all of the email alert code is found in the |
| 713 | [`src/alerts.c`](/file/src/alerts.c) source file. |
| 714 | |
| 715 | When email alerts are enabled, a trigger is created in the schema |
| 716 | (`email_trigger1`) that adds a new entry to the `PENDING_ALERT` table |
| 717 | every time a row is added to the `EVENT` table. During a `fossil |
| 718 | rebuild`, the `EVENT` table is rebuilt from scratch; since we do not |
| 719 | want users to get alerts for every historical check-in, the trigger is |
| 720 | disabled during `rebuild`. |
| 721 | |
| 722 | Email alerts are sent out by the `alert_send_alerts()` function, which |
| 723 | is normally called automatically due to the `email-autoexec` setting, |
| 724 | which defaults to enabled. If that setting is disabled or if the user |
| 725 | simply wants to force email alerts to be sent immediately, they can give |
| 726 | a `fossil alert send` command, such as via a `cron` script. Each time |
| 727 | this function is called, the alert messages are moved further down the |
| 728 | chain, so you cannot cause duplicate alerts by calling it too often. |
| 729 | |
| 730 | Digests are handled by recording the time of the last digest in the |
| 731 | `email-last-digest` setting, and only sending a new digest if the |
| 732 | current time is one day or later after the last digest. |
| 733 | |
| 734 | Individual emails are sent to each subscriber. I (drh) ran tests and |
| 735 | found that I could send about 1200 emails/second, which is fast enough |
| 736 | that I do not need to resort to trying to notify multiple subscribers |
| 737 | with a single email. Because each subscriber gets a separate email, the |
| 738 | system can include information in the email that is unique to the |
| 739 | subscriber, such as a link to the page to edit their subscription. That |
| 740 | link includes the `subscriberCode`. |
| 741 |
+6
-4
| --- www/changes.wiki | ||
| +++ www/changes.wiki | ||
| @@ -3,11 +3,11 @@ | ||
| 3 | 3 | <a name='v2_7'></a> |
| 4 | 4 | <h2>Changes for Version 2.7 (2018-09-??)</h2> |
| 5 | 5 | |
| 6 | 6 | * Add the [./alerts.md|email alerts] feature for commits, ticket |
| 7 | 7 | changes, wiki changes, forum posts, and announcements. This is |
| 8 | - still a work in progress. It works, but it is not as easy to | |
| 8 | + still a work in progress. It works, but it is not as easy to | |
| 9 | 9 | setup and use as it ought to be. |
| 10 | 10 | * Add the [./forum.wiki|discussion forum] feature. |
| 11 | 11 | * Add new user capabilities letters needed to support alerts and forum. |
| 12 | 12 | Formerly, user capabilities were letters from [a-z], but with the |
| 13 | 13 | enhancements, the supply of lower case letters was exhausted. |
| @@ -23,11 +23,13 @@ | ||
| 23 | 23 | included in the header or footer. |
| 24 | 24 | * Add the [./backoffice.md|backoffice]. |
| 25 | 25 | * Update internal Unicode character tables, used in regular expression |
| 26 | 26 | handling, from version 10.0 to 11.0. |
| 27 | 27 | * Improvements to the "Security Audit" administration page |
| 28 | + * Added the [/help?cmd=branch|fossil branch current] command. | |
| 28 | 29 | * Update the built-in SQLite to version 3.25.0. |
| 30 | + * Add support for TLS 1.3, when compiled with OpenSSL 1.1.1. | |
| 29 | 31 | * Some code and interfaces are in place to support sending and |
| 30 | 32 | receiving email directly via SMTP, but this feature is not yet |
| 31 | 33 | complete or ready for production use. |
| 32 | 34 | |
| 33 | 35 | <a name='v2_6'></a> |
| @@ -39,12 +41,12 @@ | ||
| 39 | 41 | same as "Verbose" in the previous release. The "Verbose" mode is |
| 40 | 42 | now like "Compact" except the extra check-in details are shown by |
| 41 | 43 | default. |
| 42 | 44 | * Add support for ETags:, Last-Modified:, and If-Modified-Since: |
| 43 | 45 | cache control mechanisms. |
| 44 | - * Enhance the [/help?cmd=/tarball|/tarball], | |
| 45 | - [/help?cmd=/zip|/zip], and | |
| 46 | + * Enhance the [/help?cmd=/tarball|/tarball], | |
| 47 | + [/help?cmd=/zip|/zip], and | |
| 46 | 48 | [/help?cmd=/sqlar|/sqlar] pages so that the checkin |
| 47 | 49 | name to be downloaded can be expressed as part of the URI, |
| 48 | 50 | and without the need for query parameters. |
| 49 | 51 | * On the [/help?cmd=/timeline|/timeline] webpage, add the days=N |
| 50 | 52 | query parameter and enhance the ymd=DATE and yw=DATE query parameters |
| @@ -61,11 +63,11 @@ | ||
| 61 | 63 | |
| 62 | 64 | <a name='v2_5'></a> |
| 63 | 65 | <h2>Changes for Version 2.5 (2018-02-07)</h2> |
| 64 | 66 | |
| 65 | 67 | * Numerous enhancements to the look and feel of the web interface. |
| 66 | - Especially: Added separate "Modern", "Compact", "Verbose", and | |
| 68 | + Especially: Added separate "Modern", "Compact", "Verbose", and | |
| 67 | 69 | "Columnar" view options on timelines. |
| 68 | 70 | * Common display settings (such as the "view" option and the number |
| 69 | 71 | of rows in a timeline) are held in a cookie and thus persist |
| 70 | 72 | across multiple pages. |
| 71 | 73 | * Rework the skin editing process so that changes are implemented |
| 72 | 74 | |
| 73 | 75 | DELETED www/emaildesign.md |
| --- www/changes.wiki | |
| +++ www/changes.wiki | |
| @@ -3,11 +3,11 @@ | |
| 3 | <a name='v2_7'></a> |
| 4 | <h2>Changes for Version 2.7 (2018-09-??)</h2> |
| 5 | |
| 6 | * Add the [./alerts.md|email alerts] feature for commits, ticket |
| 7 | changes, wiki changes, forum posts, and announcements. This is |
| 8 | still a work in progress. It works, but it is not as easy to |
| 9 | setup and use as it ought to be. |
| 10 | * Add the [./forum.wiki|discussion forum] feature. |
| 11 | * Add new user capabilities letters needed to support alerts and forum. |
| 12 | Formerly, user capabilities were letters from [a-z], but with the |
| 13 | enhancements, the supply of lower case letters was exhausted. |
| @@ -23,11 +23,13 @@ | |
| 23 | included in the header or footer. |
| 24 | * Add the [./backoffice.md|backoffice]. |
| 25 | * Update internal Unicode character tables, used in regular expression |
| 26 | handling, from version 10.0 to 11.0. |
| 27 | * Improvements to the "Security Audit" administration page |
| 28 | * Update the built-in SQLite to version 3.25.0. |
| 29 | * Some code and interfaces are in place to support sending and |
| 30 | receiving email directly via SMTP, but this feature is not yet |
| 31 | complete or ready for production use. |
| 32 | |
| 33 | <a name='v2_6'></a> |
| @@ -39,12 +41,12 @@ | |
| 39 | same as "Verbose" in the previous release. The "Verbose" mode is |
| 40 | now like "Compact" except the extra check-in details are shown by |
| 41 | default. |
| 42 | * Add support for ETags:, Last-Modified:, and If-Modified-Since: |
| 43 | cache control mechanisms. |
| 44 | * Enhance the [/help?cmd=/tarball|/tarball], |
| 45 | [/help?cmd=/zip|/zip], and |
| 46 | [/help?cmd=/sqlar|/sqlar] pages so that the checkin |
| 47 | name to be downloaded can be expressed as part of the URI, |
| 48 | and without the need for query parameters. |
| 49 | * On the [/help?cmd=/timeline|/timeline] webpage, add the days=N |
| 50 | query parameter and enhance the ymd=DATE and yw=DATE query parameters |
| @@ -61,11 +63,11 @@ | |
| 61 | |
| 62 | <a name='v2_5'></a> |
| 63 | <h2>Changes for Version 2.5 (2018-02-07)</h2> |
| 64 | |
| 65 | * Numerous enhancements to the look and feel of the web interface. |
| 66 | Especially: Added separate "Modern", "Compact", "Verbose", and |
| 67 | "Columnar" view options on timelines. |
| 68 | * Common display settings (such as the "view" option and the number |
| 69 | of rows in a timeline) are held in a cookie and thus persist |
| 70 | across multiple pages. |
| 71 | * Rework the skin editing process so that changes are implemented |
| 72 | |
| 73 | ELETED www/emaildesign.md |
| --- www/changes.wiki | |
| +++ www/changes.wiki | |
| @@ -3,11 +3,11 @@ | |
| 3 | <a name='v2_7'></a> |
| 4 | <h2>Changes for Version 2.7 (2018-09-??)</h2> |
| 5 | |
| 6 | * Add the [./alerts.md|email alerts] feature for commits, ticket |
| 7 | changes, wiki changes, forum posts, and announcements. This is |
| 8 | still a work in progress. It works, but it is not as easy to |
| 9 | setup and use as it ought to be. |
| 10 | * Add the [./forum.wiki|discussion forum] feature. |
| 11 | * Add new user capabilities letters needed to support alerts and forum. |
| 12 | Formerly, user capabilities were letters from [a-z], but with the |
| 13 | enhancements, the supply of lower case letters was exhausted. |
| @@ -23,11 +23,13 @@ | |
| 23 | included in the header or footer. |
| 24 | * Add the [./backoffice.md|backoffice]. |
| 25 | * Update internal Unicode character tables, used in regular expression |
| 26 | handling, from version 10.0 to 11.0. |
| 27 | * Improvements to the "Security Audit" administration page |
| 28 | * Added the [/help?cmd=branch|fossil branch current] command. |
| 29 | * Update the built-in SQLite to version 3.25.0. |
| 30 | * Add support for TLS 1.3, when compiled with OpenSSL 1.1.1. |
| 31 | * Some code and interfaces are in place to support sending and |
| 32 | receiving email directly via SMTP, but this feature is not yet |
| 33 | complete or ready for production use. |
| 34 | |
| 35 | <a name='v2_6'></a> |
| @@ -39,12 +41,12 @@ | |
| 41 | same as "Verbose" in the previous release. The "Verbose" mode is |
| 42 | now like "Compact" except the extra check-in details are shown by |
| 43 | default. |
| 44 | * Add support for ETags:, Last-Modified:, and If-Modified-Since: |
| 45 | cache control mechanisms. |
| 46 | * Enhance the [/help?cmd=/tarball|/tarball], |
| 47 | [/help?cmd=/zip|/zip], and |
| 48 | [/help?cmd=/sqlar|/sqlar] pages so that the checkin |
| 49 | name to be downloaded can be expressed as part of the URI, |
| 50 | and without the need for query parameters. |
| 51 | * On the [/help?cmd=/timeline|/timeline] webpage, add the days=N |
| 52 | query parameter and enhance the ymd=DATE and yw=DATE query parameters |
| @@ -61,11 +63,11 @@ | |
| 63 | |
| 64 | <a name='v2_5'></a> |
| 65 | <h2>Changes for Version 2.5 (2018-02-07)</h2> |
| 66 | |
| 67 | * Numerous enhancements to the look and feel of the web interface. |
| 68 | Especially: Added separate "Modern", "Compact", "Verbose", and |
| 69 | "Columnar" view options on timelines. |
| 70 | * Common display settings (such as the "view" option and the number |
| 71 | of rows in a timeline) are held in a cookie and thus persist |
| 72 | across multiple pages. |
| 73 | * Rework the skin editing process so that changes are implemented |
| 74 | |
| 75 | ELETED www/emaildesign.md |
D
www/emaildesign.md
-215
| --- a/www/emaildesign.md | ||
| +++ b/www/emaildesign.md | ||
| @@ -1,223 +0,0 @@ | ||
| 1 | -Design of Email Notification | |
| 2 | -============================ | |
| 3 | - | |
| 4 | -This document contains high-level design notes for the email | |
| 5 | -notification system in Fossil. Use this document to get a better | |
| 6 | -understanding of how Fossil handles email notification, to help | |
| 7 | -with doing custom configurations, or to help contribute features. | |
| 8 | - | |
| 9 | -This document assumes expert-level systems knowledge. A separate | |
| 10 | -tutorial for setting up email notification by non-experts will be | |
| 11 | -generated once the email notification system stabilizes. | |
| 12 | - | |
| 13 | -Email notification is under active development as of this writing | |
| 14 | -(2018-06-25). Check back frequently for updates. | |
| 15 | - | |
| 16 | -Data Design | |
| ------------ | ||
| 17 | - | |
| 18 | -There are three new tables in the repository database. These tables | |
| 19 | -are not created in new repositories by default. The tables only | |
| 20 | -come into existance if email notification is configured and used. | |
| 21 | - | |
| 22 | - | |
| 23 | - * <b>SUBSCRIBER</b> → | |
| 24 | - The subscriber table records the email address for people who | |
| 25 | - want to receive email notifications. Each subscriber has a | |
| 26 | - `subscriberCode` which is a random 32-byte blob that uniquely | |
| 27 | - identifies the subscriber. There are also fields to indicate | |
| 28 | - what kinds of notifications the subscriber wishes to receive, | |
| 29 | - whether or not the email address of the subscriber has been | |
| 30 | - verified, etc. | |
| 31 | - | |
| 32 | - * <b>PENDING\_ALERT</b> → | |
| 33 | - The PENDING\_ALERT table contains records that define events | |
| 34 | - about which notification emails might need to be sent. | |
| 35 | - A pending\_alert always refers to an entry in the | |
| 36 | - EVENT table. The EVENT table is part of the standard schema | |
| 37 | - and records timeline entries. In other words, there is one | |
| 38 | - row in the EVENT table for each possible timeline entry. The | |
| 39 | - PENDING\_ALERT table refers to EVENT table entries for which | |
| 40 | - we might need to send notification emails. | |
| 41 | - | |
| 42 | - * <b>EMAIL\_BOUNCE</b> → | |
| 43 | - This table is intended to record email bounce history so that | |
| 44 | - subscribers with excessive bounces can be turned off. That | |
| 45 | - logic has not yet been implemented so the EMAIL\_BOUNCE table | |
| 46 | - is currently unused. | |
| 47 | - | |
| 48 | -Note that "subscribers" are distinct from "users" in the USER table. | |
| 49 | -A "user" is someone who has a login and password. A "subscriber" is | |
| 50 | -an email address that receives notification events. Users can be | |
| 51 | -subscribers, and there is a SUBSCRIBER.SUNAME field that records | |
| 52 | -the linkage between users and subscribers. But it is also possible | |
| 53 | -to be a user without being a subscriber, or to be a subscriber without | |
| 54 | -being a user. | |
| 55 | - | |
| 56 | -Sending Email Messages | |
| ----------------------- | ||
| 57 | - | |
| 58 | -Fossil expects to interact with an external [mail transfer agent][MTA]. | |
| 59 | -There are currently three different methods for sending outbound | |
| 60 | -email messages from Fossil to the external mail agent: | |
| 61 | - | |
| 62 | - 1. <b>"pipe"</b> → Invoke an external command that accepts | |
| 63 | - the email message on standard input. This is useful if the | |
| 64 | - host computer has a command like /usr/sbin/sendmail that will | |
| 65 | - accept well-formed email messages from standard input and forward | |
| 66 | - them to the appropriate destination. | |
| 67 | - | |
| 68 | - 2. <b>"db"</b> → Write outgoing email messages into an | |
| 69 | - SQLite database file. The self-hosting Fossil website uses | |
| 70 | - this technique because Fossil runs inside a reduced-privilege | |
| 71 | - chroot jail and cannot invoke commands like /usr/sbin/sendmail. | |
| 72 | - A separate TCL script running outside of the jail monitors | |
| 73 | - the email queue database and forwards email messages to the | |
| 74 | - Postfix mail transfer agent. There is an example TCL script in the | |
| 75 | - [tools/email-sender.tcl](/file/tools/email-sender.tcl) file | |
| 76 | - of the source tree that shows how this is done. | |
| 77 | - | |
| 78 | - 3. <b>"dir"</b> → Write outgoing email messages as individual | |
| 79 | - files in a designated directory. This might be useful for | |
| 80 | - testing and debugging. | |
| 81 | - | |
| 82 | -Internally, there is a fourth email sending method named "stdout" | |
| 83 | -which simply writes the text of the email message on standard output. | |
| 84 | -The "stdout" method is used for testing and debugging. | |
| 85 | - | |
| 86 | -Perhaps we will add an "smtp" sending method in the future. The | |
| 87 | -main problem with an "smtp" delivery method is that front-line Fossil | |
| 88 | -running inside the privilege jail would need to deal with all kinds | |
| 89 | -of errors from SMTP, such as unable to connect, or connection resets, | |
| 90 | -etc. SMTP expects the sender to have the ability to retry, does it | |
| 91 | -not? | |
| 92 | - | |
| 93 | -The emails transmitted have a well-formed header. The downstream | |
| 94 | -processing is expected to extract the "To:", "From:", "Subject:" and | |
| 95 | -whatever other attributes it needs from the email header text. | |
| 96 | - | |
| 97 | -All emails are text/plain and use a transfer-encoding of base64. | |
| 98 | - | |
| 99 | -There is a utility command-line program named | |
| 100 | -["tools/decode-email.c"](/file/tools/decode-email.c) in | |
| 101 | -the Fossil source tree. If you compile this program, you can use it | |
| 102 | -to convert the base64 transfer-encoding into human-readable output for | |
| 103 | -testing and debugging. | |
| 104 | - | |
| 105 | -[MTA]: https://en.wikipedia.org/wiki/Message_transfer_agent | |
| 106 | - | |
| 107 | - | |
| 108 | -Receiving Email Messages | |
| ------------------------- | ||
| 109 | - | |
| 110 | -Inbound email messages (for example bounces from failed notification | |
| 111 | -emails) should be relayed to the "fossil email inbound" command. That | |
| 112 | -command is currently a no-op place-holder. At some point, we will need | |
| 113 | -to design and write a bounce-message processing system for Fossil. | |
| 114 | - | |
| 115 | -Controlling The Setup | |
| ---------------------- | ||
| 116 | - | |
| 117 | -Commands: | |
| 118 | - | |
| 119 | - * The [email](/help?cmd=email) command | |
| 120 | - | |
| 121 | -Web pages: | |
| 122 | - | |
| 123 | - * The [/subscribe](/help?cmd=/subscribe) page | |
| 124 | - * The [/alerts](/help?cmd=/alerts) page | |
| 125 | - * The [/unsubscribe](/help?cmd=/unsubscribe) page | |
| 126 | - * The [/msgtoadmin](/help?cmd=/msgtoadmin) page | |
| 127 | - | |
| 128 | -Web pages for administrators only: | |
| 129 | - | |
| 130 | - * The [/setup_email](/help?cmd=/setup_email) page | |
| 131 | - * The [/subscribers](/help?cmd=/subscribers) page | |
| 132 | - | |
| 133 | -Test command: | |
| 134 | - | |
| 135 | - * The [test-alert](/help?cmd=test-alert) command | |
| 136 | - * The [test-add-alerts](/help?cmd=test-add-alerts) command | |
| 137 | - | |
| 138 | -Email Address Verification | |
| --------------------------- | ||
| 139 | - | |
| 140 | -When anonymous passers-by on the internet sign up for email notifications, | |
| 141 | -their email address must first be verified. An email message is sent to | |
| 142 | -the address supplied inviting the user to click on a link. The link includes | |
| 143 | -the random 32-byte `subscriberCode` in hex. If anyone visits the link, the | |
| 144 | -email address is verified. | |
| 145 | - | |
| 146 | -There is no password. Knowledge of the `subscriberCode` is sufficient to | |
| 147 | -control the subscription. This is not a secure as a separate password, | |
| 148 | -but on the other hand it is easier for the average subscriber to deal | |
| 149 | -with in that they don't have to come up with yet another password. Also, | |
| 150 | -even if the `subscriberCode` is stolen, the worst that can happens is that | |
| 151 | -the thief can change your subscription settings. No PII (other than | |
| 152 | -the subscriber's email address) is available to an attacker with the | |
| 153 | -`subscriberCode`. Nor can knowledge of the `subscriberCode` lead to a | |
| 154 | -email flood or other annoyance attack, as far as I can see. | |
| 155 | - | |
| 156 | -If subscriberCodes are ever compromised, new ones can be generated | |
| 157 | -as follows: | |
| 158 | - | |
| 159 | - UPDATE subscriber SET subscriberCode=randomblob(32); | |
| 160 | - | |
| 161 | -Perhaps the system be enhanced to randomize the | |
| 162 | -`subscriberCodes` periodically - say just before each daily digest | |
| 163 | -is sent out? | |
| 164 | - | |
| 165 | -User Control Of Their Subscription | |
| ----------------------------------- | ||
| 166 | - | |
| 167 | -If a user has a separate account with a login and password for | |
| 168 | -the repository, then their subscription is linked to their account. | |
| 169 | -On the /login page is a link to a page to control their subscription. | |
| 170 | - | |
| 171 | -For users without logins, they can request a link to a page for | |
| 172 | -controling their subscription on the `/alerts` or `/unsubscribe` page. | |
| 173 | -The link is sent via email, and includes the `subscriberCode`. | |
| 174 | - | |
| 175 | -Internal Processing Flow | |
| ------------------------- | ||
| 176 | - | |
| 177 | -Almost all of the email notification code is found in the `src/email.c` | |
| 178 | -source file. | |
| 179 | - | |
| 180 | -When email notifications are enabled, a trigger is created in the schema | |
| 181 | -(the `email_trigger1` trigger) that adds a new entry to the | |
| 182 | -`PENDING_ALERT` table every time a row is added to the `EVENT` table. | |
| 183 | -During a `fossil rebuild`, the `EVENT` table is rebuilt from scratch; since we | |
| 184 | -do not want users to get notifications for every historical check-in, | |
| 185 | -the trigger is disabled during `rebuild`. | |
| 186 | - | |
| 187 | -Email notifications are sent out by the `email_send_alerts()` function. | |
| 188 | -This function is can be called by having a cron job invoke the | |
| 189 | -`fossil email exec` command. Or, if the email-autoexec setting is | |
| 190 | -enabled, then `email_send_alerts()` is invoked automatically after each | |
| 191 | -successful webpage is generated. The latter approach is used on the | |
| 192 | -Fossil self-hosting repository. The `email_send_alerts()` function is | |
| 193 | -a no-op (obviously) if there are no pending events to be sent. | |
| 194 | - | |
| 195 | -Digests are handled by recording the time of the last digest in the | |
| 196 | -`email-last-digest` setting, and only sending a new digest if the | |
| 197 | -current time is one day or later after the last digest. | |
| 198 | - | |
| 199 | -Individual emails are sent to each subscriber. I ran tests and found | |
| 200 | -that I could send about 1200 emails/second, which is fast enough that | |
| 201 | -I do not need to resort to trying to notify multiple subscribers with | |
| 202 | -a single email. Because each subscriber gets a separate email, the | |
| 203 | -system can include information in the email that is unique to the | |
| 204 | -subscriber, such as a link to the page to edit their subscription. That | |
| 205 | -link includes the `subscriberCode`., | |
| 206 | - | |
| 207 | -Other Notes | |
| ------------ | ||
| 208 | - | |
| 209 | -The `fossil configuration pull subscriber` command pulls down the content | |
| 210 | -of the `SUBSCRIBER` table. This is intended to as a backup-only. It | |
| 211 | -is not desirable to have two or more systems sending emails to the | |
| 212 | -same people for the same repository, as that would mean users would | |
| 213 | -receive duplicate emails. Hence, the settings that control email | |
| 214 | -notifications are not transmitted with the pull. The `push`, `export`, | |
| 215 | -and `import` commands all work similarly. |
| --- a/www/emaildesign.md | |
| +++ b/www/emaildesign.md | |
| @@ -1,223 +0,0 @@ | |
| 1 | Design of Email Notification |
| 2 | ============================ |
| 3 | |
| 4 | This document contains high-level design notes for the email |
| 5 | notification system in Fossil. Use this document to get a better |
| 6 | understanding of how Fossil handles email notification, to help |
| 7 | with doing custom configurations, or to help contribute features. |
| 8 | |
| 9 | This document assumes expert-level systems knowledge. A separate |
| 10 | tutorial for setting up email notification by non-experts will be |
| 11 | generated once the email notification system stabilizes. |
| 12 | |
| 13 | Email notification is under active development as of this writing |
| 14 | (2018-06-25). Check back frequently for updates. |
| 15 | |
| 16 | Data Design |
| ------------ | |
| 17 | |
| 18 | There are three new tables in the repository database. These tables |
| 19 | are not created in new repositories by default. The tables only |
| 20 | come into existance if email notification is configured and used. |
| 21 | |
| 22 | |
| 23 | * <b>SUBSCRIBER</b> → |
| 24 | The subscriber table records the email address for people who |
| 25 | want to receive email notifications. Each subscriber has a |
| 26 | `subscriberCode` which is a random 32-byte blob that uniquely |
| 27 | identifies the subscriber. There are also fields to indicate |
| 28 | what kinds of notifications the subscriber wishes to receive, |
| 29 | whether or not the email address of the subscriber has been |
| 30 | verified, etc. |
| 31 | |
| 32 | * <b>PENDING\_ALERT</b> → |
| 33 | The PENDING\_ALERT table contains records that define events |
| 34 | about which notification emails might need to be sent. |
| 35 | A pending\_alert always refers to an entry in the |
| 36 | EVENT table. The EVENT table is part of the standard schema |
| 37 | and records timeline entries. In other words, there is one |
| 38 | row in the EVENT table for each possible timeline entry. The |
| 39 | PENDING\_ALERT table refers to EVENT table entries for which |
| 40 | we might need to send notification emails. |
| 41 | |
| 42 | * <b>EMAIL\_BOUNCE</b> → |
| 43 | This table is intended to record email bounce history so that |
| 44 | subscribers with excessive bounces can be turned off. That |
| 45 | logic has not yet been implemented so the EMAIL\_BOUNCE table |
| 46 | is currently unused. |
| 47 | |
| 48 | Note that "subscribers" are distinct from "users" in the USER table. |
| 49 | A "user" is someone who has a login and password. A "subscriber" is |
| 50 | an email address that receives notification events. Users can be |
| 51 | subscribers, and there is a SUBSCRIBER.SUNAME field that records |
| 52 | the linkage between users and subscribers. But it is also possible |
| 53 | to be a user without being a subscriber, or to be a subscriber without |
| 54 | being a user. |
| 55 | |
| 56 | Sending Email Messages |
| ----------------------- | |
| 57 | |
| 58 | Fossil expects to interact with an external [mail transfer agent][MTA]. |
| 59 | There are currently three different methods for sending outbound |
| 60 | email messages from Fossil to the external mail agent: |
| 61 | |
| 62 | 1. <b>"pipe"</b> → Invoke an external command that accepts |
| 63 | the email message on standard input. This is useful if the |
| 64 | host computer has a command like /usr/sbin/sendmail that will |
| 65 | accept well-formed email messages from standard input and forward |
| 66 | them to the appropriate destination. |
| 67 | |
| 68 | 2. <b>"db"</b> → Write outgoing email messages into an |
| 69 | SQLite database file. The self-hosting Fossil website uses |
| 70 | this technique because Fossil runs inside a reduced-privilege |
| 71 | chroot jail and cannot invoke commands like /usr/sbin/sendmail. |
| 72 | A separate TCL script running outside of the jail monitors |
| 73 | the email queue database and forwards email messages to the |
| 74 | Postfix mail transfer agent. There is an example TCL script in the |
| 75 | [tools/email-sender.tcl](/file/tools/email-sender.tcl) file |
| 76 | of the source tree that shows how this is done. |
| 77 | |
| 78 | 3. <b>"dir"</b> → Write outgoing email messages as individual |
| 79 | files in a designated directory. This might be useful for |
| 80 | testing and debugging. |
| 81 | |
| 82 | Internally, there is a fourth email sending method named "stdout" |
| 83 | which simply writes the text of the email message on standard output. |
| 84 | The "stdout" method is used for testing and debugging. |
| 85 | |
| 86 | Perhaps we will add an "smtp" sending method in the future. The |
| 87 | main problem with an "smtp" delivery method is that front-line Fossil |
| 88 | running inside the privilege jail would need to deal with all kinds |
| 89 | of errors from SMTP, such as unable to connect, or connection resets, |
| 90 | etc. SMTP expects the sender to have the ability to retry, does it |
| 91 | not? |
| 92 | |
| 93 | The emails transmitted have a well-formed header. The downstream |
| 94 | processing is expected to extract the "To:", "From:", "Subject:" and |
| 95 | whatever other attributes it needs from the email header text. |
| 96 | |
| 97 | All emails are text/plain and use a transfer-encoding of base64. |
| 98 | |
| 99 | There is a utility command-line program named |
| 100 | ["tools/decode-email.c"](/file/tools/decode-email.c) in |
| 101 | the Fossil source tree. If you compile this program, you can use it |
| 102 | to convert the base64 transfer-encoding into human-readable output for |
| 103 | testing and debugging. |
| 104 | |
| 105 | [MTA]: https://en.wikipedia.org/wiki/Message_transfer_agent |
| 106 | |
| 107 | |
| 108 | Receiving Email Messages |
| ------------------------- | |
| 109 | |
| 110 | Inbound email messages (for example bounces from failed notification |
| 111 | emails) should be relayed to the "fossil email inbound" command. That |
| 112 | command is currently a no-op place-holder. At some point, we will need |
| 113 | to design and write a bounce-message processing system for Fossil. |
| 114 | |
| 115 | Controlling The Setup |
| ---------------------- | |
| 116 | |
| 117 | Commands: |
| 118 | |
| 119 | * The [email](/help?cmd=email) command |
| 120 | |
| 121 | Web pages: |
| 122 | |
| 123 | * The [/subscribe](/help?cmd=/subscribe) page |
| 124 | * The [/alerts](/help?cmd=/alerts) page |
| 125 | * The [/unsubscribe](/help?cmd=/unsubscribe) page |
| 126 | * The [/msgtoadmin](/help?cmd=/msgtoadmin) page |
| 127 | |
| 128 | Web pages for administrators only: |
| 129 | |
| 130 | * The [/setup_email](/help?cmd=/setup_email) page |
| 131 | * The [/subscribers](/help?cmd=/subscribers) page |
| 132 | |
| 133 | Test command: |
| 134 | |
| 135 | * The [test-alert](/help?cmd=test-alert) command |
| 136 | * The [test-add-alerts](/help?cmd=test-add-alerts) command |
| 137 | |
| 138 | Email Address Verification |
| --------------------------- | |
| 139 | |
| 140 | When anonymous passers-by on the internet sign up for email notifications, |
| 141 | their email address must first be verified. An email message is sent to |
| 142 | the address supplied inviting the user to click on a link. The link includes |
| 143 | the random 32-byte `subscriberCode` in hex. If anyone visits the link, the |
| 144 | email address is verified. |
| 145 | |
| 146 | There is no password. Knowledge of the `subscriberCode` is sufficient to |
| 147 | control the subscription. This is not a secure as a separate password, |
| 148 | but on the other hand it is easier for the average subscriber to deal |
| 149 | with in that they don't have to come up with yet another password. Also, |
| 150 | even if the `subscriberCode` is stolen, the worst that can happens is that |
| 151 | the thief can change your subscription settings. No PII (other than |
| 152 | the subscriber's email address) is available to an attacker with the |
| 153 | `subscriberCode`. Nor can knowledge of the `subscriberCode` lead to a |
| 154 | email flood or other annoyance attack, as far as I can see. |
| 155 | |
| 156 | If subscriberCodes are ever compromised, new ones can be generated |
| 157 | as follows: |
| 158 | |
| 159 | UPDATE subscriber SET subscriberCode=randomblob(32); |
| 160 | |
| 161 | Perhaps the system be enhanced to randomize the |
| 162 | `subscriberCodes` periodically - say just before each daily digest |
| 163 | is sent out? |
| 164 | |
| 165 | User Control Of Their Subscription |
| ----------------------------------- | |
| 166 | |
| 167 | If a user has a separate account with a login and password for |
| 168 | the repository, then their subscription is linked to their account. |
| 169 | On the /login page is a link to a page to control their subscription. |
| 170 | |
| 171 | For users without logins, they can request a link to a page for |
| 172 | controling their subscription on the `/alerts` or `/unsubscribe` page. |
| 173 | The link is sent via email, and includes the `subscriberCode`. |
| 174 | |
| 175 | Internal Processing Flow |
| ------------------------- | |
| 176 | |
| 177 | Almost all of the email notification code is found in the `src/email.c` |
| 178 | source file. |
| 179 | |
| 180 | When email notifications are enabled, a trigger is created in the schema |
| 181 | (the `email_trigger1` trigger) that adds a new entry to the |
| 182 | `PENDING_ALERT` table every time a row is added to the `EVENT` table. |
| 183 | During a `fossil rebuild`, the `EVENT` table is rebuilt from scratch; since we |
| 184 | do not want users to get notifications for every historical check-in, |
| 185 | the trigger is disabled during `rebuild`. |
| 186 | |
| 187 | Email notifications are sent out by the `email_send_alerts()` function. |
| 188 | This function is can be called by having a cron job invoke the |
| 189 | `fossil email exec` command. Or, if the email-autoexec setting is |
| 190 | enabled, then `email_send_alerts()` is invoked automatically after each |
| 191 | successful webpage is generated. The latter approach is used on the |
| 192 | Fossil self-hosting repository. The `email_send_alerts()` function is |
| 193 | a no-op (obviously) if there are no pending events to be sent. |
| 194 | |
| 195 | Digests are handled by recording the time of the last digest in the |
| 196 | `email-last-digest` setting, and only sending a new digest if the |
| 197 | current time is one day or later after the last digest. |
| 198 | |
| 199 | Individual emails are sent to each subscriber. I ran tests and found |
| 200 | that I could send about 1200 emails/second, which is fast enough that |
| 201 | I do not need to resort to trying to notify multiple subscribers with |
| 202 | a single email. Because each subscriber gets a separate email, the |
| 203 | system can include information in the email that is unique to the |
| 204 | subscriber, such as a link to the page to edit their subscription. That |
| 205 | link includes the `subscriberCode`., |
| 206 | |
| 207 | Other Notes |
| ------------ | |
| 208 | |
| 209 | The `fossil configuration pull subscriber` command pulls down the content |
| 210 | of the `SUBSCRIBER` table. This is intended to as a backup-only. It |
| 211 | is not desirable to have two or more systems sending emails to the |
| 212 | same people for the same repository, as that would mean users would |
| 213 | receive duplicate emails. Hence, the settings that control email |
| 214 | notifications are not transmitted with the pull. The `push`, `export`, |
| 215 | and `import` commands all work similarly. |
| --- a/www/emaildesign.md | |
| +++ b/www/emaildesign.md | |
| @@ -1,223 +0,0 @@ | |
| ------------ | |
| ----------------------- | |
| ------------------------- | |
| ---------------------- | |
| --------------------------- | |
| ----------------------------------- | |
| ------------------------- | |
| ------------ | |
+59
-222
| --- www/forum.wiki | ||
| +++ www/forum.wiki | ||
| @@ -97,30 +97,16 @@ | ||
| 97 | 97 | formatting features give you a middle path, providing your users |
| 98 | 98 | enough formatting power to communicate complex ideas well without |
| 99 | 99 | providing so much power as to risk |
| 100 | 100 | [https://wonko.com/post/html-escaping | security problems]. |
| 101 | 101 | |
| 102 | - * <b>Easy Notification Emails:</b> It is easy to configure Fossil to | |
| 103 | - send email notifications of new posts to interested forum users via | |
| 104 | - your Fossil server's existing | |
| 105 | - [https://en.wikipedia.org/wiki/Message_transfer_agent | message | |
| 106 | - transfer agent] (MTA): Postfix, Exim, Sendmail... Notification | |
| 107 | - emails include the complete message content for the benefit of | |
| 108 | - those that prefer to visit the forum only when they need to post | |
| 109 | - something. Notifications are optional, and each user gets the | |
| 110 | - choice of immediate or daily digest delivery. | |
| 111 | - | |
| 112 | - * <b>Talks to Everyone:</b> Because Fossil delegates email handling | |
| 113 | - to your existing MTA, it does not need to implement the | |
| 114 | - [http://sqlite.1065341.n5.nabble.com/Many-ML-emails-going-to-GMail-s-SPAM-tp98685p98722.html | |
| 115 | - | roughly two dozen] | |
| 116 | - [https://en.wikipedia.org/wiki/Request_for_Comments | RFCs] | |
| 117 | - required in order to properly support SMTP email in this complex | |
| 118 | - world we've built. As well, this design choice means you do not | |
| 119 | - need to do duplicate configuration, such as to point Fossil at your | |
| 120 | - server's TLS certificate private key in order to support users | |
| 121 | - behind mail servers that require STARTTLS encryption. | |
| 102 | + * <b>Easy Email Alerts:</b> You can configure Fossil to | |
| 103 | + [./alerts.md | send email alerts]. Forum post emails include the | |
| 104 | + complete message content for the benefit of those that prefer to | |
| 105 | + visit the forum only when they need to post something. Alerts are | |
| 106 | + optional, and each user gets the choice of immediate or daily | |
| 107 | + digest delivery. | |
| 122 | 108 | |
| 123 | 109 | |
| 124 | 110 | <h2 id="setup">Setting up a Fossil Forum</h2> |
| 125 | 111 | |
| 126 | 112 | <h3 id="caps">Capabilities</h3> |
| @@ -150,11 +136,11 @@ | ||
| 150 | 136 | * <b>Supervise Forum</b> (<tt>6</tt>): User can grant or revoke |
| 151 | 137 | <b>WriteTrusted</b> capability for other users. (Currently |
| 152 | 138 | unimplemented.) |
| 153 | 139 | |
| 154 | 140 | * <b>Email Alerts</b> (<tt>7</tt>): User can sign themselves up for |
| 155 | - email notifications, a.k.a. alerts. | |
| 141 | + email alerts, a.k.a. notifications. | |
| 156 | 142 | |
| 157 | 143 | By default, no Fossil user has permission to use the forums except for |
| 158 | 144 | users with Setup and Admin capabilities, which get these as part of the |
| 159 | 145 | large package of other capabilities they get. |
| 160 | 146 | |
| @@ -173,14 +159,14 @@ | ||
| 173 | 159 | the WriteTrusted capability (4) to users in the <tt>developer</tt> |
| 174 | 160 | category. If you did not give the Read Forum capability (2) to |
| 175 | 161 | <tt>anonymous</tt> above, you should give <tt>developer</tt> that |
| 176 | 162 | capability here if you choose to give it capability 3 or 4. |
| 177 | 163 | |
| 178 | -If you want to use the email notification feature, by default only those | |
| 164 | +If you want to use the email alert feature, by default only those | |
| 179 | 165 | users in the Setup and Admin user categories can make use of it. Grant |
| 180 | 166 | the Email Alerts capability (7) to give others access to this feature. |
| 181 | -Alternately, you can handle notification signups outside of Fossil, with | |
| 167 | +Alternately, you can handle alert signups outside of Fossil, with | |
| 182 | 168 | a Setup or Admin users manually signing users up via Admin → |
| 183 | 169 | Notification. You'll want to grant this capability to the |
| 184 | 170 | <tt>nobody</tt> user category if you want anyone to sign up without any |
| 185 | 171 | restrictions. Give it to <tt>anonymous</tt> instead if you want the |
| 186 | 172 | user to solve a simple CAPTCHA before signing up. Or, give it to |
| @@ -219,17 +205,17 @@ | ||
| 219 | 205 | |
| 220 | 206 | The first thing is that you'll need to add something like the following |
| 221 | 207 | to the Header part of the skin to create the navbar link: |
| 222 | 208 | |
| 223 | 209 | <verbatim> |
| 224 | - if {[anycap 234567] || [anoncap 2] || [anoncap 3]} { | |
| 210 | + if {[anycap 23456] || [anoncap 2] || [anoncap 3]} { | |
| 225 | 211 | menulink /forum Forum |
| 226 | 212 | } |
| 227 | 213 | </verbatim> |
| 228 | 214 | |
| 229 | 215 | These rules say that any logged-in user with any forum-related |
| 230 | -capability (2-7 inclusive, as of this writing) or an anonymous user with | |
| 216 | +capability (2-6 inclusive, as of this writing) or an anonymous user with | |
| 231 | 217 | read or write capability on the forum (2, 3) will see the "Forum" navbar |
| 232 | 218 | link, which just takes you to <tt>/forum</tt>. |
| 233 | 219 | |
| 234 | 220 | The exact code you need here varies depending on which skin you're |
| 235 | 221 | using. Follow the style you see for the other navbar links. |
| @@ -323,207 +309,58 @@ | ||
| 323 | 309 | has been a feature of Fossil since April of 2011: Admin → |
| 324 | 310 | Login-Group. This allows one Fossil repository to recognize users |
| 325 | 311 | authorized on a different Fossil repository. |
| 326 | 312 | |
| 327 | 313 | |
| 328 | -<h3 id="alerts">Email Notifications (Alerts)</h3> | |
| 329 | - | |
| 330 | -The detailed information for this feature of Fossil is in two other | |
| 331 | -documents: | |
| 332 | - | |
| 333 | - * [./alerts.md | Email Alerts] | |
| 334 | - * [./emaildesign.md | Email Notification Design] | |
| 335 | - | |
| 336 | -You may want to study those in detail, since email is complicated. Some | |
| 337 | -of that complexity necessarily leaks out to the configuration of email | |
| 338 | -notification in Fossil. | |
| 339 | - | |
| 340 | - | |
| 341 | -<h4 id="quick">Quick Setup</h4> | |
| 342 | - | |
| 343 | -However, if you've already got a working Postfix, Exim, or Sendmail | |
| 344 | -server on the machine running your Fossil instance(s), and you aren't | |
| 345 | -using Fossil's <tt>chroot</tt> feature to wall it off from the rest of | |
| 346 | -the machine, it's fairly simple to set up email notifications: | |
| 347 | - | |
| 348 | -<ol> | |
| 349 | - <li>Go to Admin → Notification and fill out all of the | |
| 350 | - <b>Required</b> fields:</li> | |
| 351 | - | |
| 352 | - <ul> | |
| 353 | - <li><b>Canonical server URL</b> — Use the suggested URL</li> | |
| 354 | - <li><b>"From" email address</b> — <tt>[email protected]</tt> | |
| 355 | - is traditional, but do what you like</li> | |
| 356 | - <li><b>Repository nickname</b> — See the suggested examples on | |
| 357 | - the web page.</li> | |
| 358 | - </ul> | |
| 359 | - | |
| 360 | - <li>Set "Email Send Method" to "Pipe to a command"</li> | |
| 361 | - | |
| 362 | - <li>Set the "Administrator email address" to a suitable email address. | |
| 363 | - It could be the same value you used for the "From" address above, | |
| 364 | - or it could be a different value like | |
| 365 | - <tt>[email protected]</tt>.</li> | |
| 366 | -</ol> | |
| 367 | - | |
| 368 | -Save your changes. | |
| 369 | - | |
| 370 | -<a id="cd"></a>For all of the following <tt>fossil</tt> CLI commands, | |
| 371 | -we're going to assume that you've <tt>cd</tt>'d into a checkout | |
| 372 | -directory for your repository on the central server. Otherwise, we'd | |
| 373 | -need to add <tt>-R /path/to/repo.fossil</tt> to each of them. | |
| 374 | - | |
| 375 | -Give this command: | |
| 376 | - | |
| 377 | -<verbatim> | |
| 378 | - $ fossil set email-send-command | |
| 379 | -</verbatim> | |
| 380 | - | |
| 381 | -If that gives a blank value instead of <tt>sendmail -ti</tt>, say | |
| 382 | - | |
| 383 | -<verbatim> | |
| 384 | - $ fossil set email-send-command "sendmail -ti" | |
| 385 | -</verbatim> | |
| 386 | - | |
| 387 | -to force the setting. That's a | |
| 388 | -[https://fossil-scm.org/forum/forumpost/840b676410 | known bug] which | |
| 389 | -should be squished soon. | |
| 390 | - | |
| 391 | -This is the correct command even if you're running Postfix or Exim | |
| 392 | -rather than Sendmail. These mail servers (and perhaps others) provide a | |
| 393 | -<tt>sendmail</tt> command for this very sort of reason: it lets programs | |
| 394 | -send email without having to care exactly which server implementation is | |
| 395 | -running at a given site. | |
| 396 | - | |
| 397 | -<a id="status"></a>If you reload the Email Notification Setup page, the | |
| 398 | -Status section at the top should show: | |
| 399 | - | |
| 400 | -<verbatim> | |
| 401 | - Outgoing Email: Piped to command "sendmail -ti" | |
| 402 | - Pending Alerts: 0 normal, 0 digest | |
| 403 | - Subscribers: 0 active, 0 total | |
| 404 | -</verbatim> | |
| 405 | - | |
| 406 | - | |
| 407 | -<h4 id="subscribe">Subscribe to Alerts</h4> | |
| 408 | - | |
| 409 | -Above, we see that there are no subscribers, so the next step is to add | |
| 410 | -one. | |
| 411 | - | |
| 412 | -Go to the <tt>/alerts</tt> page on your Fossil instance and sign your | |
| 413 | -regular Fossil user up for email alerts. (Alternate path: click the user | |
| 414 | -name or login/logout link in the upper right corner, depending on the | |
| 415 | -skin you're using, then go to "Email Alerts".) You will need "Forum | |
| 416 | -Posts" checked at the least for the testing steps below. | |
| 417 | - | |
| 418 | -If you use the same user name and email address as you used for your | |
| 419 | -normal user login, Fossil will simply tie your alert preferences to your | |
| 420 | -login record, and the email address in your user's Contact Info field | |
| 421 | -will be considered already-verified. Otherwise, Fossil will create an | |
| 422 | -alert-only record, and you will have to verify the email address before | |
| 423 | -Fossil will send notifications to it. | |
| 424 | - | |
| 425 | -This shows a key aspect of the way Fossil's email alerts system works, | |
| 426 | -by the way: a user can be signed up for email alerts without having a | |
| 427 | -full-fledged Fossil user account. Only when both user names are the same | |
| 428 | -are the two records tied together under the hood. | |
| 429 | - | |
| 430 | - | |
| 431 | -<h4 id="alert-test">Test the Email Subsystem</h4> | |
| 432 | - | |
| 433 | -If you'd rather not create an inane "testing" post in your Fossil | |
| 434 | -instance just to force out an email alert, you can test the email | |
| 435 | -subsystem separately from the rest of the Fossil email alerts system | |
| 436 | -with the following command: | |
| 437 | - | |
| 438 | -<verbatim> | |
| 439 | - $ fossil alerts test-message [email protected] --body README.md --subject Test | |
| 440 | -</verbatim> | |
| 441 | - | |
| 442 | -That should send you an email with "Test" in the subject line and the | |
| 443 | -contents of your project's <tt>README.md</tt> file in the body. If it | |
| 444 | -works, the file's contents may be truncated. I'm uncertain whether | |
| 445 | -that's due to an intentionally-small buffer size or if it's a bug. | |
| 446 | - | |
| 447 | -That command assumes that your project [./foss-cklist.wiki | contains a | |
| 448 | -readme file]. Of course it does. Why would it not? | |
| 449 | - | |
| 450 | - | |
| 451 | -<h4 id="frist" name="first">First Post</h4> | |
| 452 | - | |
| 453 | -Since you've already edited the skin per [#skin | the instructions | |
| 454 | -above], you can click the "Forum" link in the navbar and create a new | |
| 455 | -post. I suggest taking the time to compose a suitable introductory | |
| 456 | -message especially for your project's forum, one which a new user would | |
| 457 | -find helpful. | |
| 458 | - | |
| 459 | -Wait a few seconds, and you should receive a notification email with the | |
| 460 | -post's subject and body text in the email. | |
| 461 | - | |
| 462 | - | |
| 463 | -<h4 id="trouble">Troubleshooting</h4> | |
| 464 | - | |
| 465 | -If email alerts aren't working, there are several useful commands you | |
| 466 | -can give to figure out why. | |
| 467 | - | |
| 468 | -(Be sure to [#cd | <tt>cd</tt> into a repo checkout directory] first!) | |
| 469 | - | |
| 470 | -<verbatim> | |
| 471 | - $ fossil alerts status | |
| 472 | -</verbatim> | |
| 473 | - | |
| 474 | -This should give much the same information as you saw [#status | above]. | |
| 475 | -One difference is that, since you've created a forum post, the | |
| 476 | -<tt>pending-alerts</tt> value should only be zero if you did in fact get | |
| 477 | -the requested email alert. If it's zero, check your mailer's spam | |
| 478 | -folder. If it's nonzero, continue with these troubleshooting steps. | |
| 479 | - | |
| 480 | -<verbatim> | |
| 481 | - $ fossil backoffice | |
| 482 | -</verbatim> | |
| 483 | - | |
| 484 | -That forces Fossil to run its [./backoffice.md | "back office" process]. | |
| 485 | -Its only purpose at the time of this writing is to push out alert | |
| 486 | -emails, but it might do other things later. Sometimes it can get stuck | |
| 487 | -and needs to be kicked. For that reason, you might want to set up a | |
| 488 | -crontab entry to make sure it runs occasionally. | |
| 489 | - | |
| 490 | -<verbatim> | |
| 491 | - $ fossil alerts send | |
| 492 | -</verbatim> | |
| 493 | - | |
| 494 | -This should also kick off the backoffice processing, if there are any | |
| 495 | -pending alerts to send out. | |
| 496 | - | |
| 497 | -<verbatim> | |
| 498 | - $ fossil alert pending | |
| 499 | -</verbatim> | |
| 500 | - | |
| 501 | -Show any pending alerts. The number of lines output here should equal | |
| 502 | -the [#status | status output above]. | |
| 503 | - | |
| 504 | -<verbatim> | |
| 505 | - $ fossil test-add-alerts f5900 | |
| 506 | - $ fossil alert send | |
| 507 | -</verbatim> | |
| 508 | - | |
| 509 | -Manually create an email alert and push it out immediately. | |
| 510 | - | |
| 511 | -The <tt>f</tt> in the first command's final parameter means you're | |
| 512 | -scheduling a "forum" alert. The integer is the ID of a forum post, which | |
| 513 | -you can find by visiting <tt>/timeline?showid</tt> on your Fossil | |
| 514 | -instance. | |
| 515 | - | |
| 516 | -The second command above is necessary because the | |
| 517 | -<tt>test-add-alerts</tt> command doesn't kick off a backoffice run. | |
| 518 | - | |
| 519 | -<verbatim> | |
| 520 | - $ fossil ale send | |
| 521 | -</verbatim> | |
| 522 | - | |
| 523 | -This only does the same thing as the final command above, rather than | |
| 524 | -send you an ale, as you might be hoping. Sorry. | |
| 314 | +<h3 id="alerts">Email Alerts (a.k.a. Notifications)</h3> | |
| 315 | + | |
| 316 | +Internet email service has become rather complicated since its initial | |
| 317 | +simple and insecure implementation decades ago. Fossil's role in all of | |
| 318 | +this is rather small at the moment, but the details of the integration | |
| 319 | +are complex enough to justify [./alerts.md | a separate document]. | |
| 320 | + | |
| 321 | +(The other reason that document is separate is that Fossil's email | |
| 322 | +alerts system also gets used by features of Fossil other than the | |
| 323 | +forum.) | |
| 324 | + | |
| 325 | + | |
| 326 | +<h2 id="access">Accessing the Forum</h2> | |
| 327 | + | |
| 328 | +There are many paths to a repository's Fossil forum: | |
| 329 | + | |
| 330 | +<ul> | |
| 331 | + <li> | |
| 332 | + <p>If you're using the default Fossil skin as shipped with Fossil | |
| 333 | + 2.7 or one updated to include the changes since 2.6 or prior, there | |
| 334 | + is a Forum button in the navbar which appears for users with any of | |
| 335 | + the forum-related user capabilities: 2 through 6 inclusive for those | |
| 336 | + with repository logins, or caps 2 and 3 for users without a user | |
| 337 | + account but who have solved the Anonymous user CAPTCHA.</p> | |
| 338 | + <p>This button will not appear in the default skin for such users if | |
| 339 | + their browser window is not greater than 1200 pixels wide. The | |
| 340 | + Fossil admin can adjust this limit in the skin's CSS section, down | |
| 341 | + near the bottom in the definition of the `wideonly` style.</p> | |
| 342 | + </li> | |
| 343 | + | |
| 344 | + <li>The other stock skins have this button in them as of 2.7 as well, | |
| 345 | + without the screen width restriction, since the navbar in those skins | |
| 346 | + wraps on narrow screens more gracefully than the default skin | |
| 347 | + does.</li> | |
| 348 | + | |
| 349 | + <li>Users who set up their Fossil repository under prior versions and | |
| 350 | + who now have local skin changes they don't want to overwrite by | |
| 351 | + reverting to the stock 2.7 version of the skin they chose to start | |
| 352 | + with can easily [#skin | edit their skin] to include these links.</li> | |
| 353 | + | |
| 354 | + <li>A "Forum" link appears in the drop-down panel when you click the | |
| 355 | + default skin's hamburger menu (☰) while logged in as any user | |
| 356 | + with one or more of the [#caps | user capabilities listed above].</li> | |
| 357 | + | |
| 358 | + <li>That same link also appears on the repository's <tt>/sitemap</tt> | |
| 359 | + page, since it provides the content for the hamburger menu's | |
| 360 | + panel.</li> | |
| 361 | +</ul> | |
| 525 | 362 | |
| 526 | 363 | |
| 527 | 364 | <h2 id="moderation">How Moderation Works</h2> |
| 528 | 365 | |
| 529 | 366 | In this section, we're going to call all of the following a "forum |
| 530 | 367 |
| --- www/forum.wiki | |
| +++ www/forum.wiki | |
| @@ -97,30 +97,16 @@ | |
| 97 | formatting features give you a middle path, providing your users |
| 98 | enough formatting power to communicate complex ideas well without |
| 99 | providing so much power as to risk |
| 100 | [https://wonko.com/post/html-escaping | security problems]. |
| 101 | |
| 102 | * <b>Easy Notification Emails:</b> It is easy to configure Fossil to |
| 103 | send email notifications of new posts to interested forum users via |
| 104 | your Fossil server's existing |
| 105 | [https://en.wikipedia.org/wiki/Message_transfer_agent | message |
| 106 | transfer agent] (MTA): Postfix, Exim, Sendmail... Notification |
| 107 | emails include the complete message content for the benefit of |
| 108 | those that prefer to visit the forum only when they need to post |
| 109 | something. Notifications are optional, and each user gets the |
| 110 | choice of immediate or daily digest delivery. |
| 111 | |
| 112 | * <b>Talks to Everyone:</b> Because Fossil delegates email handling |
| 113 | to your existing MTA, it does not need to implement the |
| 114 | [http://sqlite.1065341.n5.nabble.com/Many-ML-emails-going-to-GMail-s-SPAM-tp98685p98722.html |
| 115 | | roughly two dozen] |
| 116 | [https://en.wikipedia.org/wiki/Request_for_Comments | RFCs] |
| 117 | required in order to properly support SMTP email in this complex |
| 118 | world we've built. As well, this design choice means you do not |
| 119 | need to do duplicate configuration, such as to point Fossil at your |
| 120 | server's TLS certificate private key in order to support users |
| 121 | behind mail servers that require STARTTLS encryption. |
| 122 | |
| 123 | |
| 124 | <h2 id="setup">Setting up a Fossil Forum</h2> |
| 125 | |
| 126 | <h3 id="caps">Capabilities</h3> |
| @@ -150,11 +136,11 @@ | |
| 150 | * <b>Supervise Forum</b> (<tt>6</tt>): User can grant or revoke |
| 151 | <b>WriteTrusted</b> capability for other users. (Currently |
| 152 | unimplemented.) |
| 153 | |
| 154 | * <b>Email Alerts</b> (<tt>7</tt>): User can sign themselves up for |
| 155 | email notifications, a.k.a. alerts. |
| 156 | |
| 157 | By default, no Fossil user has permission to use the forums except for |
| 158 | users with Setup and Admin capabilities, which get these as part of the |
| 159 | large package of other capabilities they get. |
| 160 | |
| @@ -173,14 +159,14 @@ | |
| 173 | the WriteTrusted capability (4) to users in the <tt>developer</tt> |
| 174 | category. If you did not give the Read Forum capability (2) to |
| 175 | <tt>anonymous</tt> above, you should give <tt>developer</tt> that |
| 176 | capability here if you choose to give it capability 3 or 4. |
| 177 | |
| 178 | If you want to use the email notification feature, by default only those |
| 179 | users in the Setup and Admin user categories can make use of it. Grant |
| 180 | the Email Alerts capability (7) to give others access to this feature. |
| 181 | Alternately, you can handle notification signups outside of Fossil, with |
| 182 | a Setup or Admin users manually signing users up via Admin → |
| 183 | Notification. You'll want to grant this capability to the |
| 184 | <tt>nobody</tt> user category if you want anyone to sign up without any |
| 185 | restrictions. Give it to <tt>anonymous</tt> instead if you want the |
| 186 | user to solve a simple CAPTCHA before signing up. Or, give it to |
| @@ -219,17 +205,17 @@ | |
| 219 | |
| 220 | The first thing is that you'll need to add something like the following |
| 221 | to the Header part of the skin to create the navbar link: |
| 222 | |
| 223 | <verbatim> |
| 224 | if {[anycap 234567] || [anoncap 2] || [anoncap 3]} { |
| 225 | menulink /forum Forum |
| 226 | } |
| 227 | </verbatim> |
| 228 | |
| 229 | These rules say that any logged-in user with any forum-related |
| 230 | capability (2-7 inclusive, as of this writing) or an anonymous user with |
| 231 | read or write capability on the forum (2, 3) will see the "Forum" navbar |
| 232 | link, which just takes you to <tt>/forum</tt>. |
| 233 | |
| 234 | The exact code you need here varies depending on which skin you're |
| 235 | using. Follow the style you see for the other navbar links. |
| @@ -323,207 +309,58 @@ | |
| 323 | has been a feature of Fossil since April of 2011: Admin → |
| 324 | Login-Group. This allows one Fossil repository to recognize users |
| 325 | authorized on a different Fossil repository. |
| 326 | |
| 327 | |
| 328 | <h3 id="alerts">Email Notifications (Alerts)</h3> |
| 329 | |
| 330 | The detailed information for this feature of Fossil is in two other |
| 331 | documents: |
| 332 | |
| 333 | * [./alerts.md | Email Alerts] |
| 334 | * [./emaildesign.md | Email Notification Design] |
| 335 | |
| 336 | You may want to study those in detail, since email is complicated. Some |
| 337 | of that complexity necessarily leaks out to the configuration of email |
| 338 | notification in Fossil. |
| 339 | |
| 340 | |
| 341 | <h4 id="quick">Quick Setup</h4> |
| 342 | |
| 343 | However, if you've already got a working Postfix, Exim, or Sendmail |
| 344 | server on the machine running your Fossil instance(s), and you aren't |
| 345 | using Fossil's <tt>chroot</tt> feature to wall it off from the rest of |
| 346 | the machine, it's fairly simple to set up email notifications: |
| 347 | |
| 348 | <ol> |
| 349 | <li>Go to Admin → Notification and fill out all of the |
| 350 | <b>Required</b> fields:</li> |
| 351 | |
| 352 | <ul> |
| 353 | <li><b>Canonical server URL</b> — Use the suggested URL</li> |
| 354 | <li><b>"From" email address</b> — <tt>[email protected]</tt> |
| 355 | is traditional, but do what you like</li> |
| 356 | <li><b>Repository nickname</b> — See the suggested examples on |
| 357 | the web page.</li> |
| 358 | </ul> |
| 359 | |
| 360 | <li>Set "Email Send Method" to "Pipe to a command"</li> |
| 361 | |
| 362 | <li>Set the "Administrator email address" to a suitable email address. |
| 363 | It could be the same value you used for the "From" address above, |
| 364 | or it could be a different value like |
| 365 | <tt>[email protected]</tt>.</li> |
| 366 | </ol> |
| 367 | |
| 368 | Save your changes. |
| 369 | |
| 370 | <a id="cd"></a>For all of the following <tt>fossil</tt> CLI commands, |
| 371 | we're going to assume that you've <tt>cd</tt>'d into a checkout |
| 372 | directory for your repository on the central server. Otherwise, we'd |
| 373 | need to add <tt>-R /path/to/repo.fossil</tt> to each of them. |
| 374 | |
| 375 | Give this command: |
| 376 | |
| 377 | <verbatim> |
| 378 | $ fossil set email-send-command |
| 379 | </verbatim> |
| 380 | |
| 381 | If that gives a blank value instead of <tt>sendmail -ti</tt>, say |
| 382 | |
| 383 | <verbatim> |
| 384 | $ fossil set email-send-command "sendmail -ti" |
| 385 | </verbatim> |
| 386 | |
| 387 | to force the setting. That's a |
| 388 | [https://fossil-scm.org/forum/forumpost/840b676410 | known bug] which |
| 389 | should be squished soon. |
| 390 | |
| 391 | This is the correct command even if you're running Postfix or Exim |
| 392 | rather than Sendmail. These mail servers (and perhaps others) provide a |
| 393 | <tt>sendmail</tt> command for this very sort of reason: it lets programs |
| 394 | send email without having to care exactly which server implementation is |
| 395 | running at a given site. |
| 396 | |
| 397 | <a id="status"></a>If you reload the Email Notification Setup page, the |
| 398 | Status section at the top should show: |
| 399 | |
| 400 | <verbatim> |
| 401 | Outgoing Email: Piped to command "sendmail -ti" |
| 402 | Pending Alerts: 0 normal, 0 digest |
| 403 | Subscribers: 0 active, 0 total |
| 404 | </verbatim> |
| 405 | |
| 406 | |
| 407 | <h4 id="subscribe">Subscribe to Alerts</h4> |
| 408 | |
| 409 | Above, we see that there are no subscribers, so the next step is to add |
| 410 | one. |
| 411 | |
| 412 | Go to the <tt>/alerts</tt> page on your Fossil instance and sign your |
| 413 | regular Fossil user up for email alerts. (Alternate path: click the user |
| 414 | name or login/logout link in the upper right corner, depending on the |
| 415 | skin you're using, then go to "Email Alerts".) You will need "Forum |
| 416 | Posts" checked at the least for the testing steps below. |
| 417 | |
| 418 | If you use the same user name and email address as you used for your |
| 419 | normal user login, Fossil will simply tie your alert preferences to your |
| 420 | login record, and the email address in your user's Contact Info field |
| 421 | will be considered already-verified. Otherwise, Fossil will create an |
| 422 | alert-only record, and you will have to verify the email address before |
| 423 | Fossil will send notifications to it. |
| 424 | |
| 425 | This shows a key aspect of the way Fossil's email alerts system works, |
| 426 | by the way: a user can be signed up for email alerts without having a |
| 427 | full-fledged Fossil user account. Only when both user names are the same |
| 428 | are the two records tied together under the hood. |
| 429 | |
| 430 | |
| 431 | <h4 id="alert-test">Test the Email Subsystem</h4> |
| 432 | |
| 433 | If you'd rather not create an inane "testing" post in your Fossil |
| 434 | instance just to force out an email alert, you can test the email |
| 435 | subsystem separately from the rest of the Fossil email alerts system |
| 436 | with the following command: |
| 437 | |
| 438 | <verbatim> |
| 439 | $ fossil alerts test-message [email protected] --body README.md --subject Test |
| 440 | </verbatim> |
| 441 | |
| 442 | That should send you an email with "Test" in the subject line and the |
| 443 | contents of your project's <tt>README.md</tt> file in the body. If it |
| 444 | works, the file's contents may be truncated. I'm uncertain whether |
| 445 | that's due to an intentionally-small buffer size or if it's a bug. |
| 446 | |
| 447 | That command assumes that your project [./foss-cklist.wiki | contains a |
| 448 | readme file]. Of course it does. Why would it not? |
| 449 | |
| 450 | |
| 451 | <h4 id="frist" name="first">First Post</h4> |
| 452 | |
| 453 | Since you've already edited the skin per [#skin | the instructions |
| 454 | above], you can click the "Forum" link in the navbar and create a new |
| 455 | post. I suggest taking the time to compose a suitable introductory |
| 456 | message especially for your project's forum, one which a new user would |
| 457 | find helpful. |
| 458 | |
| 459 | Wait a few seconds, and you should receive a notification email with the |
| 460 | post's subject and body text in the email. |
| 461 | |
| 462 | |
| 463 | <h4 id="trouble">Troubleshooting</h4> |
| 464 | |
| 465 | If email alerts aren't working, there are several useful commands you |
| 466 | can give to figure out why. |
| 467 | |
| 468 | (Be sure to [#cd | <tt>cd</tt> into a repo checkout directory] first!) |
| 469 | |
| 470 | <verbatim> |
| 471 | $ fossil alerts status |
| 472 | </verbatim> |
| 473 | |
| 474 | This should give much the same information as you saw [#status | above]. |
| 475 | One difference is that, since you've created a forum post, the |
| 476 | <tt>pending-alerts</tt> value should only be zero if you did in fact get |
| 477 | the requested email alert. If it's zero, check your mailer's spam |
| 478 | folder. If it's nonzero, continue with these troubleshooting steps. |
| 479 | |
| 480 | <verbatim> |
| 481 | $ fossil backoffice |
| 482 | </verbatim> |
| 483 | |
| 484 | That forces Fossil to run its [./backoffice.md | "back office" process]. |
| 485 | Its only purpose at the time of this writing is to push out alert |
| 486 | emails, but it might do other things later. Sometimes it can get stuck |
| 487 | and needs to be kicked. For that reason, you might want to set up a |
| 488 | crontab entry to make sure it runs occasionally. |
| 489 | |
| 490 | <verbatim> |
| 491 | $ fossil alerts send |
| 492 | </verbatim> |
| 493 | |
| 494 | This should also kick off the backoffice processing, if there are any |
| 495 | pending alerts to send out. |
| 496 | |
| 497 | <verbatim> |
| 498 | $ fossil alert pending |
| 499 | </verbatim> |
| 500 | |
| 501 | Show any pending alerts. The number of lines output here should equal |
| 502 | the [#status | status output above]. |
| 503 | |
| 504 | <verbatim> |
| 505 | $ fossil test-add-alerts f5900 |
| 506 | $ fossil alert send |
| 507 | </verbatim> |
| 508 | |
| 509 | Manually create an email alert and push it out immediately. |
| 510 | |
| 511 | The <tt>f</tt> in the first command's final parameter means you're |
| 512 | scheduling a "forum" alert. The integer is the ID of a forum post, which |
| 513 | you can find by visiting <tt>/timeline?showid</tt> on your Fossil |
| 514 | instance. |
| 515 | |
| 516 | The second command above is necessary because the |
| 517 | <tt>test-add-alerts</tt> command doesn't kick off a backoffice run. |
| 518 | |
| 519 | <verbatim> |
| 520 | $ fossil ale send |
| 521 | </verbatim> |
| 522 | |
| 523 | This only does the same thing as the final command above, rather than |
| 524 | send you an ale, as you might be hoping. Sorry. |
| 525 | |
| 526 | |
| 527 | <h2 id="moderation">How Moderation Works</h2> |
| 528 | |
| 529 | In this section, we're going to call all of the following a "forum |
| 530 |
| --- www/forum.wiki | |
| +++ www/forum.wiki | |
| @@ -97,30 +97,16 @@ | |
| 97 | formatting features give you a middle path, providing your users |
| 98 | enough formatting power to communicate complex ideas well without |
| 99 | providing so much power as to risk |
| 100 | [https://wonko.com/post/html-escaping | security problems]. |
| 101 | |
| 102 | * <b>Easy Email Alerts:</b> You can configure Fossil to |
| 103 | [./alerts.md | send email alerts]. Forum post emails include the |
| 104 | complete message content for the benefit of those that prefer to |
| 105 | visit the forum only when they need to post something. Alerts are |
| 106 | optional, and each user gets the choice of immediate or daily |
| 107 | digest delivery. |
| 108 | |
| 109 | |
| 110 | <h2 id="setup">Setting up a Fossil Forum</h2> |
| 111 | |
| 112 | <h3 id="caps">Capabilities</h3> |
| @@ -150,11 +136,11 @@ | |
| 136 | * <b>Supervise Forum</b> (<tt>6</tt>): User can grant or revoke |
| 137 | <b>WriteTrusted</b> capability for other users. (Currently |
| 138 | unimplemented.) |
| 139 | |
| 140 | * <b>Email Alerts</b> (<tt>7</tt>): User can sign themselves up for |
| 141 | email alerts, a.k.a. notifications. |
| 142 | |
| 143 | By default, no Fossil user has permission to use the forums except for |
| 144 | users with Setup and Admin capabilities, which get these as part of the |
| 145 | large package of other capabilities they get. |
| 146 | |
| @@ -173,14 +159,14 @@ | |
| 159 | the WriteTrusted capability (4) to users in the <tt>developer</tt> |
| 160 | category. If you did not give the Read Forum capability (2) to |
| 161 | <tt>anonymous</tt> above, you should give <tt>developer</tt> that |
| 162 | capability here if you choose to give it capability 3 or 4. |
| 163 | |
| 164 | If you want to use the email alert feature, by default only those |
| 165 | users in the Setup and Admin user categories can make use of it. Grant |
| 166 | the Email Alerts capability (7) to give others access to this feature. |
| 167 | Alternately, you can handle alert signups outside of Fossil, with |
| 168 | a Setup or Admin users manually signing users up via Admin → |
| 169 | Notification. You'll want to grant this capability to the |
| 170 | <tt>nobody</tt> user category if you want anyone to sign up without any |
| 171 | restrictions. Give it to <tt>anonymous</tt> instead if you want the |
| 172 | user to solve a simple CAPTCHA before signing up. Or, give it to |
| @@ -219,17 +205,17 @@ | |
| 205 | |
| 206 | The first thing is that you'll need to add something like the following |
| 207 | to the Header part of the skin to create the navbar link: |
| 208 | |
| 209 | <verbatim> |
| 210 | if {[anycap 23456] || [anoncap 2] || [anoncap 3]} { |
| 211 | menulink /forum Forum |
| 212 | } |
| 213 | </verbatim> |
| 214 | |
| 215 | These rules say that any logged-in user with any forum-related |
| 216 | capability (2-6 inclusive, as of this writing) or an anonymous user with |
| 217 | read or write capability on the forum (2, 3) will see the "Forum" navbar |
| 218 | link, which just takes you to <tt>/forum</tt>. |
| 219 | |
| 220 | The exact code you need here varies depending on which skin you're |
| 221 | using. Follow the style you see for the other navbar links. |
| @@ -323,207 +309,58 @@ | |
| 309 | has been a feature of Fossil since April of 2011: Admin → |
| 310 | Login-Group. This allows one Fossil repository to recognize users |
| 311 | authorized on a different Fossil repository. |
| 312 | |
| 313 | |
| 314 | <h3 id="alerts">Email Alerts (a.k.a. Notifications)</h3> |
| 315 | |
| 316 | Internet email service has become rather complicated since its initial |
| 317 | simple and insecure implementation decades ago. Fossil's role in all of |
| 318 | this is rather small at the moment, but the details of the integration |
| 319 | are complex enough to justify [./alerts.md | a separate document]. |
| 320 | |
| 321 | (The other reason that document is separate is that Fossil's email |
| 322 | alerts system also gets used by features of Fossil other than the |
| 323 | forum.) |
| 324 | |
| 325 | |
| 326 | <h2 id="access">Accessing the Forum</h2> |
| 327 | |
| 328 | There are many paths to a repository's Fossil forum: |
| 329 | |
| 330 | <ul> |
| 331 | <li> |
| 332 | <p>If you're using the default Fossil skin as shipped with Fossil |
| 333 | 2.7 or one updated to include the changes since 2.6 or prior, there |
| 334 | is a Forum button in the navbar which appears for users with any of |
| 335 | the forum-related user capabilities: 2 through 6 inclusive for those |
| 336 | with repository logins, or caps 2 and 3 for users without a user |
| 337 | account but who have solved the Anonymous user CAPTCHA.</p> |
| 338 | <p>This button will not appear in the default skin for such users if |
| 339 | their browser window is not greater than 1200 pixels wide. The |
| 340 | Fossil admin can adjust this limit in the skin's CSS section, down |
| 341 | near the bottom in the definition of the `wideonly` style.</p> |
| 342 | </li> |
| 343 | |
| 344 | <li>The other stock skins have this button in them as of 2.7 as well, |
| 345 | without the screen width restriction, since the navbar in those skins |
| 346 | wraps on narrow screens more gracefully than the default skin |
| 347 | does.</li> |
| 348 | |
| 349 | <li>Users who set up their Fossil repository under prior versions and |
| 350 | who now have local skin changes they don't want to overwrite by |
| 351 | reverting to the stock 2.7 version of the skin they chose to start |
| 352 | with can easily [#skin | edit their skin] to include these links.</li> |
| 353 | |
| 354 | <li>A "Forum" link appears in the drop-down panel when you click the |
| 355 | default skin's hamburger menu (☰) while logged in as any user |
| 356 | with one or more of the [#caps | user capabilities listed above].</li> |
| 357 | |
| 358 | <li>That same link also appears on the repository's <tt>/sitemap</tt> |
| 359 | page, since it provides the content for the hamburger menu's |
| 360 | panel.</li> |
| 361 | </ul> |
| 362 | |
| 363 | |
| 364 | <h2 id="moderation">How Moderation Works</h2> |
| 365 | |
| 366 | In this section, we're going to call all of the following a "forum |
| 367 |
+1
-1
| --- www/makefile.wiki | ||
| +++ www/makefile.wiki | ||
| @@ -70,11 +70,11 @@ | ||
| 70 | 70 | The builtin_data.h header file contains the definitions of C-language |
| 71 | 71 | byte-array constants that contain various resources such as scripts and |
| 72 | 72 | images. The builtin_data.h header file is generate from the original |
| 73 | 73 | resource files using a small program called: |
| 74 | 74 | |
| 75 | - 12 [/file/src/mkbuiltin.c | mkbuildin.c] | |
| 75 | + 12 [/file/src/mkbuiltin.c | mkbuiltin.c] | |
| 76 | 76 | |
| 77 | 77 | Examples of built-in resources include the [/file/src/diff.tcl | diff.tcl] |
| 78 | 78 | script used to implement the --tk option to [/help?cmd=diff| fossil diff], |
| 79 | 79 | the [/file/src/markdown.md | markdown documentation], and the various |
| 80 | 80 | CSS scripts, headers, and footers used to implement built-in skins. New |
| 81 | 81 |
| --- www/makefile.wiki | |
| +++ www/makefile.wiki | |
| @@ -70,11 +70,11 @@ | |
| 70 | The builtin_data.h header file contains the definitions of C-language |
| 71 | byte-array constants that contain various resources such as scripts and |
| 72 | images. The builtin_data.h header file is generate from the original |
| 73 | resource files using a small program called: |
| 74 | |
| 75 | 12 [/file/src/mkbuiltin.c | mkbuildin.c] |
| 76 | |
| 77 | Examples of built-in resources include the [/file/src/diff.tcl | diff.tcl] |
| 78 | script used to implement the --tk option to [/help?cmd=diff| fossil diff], |
| 79 | the [/file/src/markdown.md | markdown documentation], and the various |
| 80 | CSS scripts, headers, and footers used to implement built-in skins. New |
| 81 |
| --- www/makefile.wiki | |
| +++ www/makefile.wiki | |
| @@ -70,11 +70,11 @@ | |
| 70 | The builtin_data.h header file contains the definitions of C-language |
| 71 | byte-array constants that contain various resources such as scripts and |
| 72 | images. The builtin_data.h header file is generate from the original |
| 73 | resource files using a small program called: |
| 74 | |
| 75 | 12 [/file/src/mkbuiltin.c | mkbuiltin.c] |
| 76 | |
| 77 | Examples of built-in resources include the [/file/src/diff.tcl | diff.tcl] |
| 78 | script used to implement the --tk option to [/help?cmd=diff| fossil diff], |
| 79 | the [/file/src/markdown.md | markdown documentation], and the various |
| 80 | CSS scripts, headers, and footers used to implement built-in skins. New |
| 81 |
+1
-1
| --- www/makefile.wiki | ||
| +++ www/makefile.wiki | ||
| @@ -70,11 +70,11 @@ | ||
| 70 | 70 | The builtin_data.h header file contains the definitions of C-language |
| 71 | 71 | byte-array constants that contain various resources such as scripts and |
| 72 | 72 | images. The builtin_data.h header file is generate from the original |
| 73 | 73 | resource files using a small program called: |
| 74 | 74 | |
| 75 | - 12 [/file/src/mkbuiltin.c | mkbuildin.c] | |
| 75 | + 12 [/file/src/mkbuiltin.c | mkbuiltin.c] | |
| 76 | 76 | |
| 77 | 77 | Examples of built-in resources include the [/file/src/diff.tcl | diff.tcl] |
| 78 | 78 | script used to implement the --tk option to [/help?cmd=diff| fossil diff], |
| 79 | 79 | the [/file/src/markdown.md | markdown documentation], and the various |
| 80 | 80 | CSS scripts, headers, and footers used to implement built-in skins. New |
| 81 | 81 |
| --- www/makefile.wiki | |
| +++ www/makefile.wiki | |
| @@ -70,11 +70,11 @@ | |
| 70 | The builtin_data.h header file contains the definitions of C-language |
| 71 | byte-array constants that contain various resources such as scripts and |
| 72 | images. The builtin_data.h header file is generate from the original |
| 73 | resource files using a small program called: |
| 74 | |
| 75 | 12 [/file/src/mkbuiltin.c | mkbuildin.c] |
| 76 | |
| 77 | Examples of built-in resources include the [/file/src/diff.tcl | diff.tcl] |
| 78 | script used to implement the --tk option to [/help?cmd=diff| fossil diff], |
| 79 | the [/file/src/markdown.md | markdown documentation], and the various |
| 80 | CSS scripts, headers, and footers used to implement built-in skins. New |
| 81 |
| --- www/makefile.wiki | |
| +++ www/makefile.wiki | |
| @@ -70,11 +70,11 @@ | |
| 70 | The builtin_data.h header file contains the definitions of C-language |
| 71 | byte-array constants that contain various resources such as scripts and |
| 72 | images. The builtin_data.h header file is generate from the original |
| 73 | resource files using a small program called: |
| 74 | |
| 75 | 12 [/file/src/mkbuiltin.c | mkbuiltin.c] |
| 76 | |
| 77 | Examples of built-in resources include the [/file/src/diff.tcl | diff.tcl] |
| 78 | script used to implement the --tk option to [/help?cmd=diff| fossil diff], |
| 79 | the [/file/src/markdown.md | markdown documentation], and the various |
| 80 | CSS scripts, headers, and footers used to implement built-in skins. New |
| 81 |
+2
-1
| --- www/mkindex.tcl | ||
| +++ www/mkindex.tcl | ||
| @@ -9,11 +9,11 @@ | ||
| 9 | 9 | set doclist { |
| 10 | 10 | aboutcgi.wiki {How CGI Works In Fossil} |
| 11 | 11 | aboutdownload.wiki {How The Download Page Works} |
| 12 | 12 | adding_code.wiki {Adding New Features To Fossil} |
| 13 | 13 | adding_code.wiki {Hacking Fossil} |
| 14 | - alerts.md {Email Alerts And Notification} | |
| 14 | + alerts.md {Email Alerts And Notifications} | |
| 15 | 15 | antibot.wiki {Defense against Spiders and Bots} |
| 16 | 16 | backoffice.md {The "Backoffice" mechanism of Fossil} |
| 17 | 17 | blame.wiki {The Annotate/Blame Algorithm Of Fossil} |
| 18 | 18 | branching.wiki {Branching, Forking, Merging, and Tagging} |
| 19 | 19 | bugtheory.wiki {Bug Tracking In Fossil} |
| @@ -35,10 +35,11 @@ | ||
| 35 | 35 | env-opts.md {Environment Variables and Global Options} |
| 36 | 36 | event.wiki {Events} |
| 37 | 37 | faq.wiki {Frequently Asked Questions} |
| 38 | 38 | fileformat.wiki {Fossil File Format} |
| 39 | 39 | fiveminutes.wiki {Up and Running in 5 Minutes as a Single User} |
| 40 | + forum.wiki {Fossil Forums} | |
| 40 | 41 | foss-cklist.wiki {Checklist For Successful Open-Source Projects} |
| 41 | 42 | fossil-from-msvc.wiki {Integrating Fossil in the Microsoft Express 2010 IDE} |
| 42 | 43 | fossil-v-git.wiki {Fossil Versus Git} |
| 43 | 44 | globs.md {File Name Glob Patterns} |
| 44 | 45 | hacker-howto.wiki {Hacker How-To} |
| 45 | 46 |
| --- www/mkindex.tcl | |
| +++ www/mkindex.tcl | |
| @@ -9,11 +9,11 @@ | |
| 9 | set doclist { |
| 10 | aboutcgi.wiki {How CGI Works In Fossil} |
| 11 | aboutdownload.wiki {How The Download Page Works} |
| 12 | adding_code.wiki {Adding New Features To Fossil} |
| 13 | adding_code.wiki {Hacking Fossil} |
| 14 | alerts.md {Email Alerts And Notification} |
| 15 | antibot.wiki {Defense against Spiders and Bots} |
| 16 | backoffice.md {The "Backoffice" mechanism of Fossil} |
| 17 | blame.wiki {The Annotate/Blame Algorithm Of Fossil} |
| 18 | branching.wiki {Branching, Forking, Merging, and Tagging} |
| 19 | bugtheory.wiki {Bug Tracking In Fossil} |
| @@ -35,10 +35,11 @@ | |
| 35 | env-opts.md {Environment Variables and Global Options} |
| 36 | event.wiki {Events} |
| 37 | faq.wiki {Frequently Asked Questions} |
| 38 | fileformat.wiki {Fossil File Format} |
| 39 | fiveminutes.wiki {Up and Running in 5 Minutes as a Single User} |
| 40 | foss-cklist.wiki {Checklist For Successful Open-Source Projects} |
| 41 | fossil-from-msvc.wiki {Integrating Fossil in the Microsoft Express 2010 IDE} |
| 42 | fossil-v-git.wiki {Fossil Versus Git} |
| 43 | globs.md {File Name Glob Patterns} |
| 44 | hacker-howto.wiki {Hacker How-To} |
| 45 |
| --- www/mkindex.tcl | |
| +++ www/mkindex.tcl | |
| @@ -9,11 +9,11 @@ | |
| 9 | set doclist { |
| 10 | aboutcgi.wiki {How CGI Works In Fossil} |
| 11 | aboutdownload.wiki {How The Download Page Works} |
| 12 | adding_code.wiki {Adding New Features To Fossil} |
| 13 | adding_code.wiki {Hacking Fossil} |
| 14 | alerts.md {Email Alerts And Notifications} |
| 15 | antibot.wiki {Defense against Spiders and Bots} |
| 16 | backoffice.md {The "Backoffice" mechanism of Fossil} |
| 17 | blame.wiki {The Annotate/Blame Algorithm Of Fossil} |
| 18 | branching.wiki {Branching, Forking, Merging, and Tagging} |
| 19 | bugtheory.wiki {Bug Tracking In Fossil} |
| @@ -35,10 +35,11 @@ | |
| 35 | env-opts.md {Environment Variables and Global Options} |
| 36 | event.wiki {Events} |
| 37 | faq.wiki {Frequently Asked Questions} |
| 38 | fileformat.wiki {Fossil File Format} |
| 39 | fiveminutes.wiki {Up and Running in 5 Minutes as a Single User} |
| 40 | forum.wiki {Fossil Forums} |
| 41 | foss-cklist.wiki {Checklist For Successful Open-Source Projects} |
| 42 | fossil-from-msvc.wiki {Integrating Fossil in the Microsoft Express 2010 IDE} |
| 43 | fossil-v-git.wiki {Fossil Versus Git} |
| 44 | globs.md {File Name Glob Patterns} |
| 45 | hacker-howto.wiki {Hacker How-To} |
| 46 |
+5
-3
| --- www/permutedindex.html | ||
| +++ www/permutedindex.html | ||
| @@ -23,11 +23,11 @@ | ||
| 23 | 23 | <li><a href="fiveminutes.wiki">5 Minutes as a Single User — Up and Running in</a></li> |
| 24 | 24 | <li><a href="fossil-from-msvc.wiki">2010 IDE — Integrating Fossil in the Microsoft Express</a></li> |
| 25 | 25 | <li><a href="tech_overview.wiki"><b>A Technical Overview Of The Design And Implementation Of Fossil</b></a></li> |
| 26 | 26 | <li><a href="adding_code.wiki"><b>Adding New Features To Fossil</b></a></li> |
| 27 | 27 | <li><a href="copyright-release.html">Agreement — Contributor License</a></li> |
| 28 | -<li><a href="alerts.md">Alerts And Notification — Email</a></li> | |
| 28 | +<li><a href="alerts.md">Alerts And Notifications — Email</a></li> | |
| 29 | 29 | <li><a href="delta_encoder_algorithm.wiki">Algorithm — Fossil Delta Encoding</a></li> |
| 30 | 30 | <li><a href="blame.wiki">Algorithm Of Fossil — The Annotate/Blame</a></li> |
| 31 | 31 | <li><a href="blame.wiki">Annotate/Blame Algorithm Of Fossil — The</a></li> |
| 32 | 32 | <li><a href="customskin.md">Appearance of Web Pages — Theming: Customizing The</a></li> |
| 33 | 33 | <li><a href="faq.wiki">Asked Questions — Frequently</a></li> |
| @@ -78,11 +78,11 @@ | ||
| 78 | 78 | <li><a href="embeddeddoc.wiki">Documentation — Embedded Project</a></li> |
| 79 | 79 | <li><a href="contribute.wiki">Documentation To The Fossil Project — Contributing Code or</a></li> |
| 80 | 80 | <li><a href="aboutdownload.wiki">Download Page Works — How The</a></li> |
| 81 | 81 | <li><a href="theory1.wiki">DVCS — Thoughts On The Design Of The Fossil</a></li> |
| 82 | 82 | <li><a href="quotes.wiki">DVCSes in General — Quotes: What People Are Saying About Fossil, Git, and</a></li> |
| 83 | -<li><a href="alerts.md"><b>Email Alerts And Notification</b></a></li> | |
| 83 | +<li><a href="alerts.md"><b>Email Alerts And Notifications</b></a></li> | |
| 84 | 84 | <li><a href="embeddeddoc.wiki"><b>Embedded Project Documentation</b></a></li> |
| 85 | 85 | <li><a href="delta_encoder_algorithm.wiki">Encoding Algorithm — Fossil Delta</a></li> |
| 86 | 86 | <li><a href="encryptedrepos.wiki">Encrypted Repositories — How To Use</a></li> |
| 87 | 87 | <li><a href="env-opts.md"><b>Environment Variables and Global Options</b></a></li> |
| 88 | 88 | <li><a href="event.wiki"><b>Events</b></a></li> |
| @@ -96,15 +96,17 @@ | ||
| 96 | 96 | <li><a href="branching.wiki">Forking, Merging, and Tagging — Branching,</a></li> |
| 97 | 97 | <li><a href="delta_format.wiki">Format — Fossil Delta</a></li> |
| 98 | 98 | <li><a href="fileformat.wiki">Format — Fossil File</a></li> |
| 99 | 99 | <li><a href="../../../md_rules">Formatting Rules — Markdown</a></li> |
| 100 | 100 | <li><a href="../../../wiki_rules">Formatting Rules — Wiki</a></li> |
| 101 | +<li><a href="forum.wiki">Forums — Fossil</a></li> | |
| 101 | 102 | <li><a href="changes.wiki"><b>Fossil Changelog</b></a></li> |
| 102 | 103 | <li><a href="concepts.wiki"><b>Fossil Core Concepts</b></a></li> |
| 103 | 104 | <li><a href="delta_encoder_algorithm.wiki"><b>Fossil Delta Encoding Algorithm</b></a></li> |
| 104 | 105 | <li><a href="delta_format.wiki"><b>Fossil Delta Format</b></a></li> |
| 105 | 106 | <li><a href="fileformat.wiki"><b>Fossil File Format</b></a></li> |
| 107 | +<li><a href="forum.wiki"><b>Fossil Forums</b></a></li> | |
| 106 | 108 | <li><a href="quickstart.wiki"><b>Fossil Quick Start Guide</b></a></li> |
| 107 | 109 | <li><a href="selfcheck.wiki"><b>Fossil Repository Integrity Self Checks</b></a></li> |
| 108 | 110 | <li><a href="selfhost.wiki"><b>Fossil Self Hosting Repositories</b></a></li> |
| 109 | 111 | <li><a href="settings.wiki"><b>Fossil Settings</b></a></li> |
| 110 | 112 | <li><a href="hints.wiki"><b>Fossil Tips And Usage Hints</b></a></li> |
| @@ -151,11 +153,11 @@ | ||
| 151 | 153 | <li><a href="fiveminutes.wiki">Minutes as a Single User — Up and Running in 5</a></li> |
| 152 | 154 | <li><a href="globs.md">Name Glob Patterns — File</a></li> |
| 153 | 155 | <li><a href="checkin_names.wiki">Names — Check-in And Version</a></li> |
| 154 | 156 | <li><a href="adding_code.wiki">New Features To Fossil — Adding</a></li> |
| 155 | 157 | <li><a href="newrepo.wiki">New Fossil Repository — How To Create A</a></li> |
| 156 | -<li><a href="alerts.md">Notification — Email Alerts And</a></li> | |
| 158 | +<li><a href="alerts.md">Notifications — Email Alerts And</a></li> | |
| 157 | 159 | <li><a href="foss-cklist.wiki">Open-Source Projects — Checklist For Successful</a></li> |
| 158 | 160 | <li><a href="pop.wiki">Operation — Principles Of</a></li> |
| 159 | 161 | <li><a href="env-opts.md">Options — Environment Variables and Global</a></li> |
| 160 | 162 | <li><a href="tech_overview.wiki">Overview Of The Design And Implementation Of Fossil — A Technical</a></li> |
| 161 | 163 | <li><a href="index.wiki">Page — Home</a></li> |
| 162 | 164 |
| --- www/permutedindex.html | |
| +++ www/permutedindex.html | |
| @@ -23,11 +23,11 @@ | |
| 23 | <li><a href="fiveminutes.wiki">5 Minutes as a Single User — Up and Running in</a></li> |
| 24 | <li><a href="fossil-from-msvc.wiki">2010 IDE — Integrating Fossil in the Microsoft Express</a></li> |
| 25 | <li><a href="tech_overview.wiki"><b>A Technical Overview Of The Design And Implementation Of Fossil</b></a></li> |
| 26 | <li><a href="adding_code.wiki"><b>Adding New Features To Fossil</b></a></li> |
| 27 | <li><a href="copyright-release.html">Agreement — Contributor License</a></li> |
| 28 | <li><a href="alerts.md">Alerts And Notification — Email</a></li> |
| 29 | <li><a href="delta_encoder_algorithm.wiki">Algorithm — Fossil Delta Encoding</a></li> |
| 30 | <li><a href="blame.wiki">Algorithm Of Fossil — The Annotate/Blame</a></li> |
| 31 | <li><a href="blame.wiki">Annotate/Blame Algorithm Of Fossil — The</a></li> |
| 32 | <li><a href="customskin.md">Appearance of Web Pages — Theming: Customizing The</a></li> |
| 33 | <li><a href="faq.wiki">Asked Questions — Frequently</a></li> |
| @@ -78,11 +78,11 @@ | |
| 78 | <li><a href="embeddeddoc.wiki">Documentation — Embedded Project</a></li> |
| 79 | <li><a href="contribute.wiki">Documentation To The Fossil Project — Contributing Code or</a></li> |
| 80 | <li><a href="aboutdownload.wiki">Download Page Works — How The</a></li> |
| 81 | <li><a href="theory1.wiki">DVCS — Thoughts On The Design Of The Fossil</a></li> |
| 82 | <li><a href="quotes.wiki">DVCSes in General — Quotes: What People Are Saying About Fossil, Git, and</a></li> |
| 83 | <li><a href="alerts.md"><b>Email Alerts And Notification</b></a></li> |
| 84 | <li><a href="embeddeddoc.wiki"><b>Embedded Project Documentation</b></a></li> |
| 85 | <li><a href="delta_encoder_algorithm.wiki">Encoding Algorithm — Fossil Delta</a></li> |
| 86 | <li><a href="encryptedrepos.wiki">Encrypted Repositories — How To Use</a></li> |
| 87 | <li><a href="env-opts.md"><b>Environment Variables and Global Options</b></a></li> |
| 88 | <li><a href="event.wiki"><b>Events</b></a></li> |
| @@ -96,15 +96,17 @@ | |
| 96 | <li><a href="branching.wiki">Forking, Merging, and Tagging — Branching,</a></li> |
| 97 | <li><a href="delta_format.wiki">Format — Fossil Delta</a></li> |
| 98 | <li><a href="fileformat.wiki">Format — Fossil File</a></li> |
| 99 | <li><a href="../../../md_rules">Formatting Rules — Markdown</a></li> |
| 100 | <li><a href="../../../wiki_rules">Formatting Rules — Wiki</a></li> |
| 101 | <li><a href="changes.wiki"><b>Fossil Changelog</b></a></li> |
| 102 | <li><a href="concepts.wiki"><b>Fossil Core Concepts</b></a></li> |
| 103 | <li><a href="delta_encoder_algorithm.wiki"><b>Fossil Delta Encoding Algorithm</b></a></li> |
| 104 | <li><a href="delta_format.wiki"><b>Fossil Delta Format</b></a></li> |
| 105 | <li><a href="fileformat.wiki"><b>Fossil File Format</b></a></li> |
| 106 | <li><a href="quickstart.wiki"><b>Fossil Quick Start Guide</b></a></li> |
| 107 | <li><a href="selfcheck.wiki"><b>Fossil Repository Integrity Self Checks</b></a></li> |
| 108 | <li><a href="selfhost.wiki"><b>Fossil Self Hosting Repositories</b></a></li> |
| 109 | <li><a href="settings.wiki"><b>Fossil Settings</b></a></li> |
| 110 | <li><a href="hints.wiki"><b>Fossil Tips And Usage Hints</b></a></li> |
| @@ -151,11 +153,11 @@ | |
| 151 | <li><a href="fiveminutes.wiki">Minutes as a Single User — Up and Running in 5</a></li> |
| 152 | <li><a href="globs.md">Name Glob Patterns — File</a></li> |
| 153 | <li><a href="checkin_names.wiki">Names — Check-in And Version</a></li> |
| 154 | <li><a href="adding_code.wiki">New Features To Fossil — Adding</a></li> |
| 155 | <li><a href="newrepo.wiki">New Fossil Repository — How To Create A</a></li> |
| 156 | <li><a href="alerts.md">Notification — Email Alerts And</a></li> |
| 157 | <li><a href="foss-cklist.wiki">Open-Source Projects — Checklist For Successful</a></li> |
| 158 | <li><a href="pop.wiki">Operation — Principles Of</a></li> |
| 159 | <li><a href="env-opts.md">Options — Environment Variables and Global</a></li> |
| 160 | <li><a href="tech_overview.wiki">Overview Of The Design And Implementation Of Fossil — A Technical</a></li> |
| 161 | <li><a href="index.wiki">Page — Home</a></li> |
| 162 |
| --- www/permutedindex.html | |
| +++ www/permutedindex.html | |
| @@ -23,11 +23,11 @@ | |
| 23 | <li><a href="fiveminutes.wiki">5 Minutes as a Single User — Up and Running in</a></li> |
| 24 | <li><a href="fossil-from-msvc.wiki">2010 IDE — Integrating Fossil in the Microsoft Express</a></li> |
| 25 | <li><a href="tech_overview.wiki"><b>A Technical Overview Of The Design And Implementation Of Fossil</b></a></li> |
| 26 | <li><a href="adding_code.wiki"><b>Adding New Features To Fossil</b></a></li> |
| 27 | <li><a href="copyright-release.html">Agreement — Contributor License</a></li> |
| 28 | <li><a href="alerts.md">Alerts And Notifications — Email</a></li> |
| 29 | <li><a href="delta_encoder_algorithm.wiki">Algorithm — Fossil Delta Encoding</a></li> |
| 30 | <li><a href="blame.wiki">Algorithm Of Fossil — The Annotate/Blame</a></li> |
| 31 | <li><a href="blame.wiki">Annotate/Blame Algorithm Of Fossil — The</a></li> |
| 32 | <li><a href="customskin.md">Appearance of Web Pages — Theming: Customizing The</a></li> |
| 33 | <li><a href="faq.wiki">Asked Questions — Frequently</a></li> |
| @@ -78,11 +78,11 @@ | |
| 78 | <li><a href="embeddeddoc.wiki">Documentation — Embedded Project</a></li> |
| 79 | <li><a href="contribute.wiki">Documentation To The Fossil Project — Contributing Code or</a></li> |
| 80 | <li><a href="aboutdownload.wiki">Download Page Works — How The</a></li> |
| 81 | <li><a href="theory1.wiki">DVCS — Thoughts On The Design Of The Fossil</a></li> |
| 82 | <li><a href="quotes.wiki">DVCSes in General — Quotes: What People Are Saying About Fossil, Git, and</a></li> |
| 83 | <li><a href="alerts.md"><b>Email Alerts And Notifications</b></a></li> |
| 84 | <li><a href="embeddeddoc.wiki"><b>Embedded Project Documentation</b></a></li> |
| 85 | <li><a href="delta_encoder_algorithm.wiki">Encoding Algorithm — Fossil Delta</a></li> |
| 86 | <li><a href="encryptedrepos.wiki">Encrypted Repositories — How To Use</a></li> |
| 87 | <li><a href="env-opts.md"><b>Environment Variables and Global Options</b></a></li> |
| 88 | <li><a href="event.wiki"><b>Events</b></a></li> |
| @@ -96,15 +96,17 @@ | |
| 96 | <li><a href="branching.wiki">Forking, Merging, and Tagging — Branching,</a></li> |
| 97 | <li><a href="delta_format.wiki">Format — Fossil Delta</a></li> |
| 98 | <li><a href="fileformat.wiki">Format — Fossil File</a></li> |
| 99 | <li><a href="../../../md_rules">Formatting Rules — Markdown</a></li> |
| 100 | <li><a href="../../../wiki_rules">Formatting Rules — Wiki</a></li> |
| 101 | <li><a href="forum.wiki">Forums — Fossil</a></li> |
| 102 | <li><a href="changes.wiki"><b>Fossil Changelog</b></a></li> |
| 103 | <li><a href="concepts.wiki"><b>Fossil Core Concepts</b></a></li> |
| 104 | <li><a href="delta_encoder_algorithm.wiki"><b>Fossil Delta Encoding Algorithm</b></a></li> |
| 105 | <li><a href="delta_format.wiki"><b>Fossil Delta Format</b></a></li> |
| 106 | <li><a href="fileformat.wiki"><b>Fossil File Format</b></a></li> |
| 107 | <li><a href="forum.wiki"><b>Fossil Forums</b></a></li> |
| 108 | <li><a href="quickstart.wiki"><b>Fossil Quick Start Guide</b></a></li> |
| 109 | <li><a href="selfcheck.wiki"><b>Fossil Repository Integrity Self Checks</b></a></li> |
| 110 | <li><a href="selfhost.wiki"><b>Fossil Self Hosting Repositories</b></a></li> |
| 111 | <li><a href="settings.wiki"><b>Fossil Settings</b></a></li> |
| 112 | <li><a href="hints.wiki"><b>Fossil Tips And Usage Hints</b></a></li> |
| @@ -151,11 +153,11 @@ | |
| 153 | <li><a href="fiveminutes.wiki">Minutes as a Single User — Up and Running in 5</a></li> |
| 154 | <li><a href="globs.md">Name Glob Patterns — File</a></li> |
| 155 | <li><a href="checkin_names.wiki">Names — Check-in And Version</a></li> |
| 156 | <li><a href="adding_code.wiki">New Features To Fossil — Adding</a></li> |
| 157 | <li><a href="newrepo.wiki">New Fossil Repository — How To Create A</a></li> |
| 158 | <li><a href="alerts.md">Notifications — Email Alerts And</a></li> |
| 159 | <li><a href="foss-cklist.wiki">Open-Source Projects — Checklist For Successful</a></li> |
| 160 | <li><a href="pop.wiki">Operation — Principles Of</a></li> |
| 161 | <li><a href="env-opts.md">Options — Environment Variables and Global</a></li> |
| 162 | <li><a href="tech_overview.wiki">Overview Of The Design And Implementation Of Fossil — A Technical</a></li> |
| 163 | <li><a href="index.wiki">Page — Home</a></li> |
| 164 |