| | @@ -1150,10 +1150,43 @@ |
| 1150 | 1150 | ** } |
| 1151 | 1151 | */ |
| 1152 | 1152 | int xfer_run_common_script(void){ |
| 1153 | 1153 | return xfer_run_script(xfer_common_code(), 0, 0); |
| 1154 | 1154 | } |
| 1155 | + |
| 1156 | +/* |
| 1157 | +** The current line is a "pragma synclog". Accept this line into |
| 1158 | +** the SYNCLOG table, if appropriate. |
| 1159 | +** |
| 1160 | +** pragma synclog FROM TO MTIME ?TYPE? |
| 1161 | +** |
| 1162 | +** The name of the remote size is zRemote. The value of "this" for |
| 1163 | +** either the FROM or TO fields is converted into zRemote. |
| 1164 | +** |
| 1165 | +** If either FROM or TO is an alias for the current repository, then |
| 1166 | +** silently reject the entry. |
| 1167 | +*/ |
| 1168 | +static void xfer_accept_synclog_pragma( |
| 1169 | + Xfer *pXfer, /* Current line of xfer script */ |
| 1170 | + const char *zRemote /* The name of the remote repository */ |
| 1171 | +){ |
| 1172 | + const char *zFrom = blob_str(&pXfer->aToken[2]); |
| 1173 | + const char *zTo = blob_str(&pXfer->aToken[3]); |
| 1174 | + i64 iTime = strtoll(blob_str(&pXfer->aToken[4]), 0, 0); |
| 1175 | + const char *zType = pXfer->nToken>=5 ? blob_str(&pXfer->aToken[5]) : 0; |
| 1176 | + if( strcmp(zFrom, "this")==0 ){ |
| 1177 | + zFrom = zRemote; |
| 1178 | + }else if( db_exists("SELECT 1 FROM config WHERE name='baseurl:%q'",zFrom) ){ |
| 1179 | + iTime = 0; |
| 1180 | + } |
| 1181 | + if( strcmp(zTo, "this")==0 ){ |
| 1182 | + zTo = zRemote; |
| 1183 | + }else if( db_exists("SELECT 1 FROM config WHERE name='baseurl:%q'",zTo) ){ |
| 1184 | + iTime = 0; |
| 1185 | + } |
| 1186 | + if( iTime>0 ) sync_log_entry(zFrom, zTo, iTime, zType); |
| 1187 | +} |
| 1155 | 1188 | |
| 1156 | 1189 | /* |
| 1157 | 1190 | ** If this variable is set, disable login checks. Used for debugging |
| 1158 | 1191 | ** only. |
| 1159 | 1192 | */ |
| | @@ -1187,10 +1220,11 @@ |
| 1187 | 1220 | char *zUuidList = 0; |
| 1188 | 1221 | int nUuidList = 0; |
| 1189 | 1222 | char **pzUuidList = 0; |
| 1190 | 1223 | int *pnUuidList = 0; |
| 1191 | 1224 | int uvCatalogSent = 0; |
| 1225 | + const char *zClientUrl = 0; |
| 1192 | 1226 | |
| 1193 | 1227 | if( fossil_strcmp(PD("REQUEST_METHOD","POST"),"POST") ){ |
| 1194 | 1228 | fossil_redirect_home(); |
| 1195 | 1229 | } |
| 1196 | 1230 | g.zLogin = "anonymous"; |
| | @@ -1686,11 +1720,11 @@ |
| 1686 | 1720 | db_protect_pop(); |
| 1687 | 1721 | } |
| 1688 | 1722 | if( db_get_boolean("forbid-delta-manifests",0) ){ |
| 1689 | 1723 | @ pragma avoid-delta-manifests |
| 1690 | 1724 | } |
| 1691 | | - } |
| 1725 | + }else |
| 1692 | 1726 | |
| 1693 | 1727 | /* pragma ci-unlock CLIENT-ID |
| 1694 | 1728 | ** |
| 1695 | 1729 | ** Remove any locks previously held by CLIENT-ID. Clients send this |
| 1696 | 1730 | ** pragma with their own ID whenever they know that they no longer |
| | @@ -1706,10 +1740,61 @@ |
| 1706 | 1740 | " WHERE name GLOB 'ci-lock-*'" |
| 1707 | 1741 | " AND json_extract(value,'$.clientid')=%Q", |
| 1708 | 1742 | blob_str(&xfer.aToken[2]) |
| 1709 | 1743 | ); |
| 1710 | 1744 | db_protect_pop(); |
| 1745 | + }else |
| 1746 | + |
| 1747 | + /* pragma req-synclog ?CLIENT-URL? |
| 1748 | + ** |
| 1749 | + ** Request synclog data. If the CLIENT-URL argument is provided, |
| 1750 | + ** it will be the canonical URL for the client. |
| 1751 | + */ |
| 1752 | + if( blob_eq(&xfer.aToken[1], "req-synclog") && g.perm.RdSLog ){ |
| 1753 | + Stmt qSynclog; |
| 1754 | + if( xfer.nToken>=2 ){ |
| 1755 | + zClientUrl = blob_str(&xfer.aToken[2]); |
| 1756 | + if( sqlite3_strlike("http%//localhost%", zClientUrl, 0)==0 ){ |
| 1757 | + zClientUrl = 0; |
| 1758 | + } |
| 1759 | + } |
| 1760 | + db_prepare(&qSynclog, |
| 1761 | + "SELECT sfrom, sto, unixepoch(stime), stype FROM synclog" |
| 1762 | + ); |
| 1763 | + while( db_step(&qSynclog)==SQLITE_ROW ){ |
| 1764 | + const char *zFrom = db_column_text(&qSynclog,0); |
| 1765 | + const char *zTo = db_column_text(&qSynclog,1); |
| 1766 | + const char *zTime = db_column_text(&qSynclog,2); |
| 1767 | + const char *zType = db_column_text(&qSynclog,3); |
| 1768 | + if( zClientUrl ){ |
| 1769 | + if( strcmp(zFrom, zClientUrl)==0 ) continue; |
| 1770 | + if( strcmp(zTo, zClientUrl)==0 ) continue; |
| 1771 | + } |
| 1772 | + if( zType!=0 && zType[0]!=0 ){ |
| 1773 | + @ pragma synclog %s(zFrom) %s(zTo) %s(zTime) %s(zType) |
| 1774 | + }else{ |
| 1775 | + @ pragma synclog %s(zFrom) %s(zTo) %s(zTime) |
| 1776 | + } |
| 1777 | + } |
| 1778 | + }else |
| 1779 | + |
| 1780 | + /* pragma synclog FROM TO MTIME ?TYPE? |
| 1781 | + ** |
| 1782 | + ** The client is uploading an entry from its SYNCLOG table. This |
| 1783 | + ** will only be accepted if both: |
| 1784 | + ** |
| 1785 | + ** (1) The client as WrSLog permission |
| 1786 | + ** (2) A prior req-synclog pragma has identified the URL of the client |
| 1787 | + ** |
| 1788 | + ** Insert the entry into the SYNC log if appropriate. |
| 1789 | + */ |
| 1790 | + if( xfer.nToken>=4 |
| 1791 | + && blob_eq(&xfer.aToken[1], "synclog") |
| 1792 | + && g.perm.WrSLog |
| 1793 | + && zClientUrl!=0 |
| 1794 | + ){ |
| 1795 | + xfer_accept_synclog_pragma(&xfer, zClientUrl); |
| 1711 | 1796 | } |
| 1712 | 1797 | |
| 1713 | 1798 | }else |
| 1714 | 1799 | |
| 1715 | 1800 | /* Unknown message |
| | @@ -2121,10 +2206,44 @@ |
| 2121 | 2206 | blob_appendf(&send, "pragma ci-lock %s %s\n", zCkinLock, zClientId); |
| 2122 | 2207 | zCkinLock = 0; |
| 2123 | 2208 | }else if( zClientId ){ |
| 2124 | 2209 | blob_appendf(&send, "pragma ci-unlock %s\n", zClientId); |
| 2125 | 2210 | } |
| 2211 | + |
| 2212 | + /* Transfer SYNCLOG data on the first roundtrip, if appropriate */ |
| 2213 | + if( nCycle==0 ){ |
| 2214 | + const char *zSelfUrl = public_url(); |
| 2215 | + if( sqlite3_strlike("http%//localhost%", zSelfUrl, 0)==0 ){ |
| 2216 | + zSelfUrl = 0; |
| 2217 | + } |
| 2218 | + if( zSelfUrl==0 ){ |
| 2219 | + blob_appendf(&send,"pragma req-synclog\n"); |
| 2220 | + }else{ |
| 2221 | + blob_appendf(&send,"pragma req-synclog %s\n", zSelfUrl); |
| 2222 | + if( syncFlags & SYNC_PUSH_SYNCLOG ){ |
| 2223 | + Stmt qSynclog; |
| 2224 | + db_prepare(&qSynclog, |
| 2225 | + "SELECT sfrom, sto, unixepoch(stime), stype FROM synclog" |
| 2226 | + " WHERE sfrom!=%Q AND sto!=%Q", |
| 2227 | + g.url.canonical, g.url.canonical |
| 2228 | + ); |
| 2229 | + while( db_step(&qSynclog)==SQLITE_ROW ){ |
| 2230 | + const char *zFrom = db_column_text(&qSynclog,0); |
| 2231 | + const char *zTo = db_column_text(&qSynclog,1); |
| 2232 | + const char *zTime = db_column_text(&qSynclog,2); |
| 2233 | + const char *zType = db_column_text(&qSynclog,3); |
| 2234 | + if( zType!=0 && zType[0]!=0 ){ |
| 2235 | + blob_appendf(&send,"pragma synclog %s %s %s %s\n", |
| 2236 | + zFrom, zTo, zTime, zType); |
| 2237 | + }else{ |
| 2238 | + blob_appendf(&send,"pragma synclog %s %s %s\n", |
| 2239 | + zFrom, zTo, zTime); |
| 2240 | + } |
| 2241 | + } |
| 2242 | + } |
| 2243 | + } |
| 2244 | + } |
| 2126 | 2245 | |
| 2127 | 2246 | /* Append randomness to the end of the uplink message. This makes all |
| 2128 | 2247 | ** messages unique so that that the login-card nonce will always |
| 2129 | 2248 | ** be unique. |
| 2130 | 2249 | */ |
| | @@ -2524,19 +2643,19 @@ |
| 2524 | 2643 | xfer.remoteDate = atoi(blob_str(&xfer.aToken[3])); |
| 2525 | 2644 | xfer.remoteTime = atoi(blob_str(&xfer.aToken[4])); |
| 2526 | 2645 | } |
| 2527 | 2646 | } |
| 2528 | 2647 | |
| 2529 | | - /* pragma synclog FROM TO MTIME TYPE |
| 2648 | + /* pragma synclog FROM TO MTIME ?TYPE? |
| 2530 | 2649 | ** |
| 2531 | 2650 | ** The server is downloading an entry from its SYNCLOG table. Merge |
| 2532 | 2651 | ** this into the local SYNCLOG table if appropriate. |
| 2533 | 2652 | ** is running. The DATE and TIME are a pure numeric ISO8601 time |
| 2534 | 2653 | ** for the specific check-in of the client. |
| 2535 | 2654 | */ |
| 2536 | | - if( xfer.nToken==5 && blob_eq(&xfer.aToken[1], "synclog") ){ |
| 2537 | | - /* TBD */ |
| 2655 | + if( xfer.nToken>=4 && blob_eq(&xfer.aToken[1], "synclog") ){ |
| 2656 | + xfer_accept_synclog_pragma(&xfer, g.url.canonical); |
| 2538 | 2657 | } |
| 2539 | 2658 | |
| 2540 | 2659 | /* pragma uv-pull-only |
| 2541 | 2660 | ** pragma uv-push-ok |
| 2542 | 2661 | ** |
| | @@ -2705,11 +2824,20 @@ |
| 2705 | 2824 | db_timespan_name(-rSkew)); |
| 2706 | 2825 | g.clockSkewSeen = 1; |
| 2707 | 2826 | } |
| 2708 | 2827 | |
| 2709 | 2828 | if( nErr==0 ){ |
| 2710 | | - sync_log_entry(syncFlags, g.url.canonical, zAltPCode!=0 ? "import" : 0, 0); |
| 2829 | + if( zAltPCode!=0 ){ |
| 2830 | + sync_log_entry(g.url.canonical, "this", 0, "import"); |
| 2831 | + }else{ |
| 2832 | + if( syncFlags & SYNC_PUSH ){ |
| 2833 | + sync_log_entry("this", g.url.canonical, 0, 0); |
| 2834 | + } |
| 2835 | + if( syncFlags & SYNC_PULL ){ |
| 2836 | + sync_log_entry(g.url.canonical, "this", 0, 0); |
| 2837 | + } |
| 2838 | + } |
| 2711 | 2839 | } |
| 2712 | 2840 | |
| 2713 | 2841 | fossil_force_newline(); |
| 2714 | 2842 | fossil_print( |
| 2715 | 2843 | "%s done, wire bytes sent: %lld received: %lld ip: %s\n", |
| 2716 | 2844 | |