Check-in [12d2f70bdf]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:The --share-links option on "fossil sync" and similar causes the server to reply with "pragma link" lines that identify other repositories with which the server has interacted within the past month. Those links are recorded in "link:URL" entries of the CONFIG table on the client.
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 12d2f70bdff55411e8a0df1a62d50215185e1ab3200aa350ce78959b3d8c133a
User & Date: drh 2021-12-21 19:50:31.088
Context
2021-12-21
20:20
Add the "Links from other repositories" section on the /urllist page. check-in: 6916a058ab user: drh tags: trunk
19:50
The --share-links option on "fossil sync" and similar causes the server to reply with "pragma link" lines that identify other repositories with which the server has interacted within the past month. Those links are recorded in "link:URL" entries of the CONFIG table on the client. check-in: 12d2f70bdf user: drh tags: trunk
18:22
For "fossil git export", add the comment line at the end of automatically generated "manifest" files so that they do not appear to be valid Fossil artifacts. check-in: 4ff45df429 user: drh tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/sync.c.
230
231
232
233
234
235
236





237
238
239
240
241
242
243
  }
  if( find_option("no-http-compression",0,0)!=0 ){
    *pSyncFlags |= SYNC_NOHTTPCOMPRESS;
  }
  if( find_option("all",0,0)!=0 ){
    *pSyncFlags |= SYNC_ALLURL;
  }





  url_proxy_options();
  clone_ssh_find_options();
  if( !uvOnly ) db_find_and_open_repository(0, 0);
  db_open_config(0, 1);
  if( g.argc==2 ){
    if( db_get_boolean("auto-shun",0) ) configSync = CONFIGSET_SHUN;
  }else if( g.argc==3 ){







>
>
>
>
>







230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
  }
  if( find_option("no-http-compression",0,0)!=0 ){
    *pSyncFlags |= SYNC_NOHTTPCOMPRESS;
  }
  if( find_option("all",0,0)!=0 ){
    *pSyncFlags |= SYNC_ALLURL;
  }
  if( ((*pSyncFlags) & SYNC_PULL)!=0
   && find_option("share-links",0,0)!=0
  ){
    *pSyncFlags |= SYNC_SHARE_LINKS;
  }
  url_proxy_options();
  clone_ssh_find_options();
  if( !uvOnly ) db_find_and_open_repository(0, 0);
  db_open_config(0, 1);
  if( g.argc==2 ){
    if( db_get_boolean("auto-shun",0) ) configSync = CONFIGSET_SHUN;
  }else if( g.argc==3 ){
292
293
294
295
296
297
298

299
300
301
302
303
304
305
**   --ipv4                     Use only IPv4, not IPv6
**   --no-http-compression      Do not compress HTTP traffic
**   --once                     Do not remember URL for subsequent syncs
**   --private                  Pull private branches too
**   --project-code CODE        Use CODE as the project code
**   --proxy PROXY              Use the specified HTTP proxy
**   -R|--repository REPO       Local repository to pull into

**   --ssl-identity FILE        Local SSL credentials, if requested by remote
**   --ssh-command SSH          Use SSH as the "ssh" command
**   -v|--verbose               Additional (debugging) output
**   --verily                   Exchange extra information with the remote
**                              to ensure no content is overlooked
**
** See also: [[clone]], [[config]], [[push]], [[remote]], [[sync]]







>







297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
**   --ipv4                     Use only IPv4, not IPv6
**   --no-http-compression      Do not compress HTTP traffic
**   --once                     Do not remember URL for subsequent syncs
**   --private                  Pull private branches too
**   --project-code CODE        Use CODE as the project code
**   --proxy PROXY              Use the specified HTTP proxy
**   -R|--repository REPO       Local repository to pull into
**   --share-links              Share links to mirror repos
**   --ssl-identity FILE        Local SSL credentials, if requested by remote
**   --ssh-command SSH          Use SSH as the "ssh" command
**   -v|--verbose               Additional (debugging) output
**   --verily                   Exchange extra information with the remote
**                              to ensure no content is overlooked
**
** See also: [[clone]], [[config]], [[push]], [[remote]], [[sync]]
390
391
392
393
394
395
396

397
398
399
400
401
402
403
**                              if required by the remote website
**   --ipv4                     Use only IPv4, not IPv6
**   --no-http-compression      Do not compress HTTP traffic
**   --once                     Do not remember URL for subsequent syncs
**   --proxy PROXY              Use the specified HTTP proxy
**   --private                  Sync private branches too
**   -R|--repository REPO       Local repository to sync with

**   --ssl-identity FILE        Local SSL credentials, if requested by remote
**   --ssh-command SSH          Use SSH as the "ssh" command
**   -u|--unversioned           Also sync unversioned content
**   -v|--verbose               Additional (debugging) output
**   --verily                   Exchange extra information with the remote
**                              to ensure no content is overlooked
**







>







396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
**                              if required by the remote website
**   --ipv4                     Use only IPv4, not IPv6
**   --no-http-compression      Do not compress HTTP traffic
**   --once                     Do not remember URL for subsequent syncs
**   --proxy PROXY              Use the specified HTTP proxy
**   --private                  Sync private branches too
**   -R|--repository REPO       Local repository to sync with
**   --share-links              Share links to mirror repos
**   --ssl-identity FILE        Local SSL credentials, if requested by remote
**   --ssh-command SSH          Use SSH as the "ssh" command
**   -u|--unversioned           Also sync unversioned content
**   -v|--verbose               Additional (debugging) output
**   --verily                   Exchange extra information with the remote
**                              to ensure no content is overlooked
**
Changes to src/xfer.c.
1207
1208
1209
1210
1211
1212
1213

1214
1215
1216
1217
1218
1219
1220
  int rc;
  const char *zScript = 0;
  char *zUuidList = 0;
  int nUuidList = 0;
  char **pzUuidList = 0;
  int *pnUuidList = 0;
  int uvCatalogSent = 0;


  if( fossil_strcmp(PD("REQUEST_METHOD","POST"),"POST") ){
     fossil_redirect_home();
  }
  g.zLogin = "anonymous";
  login_set_anon_nobody_capabilities();
  login_check_credentials();







>







1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
  int rc;
  const char *zScript = 0;
  char *zUuidList = 0;
  int nUuidList = 0;
  char **pzUuidList = 0;
  int *pnUuidList = 0;
  int uvCatalogSent = 0;
  int bSendLinks = 0;

  if( fossil_strcmp(PD("REQUEST_METHOD","POST"),"POST") ){
     fossil_redirect_home();
  }
  g.zLogin = "anonymous";
  login_set_anon_nobody_capabilities();
  login_check_credentials();
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
      if( blob_eq(&xfer.aToken[1], "send-private") ){
        login_check_credentials();
        if( !g.perm.Private ){
          server_private_xfer_not_authorized();
        }else{
          xfer.syncPrivate = 1;
        }
      }

      /*   pragma send-catalog
      **
      ** The client wants to see igot cards for all known artifacts.
      ** This is used as part of "sync --verily" to help ensure that
      ** no artifacts have been missed on prior syncs.
      */
      if( blob_eq(&xfer.aToken[1], "send-catalog") ){
        xfer.resync = 0x7fffffff;
      }

      /*   pragma client-version VERSION ?DATE? ?TIME?
      **
      ** The client announces to the server what version of Fossil it
      ** is running.  The DATE and TIME are a pure numeric ISO8601 time
      ** for the specific check-in of the client.
      */
      if( xfer.nToken>=3 && blob_eq(&xfer.aToken[1], "client-version") ){
        xfer.remoteVersion = atoi(blob_str(&xfer.aToken[2]));
        if( xfer.nToken>=5 ){
          xfer.remoteDate = atoi(blob_str(&xfer.aToken[3]));
          xfer.remoteTime = atoi(blob_str(&xfer.aToken[4]));
          @ pragma server-version %d(RELEASE_VERSION_NUMBER) \
          @ %d(MANIFEST_NUMERIC_DATE) %d(MANIFEST_NUMERIC_TIME)
        }
      }

      /*   pragma uv-hash HASH
      **
      ** The client wants to make sure that unversioned files are all synced.
      ** If the HASH does not match, send a complete catalog of
      ** "uvigot" cards.
      */







|









|















|







1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
      if( blob_eq(&xfer.aToken[1], "send-private") ){
        login_check_credentials();
        if( !g.perm.Private ){
          server_private_xfer_not_authorized();
        }else{
          xfer.syncPrivate = 1;
        }
      }else

      /*   pragma send-catalog
      **
      ** The client wants to see igot cards for all known artifacts.
      ** This is used as part of "sync --verily" to help ensure that
      ** no artifacts have been missed on prior syncs.
      */
      if( blob_eq(&xfer.aToken[1], "send-catalog") ){
        xfer.resync = 0x7fffffff;
      }else

      /*   pragma client-version VERSION ?DATE? ?TIME?
      **
      ** The client announces to the server what version of Fossil it
      ** is running.  The DATE and TIME are a pure numeric ISO8601 time
      ** for the specific check-in of the client.
      */
      if( xfer.nToken>=3 && blob_eq(&xfer.aToken[1], "client-version") ){
        xfer.remoteVersion = atoi(blob_str(&xfer.aToken[2]));
        if( xfer.nToken>=5 ){
          xfer.remoteDate = atoi(blob_str(&xfer.aToken[3]));
          xfer.remoteTime = atoi(blob_str(&xfer.aToken[4]));
          @ pragma server-version %d(RELEASE_VERSION_NUMBER) \
          @ %d(MANIFEST_NUMERIC_DATE) %d(MANIFEST_NUMERIC_TIME)
        }
      }else

      /*   pragma uv-hash HASH
      **
      ** The client wants to make sure that unversioned files are all synced.
      ** If the HASH does not match, send a complete catalog of
      ** "uvigot" cards.
      */
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
            @ pragma uv-push-ok
          }else if( g.perm.Read ){
            @ pragma uv-pull-only
          }
          send_unversioned_catalog(&xfer);
        }
        uvCatalogSent = 1;
      }

      /*   pragma ci-lock CHECKIN-HASH CLIENT-ID
      **
      ** The client wants to make non-branch commit against the check-in
      ** identified by CHECKIN-HASH.  The server will remember this and
      ** subsequent ci-lock requests from different clients will generate
      ** a ci-lock-fail pragma in the reply.







|







1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
            @ pragma uv-push-ok
          }else if( g.perm.Read ){
            @ pragma uv-pull-only
          }
          send_unversioned_catalog(&xfer);
        }
        uvCatalogSent = 1;
      }else

      /*   pragma ci-lock CHECKIN-HASH CLIENT-ID
      **
      ** The client wants to make non-branch commit against the check-in
      ** identified by CHECKIN-HASH.  The server will remember this and
      ** subsequent ci-lock requests from different clients will generate
      ** a ci-lock-fail pragma in the reply.
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745









1746
1747
1748
1749
1750
1751
1752
            blob_str(&xfer.aToken[3])
          );
          db_protect_pop();
        }
        if( db_get_boolean("forbid-delta-manifests",0) ){
          @ pragma avoid-delta-manifests
        }
      }

      /*   pragma ci-unlock CLIENT-ID
      **
      ** Remove any locks previously held by CLIENT-ID.  Clients send this
      ** pragma with their own ID whenever they know that they no longer
      ** have any commits pending.
      */
      if( blob_eq(&xfer.aToken[1], "ci-unlock")
       && xfer.nToken==3
       && blob_is_hname(&xfer.aToken[2])
      ){
        db_unprotect(PROTECT_CONFIG);
        db_multi_exec(
          "DELETE FROM config"
          " WHERE name GLOB 'ci-lock-*'"
          "   AND json_extract(value,'$.clientid')=%Q",
          blob_str(&xfer.aToken[2])
        );
        db_protect_pop();
      }

      /*   pragma client-url URL
      **
      ** This pragma is an informational notification to the server that
      ** their relationship could, in theory, be inverted by having the
      ** server call the client at URL.
      */
      if( blob_eq(&xfer.aToken[1], "client-url")
       && xfer.nToken==3
       && g.perm.Write
      ){
        xfer_syncwith(blob_str(&xfer.aToken[2]), 1);









      }

    }else

    /* Unknown message
    */
    {







|



















|












>
>
>
>
>
>
>
>
>







1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
            blob_str(&xfer.aToken[3])
          );
          db_protect_pop();
        }
        if( db_get_boolean("forbid-delta-manifests",0) ){
          @ pragma avoid-delta-manifests
        }
      }else

      /*   pragma ci-unlock CLIENT-ID
      **
      ** Remove any locks previously held by CLIENT-ID.  Clients send this
      ** pragma with their own ID whenever they know that they no longer
      ** have any commits pending.
      */
      if( blob_eq(&xfer.aToken[1], "ci-unlock")
       && xfer.nToken==3
       && blob_is_hname(&xfer.aToken[2])
      ){
        db_unprotect(PROTECT_CONFIG);
        db_multi_exec(
          "DELETE FROM config"
          " WHERE name GLOB 'ci-lock-*'"
          "   AND json_extract(value,'$.clientid')=%Q",
          blob_str(&xfer.aToken[2])
        );
        db_protect_pop();
      }else

      /*   pragma client-url URL
      **
      ** This pragma is an informational notification to the server that
      ** their relationship could, in theory, be inverted by having the
      ** server call the client at URL.
      */
      if( blob_eq(&xfer.aToken[1], "client-url")
       && xfer.nToken==3
       && g.perm.Write
      ){
        xfer_syncwith(blob_str(&xfer.aToken[2]), 1);
      }else

      /*    pragma req-links
      **
      ** The client sends this message to the server to ask the server
      ** to tell it about alternative repositories  in the reply.
      */
      if( blob_eq(&xfer.aToken[1], "req-links") ){
        bSendLinks = 1;
      }

    }else

    /* Unknown message
    */
    {
1784
1785
1786
1787
1788
1789
1790



































1791
1792
1793
1794
1795
1796
1797
    create_cluster();
    send_unclustered(&xfer);
    if( xfer.syncPrivate ) send_private(&xfer);
  }
  hook_expecting_more_artifacts(xfer.nGimmeSent?60:0);
  db_multi_exec("DROP TABLE onremote; DROP TABLE unk;");
  manifest_crosslink_end(MC_PERMIT_HOOKS);




































  /* Send the server timestamp last, in case prior processing happened
  ** to use up a significant fraction of our time window.
  */
  zNow = db_text(0, "SELECT strftime('%%Y-%%m-%%dT%%H:%%M:%%S', 'now')");
  @ # timestamp %s(zNow)
  free(zNow);







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
    create_cluster();
    send_unclustered(&xfer);
    if( xfer.syncPrivate ) send_private(&xfer);
  }
  hook_expecting_more_artifacts(xfer.nGimmeSent?60:0);
  db_multi_exec("DROP TABLE onremote; DROP TABLE unk;");
  manifest_crosslink_end(MC_PERMIT_HOOKS);

  /* Send URLs for alternative repositories for the same project,
  ** if requested by the client. */
  if( bSendLinks && g.zBaseURL ){
    Stmt q;
    db_prepare(&q,
      "WITH remote(mtime, url, arg) AS (\n"
      "  SELECT mtime, substr(name,10), '{}' FROM config\n"
      "   WHERE name GLOB 'syncwith:http*'\n"
      "  UNION ALL\n"
      "  SELECT mtime, substr(name,10), '{}' FROM config\n"
      "   WHERE name GLOB 'syncfrom:http*'\n"
      "  UNION ALL\n"
      "  SELECT mtime, substr(name,9), '{\"type\":\"git\"}' FROM config\n"
      "   WHERE name GLOB 'gitpush:*'\n"
      ")\n"
      "SELECT url, json_insert(arg,'$.src',%Q), max(mtime)\n"
      "  FROM remote WHERE mtime>unixepoch('now','-1 month')\n"
      " GROUP BY url;",
      g.zBaseURL
    );
    while( db_step(&q)==SQLITE_ROW ){
      UrlData x;
      const char *zUrl = db_column_text(&q, 0);
      const char *zArg = db_column_text(&q, 1);
      i64 iMtime = db_column_int64(&q, 2);
      memset(&x, 0, sizeof(x));
      url_parse_local(zUrl, URL_OMIT_USER, &x);
      if( x.name!=0 && sqlite3_strlike("%localhost%", x.name, 0)!=0 ){
        @ pragma link %F(x.canonical) %F(zArg) %lld(iMtime)
      }
      url_unparse(&x);      
    }
    db_finalize(&q);
  }

  /* Send the server timestamp last, in case prior processing happened
  ** to use up a significant fraction of our time window.
  */
  zNow = db_text(0, "SELECT strftime('%%Y-%%m-%%dT%%H:%%M:%%S', 'now')");
  @ # timestamp %s(zNow)
  free(zNow);
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861

1862
1863
1864
1865
1866
1867
1868
static const char zBriefFormat[] =
   "Round-trips: %d   Artifacts sent: %d  received: %d\r";

#if INTERFACE
/*
** Flag options for controlling client_sync()
*/
#define SYNC_PUSH           0x0001    /* push content client to server */
#define SYNC_PULL           0x0002    /* pull content server to client */
#define SYNC_CLONE          0x0004    /* clone the repository */
#define SYNC_PRIVATE        0x0008    /* Also transfer private content */
#define SYNC_VERBOSE        0x0010    /* Extra diagnostics */
#define SYNC_RESYNC         0x0020    /* --verily */
#define SYNC_FROMPARENT     0x0040    /* Pull from the parent project */
#define SYNC_UNVERSIONED    0x0100    /* Sync unversioned content */
#define SYNC_UV_REVERT      0x0200    /* Copy server unversioned to client */
#define SYNC_UV_TRACE       0x0400    /* Describe UV activities */
#define SYNC_UV_DRYRUN      0x0800    /* Do not actually exchange files */
#define SYNC_IFABLE         0x1000    /* Inability to sync is not fatal */
#define SYNC_CKIN_LOCK      0x2000    /* Lock the current check-in */
#define SYNC_NOHTTPCOMPRESS 0x4000    /* Do not compression HTTP messages */
#define SYNC_ALLURL         0x8000    /* The --all flag - sync to all URLs */

#endif

/*
** Floating-point absolute value
*/
static double fossil_fabs(double x){
  return x>0.0 ? x : -x;







|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>







1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
static const char zBriefFormat[] =
   "Round-trips: %d   Artifacts sent: %d  received: %d\r";

#if INTERFACE
/*
** Flag options for controlling client_sync()
*/
#define SYNC_PUSH           0x00001    /* push content client to server */
#define SYNC_PULL           0x00002    /* pull content server to client */
#define SYNC_CLONE          0x00004    /* clone the repository */
#define SYNC_PRIVATE        0x00008    /* Also transfer private content */
#define SYNC_VERBOSE        0x00010    /* Extra diagnostics */
#define SYNC_RESYNC         0x00020    /* --verily */
#define SYNC_FROMPARENT     0x00040    /* Pull from the parent project */
#define SYNC_UNVERSIONED    0x00100    /* Sync unversioned content */
#define SYNC_UV_REVERT      0x00200    /* Copy server unversioned to client */
#define SYNC_UV_TRACE       0x00400    /* Describe UV activities */
#define SYNC_UV_DRYRUN      0x00800    /* Do not actually exchange files */
#define SYNC_IFABLE         0x01000    /* Inability to sync is not fatal */
#define SYNC_CKIN_LOCK      0x02000    /* Lock the current check-in */
#define SYNC_NOHTTPCOMPRESS 0x04000    /* Do not compression HTTP messages */
#define SYNC_ALLURL         0x08000    /* The --all flag - sync to all URLs */
#define SYNC_SHARE_LINKS    0x10000    /* Request alternate repo links */
#endif

/*
** Floating-point absolute value
*/
static double fossil_fabs(double x){
  return x>0.0 ? x : -x;
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
  if( zAltPCode==0 ){
    const char *zSelfUrl = public_url();
    if( zSelfUrl ){
      blob_appendf(&send, "pragma client-url %s\n", zSelfUrl);
    }
  }

  /* Request names of alternative repositories
  */
  if( zAltPCode==0 ){
    blob_appendf(&send, "pragma req-alt-repo\n");
  }

  while( go ){
    int newPhantom = 0;
    char *zRandomness;
    db_begin_transaction();
    db_record_repository_filename(0);







|

|
|







2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
  if( zAltPCode==0 ){
    const char *zSelfUrl = public_url();
    if( zSelfUrl ){
      blob_appendf(&send, "pragma client-url %s\n", zSelfUrl);
    }
  }

  /* Request URLs of alternative repositories
  */
  if( zAltPCode==0 && (syncFlags & SYNC_SHARE_LINKS)!=0 ){
    blob_appendf(&send, "pragma req-links\n");
  }

  while( go ){
    int newPhantom = 0;
    char *zRandomness;
    db_begin_transaction();
    db_record_repository_filename(0);
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
        **
        ** If the server is unwill to accept new unversioned content (because
        ** this client lacks the necessary permissions) then it sends a
        ** "uv-pull-only" pragma so that the client will know not to waste
        ** bandwidth trying to upload unversioned content.  If the server
        ** does accept new unversioned content, it sends "uv-push-ok".
        */
        if( syncFlags & SYNC_UNVERSIONED ){
          if( blob_eq(&xfer.aToken[1], "uv-pull-only") ){
            uvPullOnly = 1;
            if( syncFlags & SYNC_UV_REVERT ) uvDoPush = 1;
          }else if( blob_eq(&xfer.aToken[1], "uv-push-ok") ){
            uvDoPush = 1;
          }
        }







|







2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
        **
        ** If the server is unwill to accept new unversioned content (because
        ** this client lacks the necessary permissions) then it sends a
        ** "uv-pull-only" pragma so that the client will know not to waste
        ** bandwidth trying to upload unversioned content.  If the server
        ** does accept new unversioned content, it sends "uv-push-ok".
        */
        else if( syncFlags & SYNC_UNVERSIONED ){
          if( blob_eq(&xfer.aToken[1], "uv-pull-only") ){
            uvPullOnly = 1;
            if( syncFlags & SYNC_UV_REVERT ) uvDoPush = 1;
          }else if( blob_eq(&xfer.aToken[1], "uv-push-ok") ){
            uvDoPush = 1;
          }
        }
2628
2629
2630
2631
2632
2633
2634




































2635
2636
2637
2638
2639
2640
2641
        **
        ** Discourage the use of delta manifests.  The remote side sends
        ** this pragma when its forbid-delta-manifests setting is true.
        */
        else if( blob_eq(&xfer.aToken[1], "avoid-delta-manifests") ){
          g.bAvoidDeltaManifests = 1;
        }




































      }else

      /*   error MESSAGE
      **
      ** The server is reporting an error.  The client will abandon
      ** the sync session.
      **







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
        **
        ** Discourage the use of delta manifests.  The remote side sends
        ** this pragma when its forbid-delta-manifests setting is true.
        */
        else if( blob_eq(&xfer.aToken[1], "avoid-delta-manifests") ){
          g.bAvoidDeltaManifests = 1;
        }

        /*    pragma link URL ARG MTIME
        **
        ** The server has sent the URL for a link to another repository.
        ** Record this as a link:URL entry in the config table.
        */
        else if( blob_eq(&xfer.aToken[1], "link")
              && xfer.nToken==5
              && (syncFlags & SYNC_SHARE_LINKS)!=0
        ){
          UrlData x;
          char *zUrl = blob_str(&xfer.aToken[2]);
          char *zArg = blob_str(&xfer.aToken[3]);
          i64 iTime = strtoll(blob_str(&xfer.aToken[4]),0,0);
          memset(&x, 0, sizeof(x));
          defossilize(zUrl);
          defossilize(zArg);
          url_parse_local(zUrl, URL_OMIT_USER, &x);
          if( x.protocol
           && strncmp(x.protocol,"http",4)==0
           && iTime>0
          ){
            db_unprotect(PROTECT_CONFIG);
            db_multi_exec(
              "INSERT INTO config(name,value,mtime)\n"
              " VALUES('link:%q',%Q,%lld)\n"
              " ON CONFLICT DO UPDATE\n"
              "   SET value=excluded.value, mtime=excluded.mtime\n"
              "   WHERE mtime<excluded.mtime;",
              zUrl, zArg, iTime
            );
            db_protect_pop();
          }
          url_unparse(&x);
        }

      }else

      /*   error MESSAGE
      **
      ** The server is reporting an error.  The client will abandon
      ** the sync session.
      **