Fossil SCM
merge trunk
Commit
7e7dcdd2c9b6be29078470de7c42a55694338c0b
Parent
2c5844b1bebfe5d…
11 files changed
+66
+24
-22
+35
-2
+75
-21
+5
-1
+27
-9
+40
-24
+11
-10
+49
-3
+9
-9
+1
-1
+66
| --- src/descendants.c | ||
| +++ src/descendants.c | ||
| @@ -441,5 +441,71 @@ | ||
| 441 | 441 | @ function xout(id){ |
| 442 | 442 | @ } |
| 443 | 443 | @ </script> |
| 444 | 444 | style_footer(); |
| 445 | 445 | } |
| 446 | + | |
| 447 | +#if INTERFACE | |
| 448 | +/* Flag parameters to compute_uses_file() */ | |
| 449 | +#define USESFILE_DELETE 0x01 /* Include the check-ins where file deleted */ | |
| 450 | + | |
| 451 | +#endif | |
| 452 | + | |
| 453 | + | |
| 454 | +/* | |
| 455 | +** Add to table zTab the record ID (rid) of every check-in that contains | |
| 456 | +** the file fid. | |
| 457 | +*/ | |
| 458 | +void compute_uses_file(const char *zTab, int fid, int usesFlags){ | |
| 459 | + Bag seen; | |
| 460 | + Bag pending; | |
| 461 | + Stmt ins; | |
| 462 | + Stmt q; | |
| 463 | + int rid; | |
| 464 | + | |
| 465 | + bag_init(&seen); | |
| 466 | + bag_init(&pending); | |
| 467 | + db_prepare(&ins, "INSERT OR IGNORE INTO \"%s\" VALUES(:rid)", zTab); | |
| 468 | + db_prepare(&q, "SELECT mid FROM mlink WHERE fid=%d", fid); | |
| 469 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 470 | + int mid = db_column_int(&q, 0); | |
| 471 | + bag_insert(&pending, mid); | |
| 472 | + bag_insert(&seen, mid); | |
| 473 | + db_bind_int(&ins, ":rid", mid); | |
| 474 | + db_step(&ins); | |
| 475 | + db_reset(&ins); | |
| 476 | + } | |
| 477 | + db_finalize(&q); | |
| 478 | + | |
| 479 | + db_prepare(&q, "SELECT mid FROM mlink WHERE pid=%d", fid); | |
| 480 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 481 | + int mid = db_column_int(&q, 0); | |
| 482 | + bag_insert(&seen, mid); | |
| 483 | + if( usesFlags & USESFILE_DELETE ){ | |
| 484 | + db_bind_int(&ins, ":rid", mid); | |
| 485 | + db_step(&ins); | |
| 486 | + db_reset(&ins); | |
| 487 | + } | |
| 488 | + } | |
| 489 | + db_finalize(&q); | |
| 490 | + db_prepare(&q, "SELECT cid FROM plink WHERE pid=:rid"); | |
| 491 | + | |
| 492 | + while( (rid = bag_first(&pending))!=0 ){ | |
| 493 | + bag_remove(&pending, rid); | |
| 494 | + db_bind_int(&q, ":rid", rid); | |
| 495 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 496 | + int mid = db_column_int(&q, 0); | |
| 497 | + if( bag_find(&seen, mid) ) continue; | |
| 498 | + bag_insert(&seen, mid); | |
| 499 | + bag_insert(&pending, mid); | |
| 500 | + db_bind_int(&ins, ":rid", mid); | |
| 501 | + db_step(&ins); | |
| 502 | + db_reset(&ins); | |
| 503 | + } | |
| 504 | + db_reset(&q); | |
| 505 | + } | |
| 506 | + db_finalize(&q); | |
| 507 | + db_finalize(&ins); | |
| 508 | + bag_clear(&seen); | |
| 509 | + bag_clear(&pending); | |
| 510 | +} | |
| 511 | + | |
| 446 | 512 |
| --- src/descendants.c | |
| +++ src/descendants.c | |
| @@ -441,5 +441,71 @@ | |
| 441 | @ function xout(id){ |
| 442 | @ } |
| 443 | @ </script> |
| 444 | style_footer(); |
| 445 | } |
| 446 |
| --- src/descendants.c | |
| +++ src/descendants.c | |
| @@ -441,5 +441,71 @@ | |
| 441 | @ function xout(id){ |
| 442 | @ } |
| 443 | @ </script> |
| 444 | style_footer(); |
| 445 | } |
| 446 | |
| 447 | #if INTERFACE |
| 448 | /* Flag parameters to compute_uses_file() */ |
| 449 | #define USESFILE_DELETE 0x01 /* Include the check-ins where file deleted */ |
| 450 | |
| 451 | #endif |
| 452 | |
| 453 | |
| 454 | /* |
| 455 | ** Add to table zTab the record ID (rid) of every check-in that contains |
| 456 | ** the file fid. |
| 457 | */ |
| 458 | void compute_uses_file(const char *zTab, int fid, int usesFlags){ |
| 459 | Bag seen; |
| 460 | Bag pending; |
| 461 | Stmt ins; |
| 462 | Stmt q; |
| 463 | int rid; |
| 464 | |
| 465 | bag_init(&seen); |
| 466 | bag_init(&pending); |
| 467 | db_prepare(&ins, "INSERT OR IGNORE INTO \"%s\" VALUES(:rid)", zTab); |
| 468 | db_prepare(&q, "SELECT mid FROM mlink WHERE fid=%d", fid); |
| 469 | while( db_step(&q)==SQLITE_ROW ){ |
| 470 | int mid = db_column_int(&q, 0); |
| 471 | bag_insert(&pending, mid); |
| 472 | bag_insert(&seen, mid); |
| 473 | db_bind_int(&ins, ":rid", mid); |
| 474 | db_step(&ins); |
| 475 | db_reset(&ins); |
| 476 | } |
| 477 | db_finalize(&q); |
| 478 | |
| 479 | db_prepare(&q, "SELECT mid FROM mlink WHERE pid=%d", fid); |
| 480 | while( db_step(&q)==SQLITE_ROW ){ |
| 481 | int mid = db_column_int(&q, 0); |
| 482 | bag_insert(&seen, mid); |
| 483 | if( usesFlags & USESFILE_DELETE ){ |
| 484 | db_bind_int(&ins, ":rid", mid); |
| 485 | db_step(&ins); |
| 486 | db_reset(&ins); |
| 487 | } |
| 488 | } |
| 489 | db_finalize(&q); |
| 490 | db_prepare(&q, "SELECT cid FROM plink WHERE pid=:rid"); |
| 491 | |
| 492 | while( (rid = bag_first(&pending))!=0 ){ |
| 493 | bag_remove(&pending, rid); |
| 494 | db_bind_int(&q, ":rid", rid); |
| 495 | while( db_step(&q)==SQLITE_ROW ){ |
| 496 | int mid = db_column_int(&q, 0); |
| 497 | if( bag_find(&seen, mid) ) continue; |
| 498 | bag_insert(&seen, mid); |
| 499 | bag_insert(&pending, mid); |
| 500 | db_bind_int(&ins, ":rid", mid); |
| 501 | db_step(&ins); |
| 502 | db_reset(&ins); |
| 503 | } |
| 504 | db_reset(&q); |
| 505 | } |
| 506 | db_finalize(&q); |
| 507 | db_finalize(&ins); |
| 508 | bag_clear(&seen); |
| 509 | bag_clear(&pending); |
| 510 | } |
| 511 | |
| 512 |
+24
-22
| --- src/diff.c | ||
| +++ src/diff.c | ||
| @@ -1981,44 +1981,42 @@ | ||
| 1981 | 1981 | Blob toAnnotate; /* Text of the final (mid) version of the file */ |
| 1982 | 1982 | Blob step; /* Text of previous revision */ |
| 1983 | 1983 | int rid; /* Artifact ID of the file being annotated */ |
| 1984 | 1984 | char *zLabel; /* Label to apply to a line */ |
| 1985 | 1985 | Stmt q; /* Query returning all ancestor versions */ |
| 1986 | + int cnt = 0; /* Number of versions examined */ | |
| 1986 | 1987 | |
| 1987 | 1988 | /* Initialize the annotation */ |
| 1988 | 1989 | rid = db_int(0, "SELECT fid FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid); |
| 1989 | 1990 | if( rid==0 ){ |
| 1990 | 1991 | fossil_panic("file #%d is unchanged in manifest #%d", fnid, mid); |
| 1991 | 1992 | } |
| 1992 | 1993 | if( !content_get(rid, &toAnnotate) ){ |
| 1993 | 1994 | fossil_panic("unable to retrieve content of artifact #%d", rid); |
| 1994 | 1995 | } |
| 1995 | - db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)"); | |
| 1996 | 1996 | if( iLimit<=0 ) iLimit = 1000000000; |
| 1997 | - compute_direct_ancestors(mid, iLimit); | |
| 1998 | 1997 | annotation_start(p, &toAnnotate); |
| 1999 | - | |
| 1998 | + | |
| 2000 | 1999 | db_prepare(&q, |
| 2001 | - "SELECT mlink.fid," | |
| 2002 | - " (SELECT uuid FROM blob WHERE rid=mlink.%s)," | |
| 2003 | - " date(event.mtime), " | |
| 2004 | - " coalesce(event.euser,event.user) " | |
| 2005 | - " FROM ancestor, mlink, event" | |
| 2006 | - " WHERE mlink.fnid=%d" | |
| 2007 | - " AND mlink.mid=ancestor.rid" | |
| 2008 | - " AND event.objid=ancestor.rid" | |
| 2009 | - " ORDER BY ancestor.generation ASC" | |
| 2010 | - " LIMIT %d", | |
| 2011 | - (annFlags & ANN_FILE_VERS)!=0 ? "fid" : "mid", | |
| 2012 | - fnid, | |
| 2013 | - iLimit>0 ? iLimit : 10000000 | |
| 2000 | + "SELECT (SELECT uuid FROM blob WHERE rid=mlink.%s)," | |
| 2001 | + " date(event.mtime)," | |
| 2002 | + " coalesce(event.euser,event.user)," | |
| 2003 | + " mlink.pid" | |
| 2004 | + " FROM mlink, event" | |
| 2005 | + " WHERE mlink.fid=:rid" | |
| 2006 | + " AND event.objid=mlink.mid" | |
| 2007 | + " ORDER BY event.mtime", | |
| 2008 | + (annFlags & ANN_FILE_VERS)!=0 ? "fid" : "mid" | |
| 2014 | 2009 | ); |
| 2015 | - while( db_step(&q)==SQLITE_ROW ){ | |
| 2016 | - int pid = db_column_int(&q, 0); | |
| 2017 | - const char *zUuid = db_column_text(&q, 1); | |
| 2018 | - const char *zDate = db_column_text(&q, 2); | |
| 2019 | - const char *zUser = db_column_text(&q, 3); | |
| 2010 | + | |
| 2011 | + db_bind_int(&q, ":rid", rid); | |
| 2012 | + if( iLimit==0 ) iLimit = 1000000000; | |
| 2013 | + while( rid && iLimit>cnt && db_step(&q)==SQLITE_ROW ){ | |
| 2014 | + const char *zUuid = db_column_text(&q, 0); | |
| 2015 | + const char *zDate = db_column_text(&q, 1); | |
| 2016 | + const char *zUser = db_column_text(&q, 2); | |
| 2017 | + int prevId = db_column_int(&q, 3); | |
| 2020 | 2018 | if( webLabel ){ |
| 2021 | 2019 | zLabel = mprintf( |
| 2022 | 2020 | "<a href='%R/info/%s' target='infowindow'>%.10s</a> %s %13.13s", |
| 2023 | 2021 | zUuid, zUuid, zDate, zUser |
| 2024 | 2022 | ); |
| @@ -2026,13 +2024,17 @@ | ||
| 2026 | 2024 | zLabel = mprintf("%.10s %s %13.13s", zUuid, zDate, zUser); |
| 2027 | 2025 | } |
| 2028 | 2026 | p->nVers++; |
| 2029 | 2027 | p->azVers = fossil_realloc(p->azVers, p->nVers*sizeof(p->azVers[0]) ); |
| 2030 | 2028 | p->azVers[p->nVers-1] = zLabel; |
| 2031 | - content_get(pid, &step); | |
| 2029 | + content_get(rid, &step); | |
| 2032 | 2030 | annotation_step(p, &step, zLabel); |
| 2033 | 2031 | blob_reset(&step); |
| 2032 | + db_reset(&q); | |
| 2033 | + rid = prevId; | |
| 2034 | + db_bind_int(&q, ":rid", prevId); | |
| 2035 | + cnt++; | |
| 2034 | 2036 | } |
| 2035 | 2037 | db_finalize(&q); |
| 2036 | 2038 | } |
| 2037 | 2039 | |
| 2038 | 2040 | /* |
| 2039 | 2041 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -1981,44 +1981,42 @@ | |
| 1981 | Blob toAnnotate; /* Text of the final (mid) version of the file */ |
| 1982 | Blob step; /* Text of previous revision */ |
| 1983 | int rid; /* Artifact ID of the file being annotated */ |
| 1984 | char *zLabel; /* Label to apply to a line */ |
| 1985 | Stmt q; /* Query returning all ancestor versions */ |
| 1986 | |
| 1987 | /* Initialize the annotation */ |
| 1988 | rid = db_int(0, "SELECT fid FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid); |
| 1989 | if( rid==0 ){ |
| 1990 | fossil_panic("file #%d is unchanged in manifest #%d", fnid, mid); |
| 1991 | } |
| 1992 | if( !content_get(rid, &toAnnotate) ){ |
| 1993 | fossil_panic("unable to retrieve content of artifact #%d", rid); |
| 1994 | } |
| 1995 | db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)"); |
| 1996 | if( iLimit<=0 ) iLimit = 1000000000; |
| 1997 | compute_direct_ancestors(mid, iLimit); |
| 1998 | annotation_start(p, &toAnnotate); |
| 1999 | |
| 2000 | db_prepare(&q, |
| 2001 | "SELECT mlink.fid," |
| 2002 | " (SELECT uuid FROM blob WHERE rid=mlink.%s)," |
| 2003 | " date(event.mtime), " |
| 2004 | " coalesce(event.euser,event.user) " |
| 2005 | " FROM ancestor, mlink, event" |
| 2006 | " WHERE mlink.fnid=%d" |
| 2007 | " AND mlink.mid=ancestor.rid" |
| 2008 | " AND event.objid=ancestor.rid" |
| 2009 | " ORDER BY ancestor.generation ASC" |
| 2010 | " LIMIT %d", |
| 2011 | (annFlags & ANN_FILE_VERS)!=0 ? "fid" : "mid", |
| 2012 | fnid, |
| 2013 | iLimit>0 ? iLimit : 10000000 |
| 2014 | ); |
| 2015 | while( db_step(&q)==SQLITE_ROW ){ |
| 2016 | int pid = db_column_int(&q, 0); |
| 2017 | const char *zUuid = db_column_text(&q, 1); |
| 2018 | const char *zDate = db_column_text(&q, 2); |
| 2019 | const char *zUser = db_column_text(&q, 3); |
| 2020 | if( webLabel ){ |
| 2021 | zLabel = mprintf( |
| 2022 | "<a href='%R/info/%s' target='infowindow'>%.10s</a> %s %13.13s", |
| 2023 | zUuid, zUuid, zDate, zUser |
| 2024 | ); |
| @@ -2026,13 +2024,17 @@ | |
| 2026 | zLabel = mprintf("%.10s %s %13.13s", zUuid, zDate, zUser); |
| 2027 | } |
| 2028 | p->nVers++; |
| 2029 | p->azVers = fossil_realloc(p->azVers, p->nVers*sizeof(p->azVers[0]) ); |
| 2030 | p->azVers[p->nVers-1] = zLabel; |
| 2031 | content_get(pid, &step); |
| 2032 | annotation_step(p, &step, zLabel); |
| 2033 | blob_reset(&step); |
| 2034 | } |
| 2035 | db_finalize(&q); |
| 2036 | } |
| 2037 | |
| 2038 | /* |
| 2039 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -1981,44 +1981,42 @@ | |
| 1981 | Blob toAnnotate; /* Text of the final (mid) version of the file */ |
| 1982 | Blob step; /* Text of previous revision */ |
| 1983 | int rid; /* Artifact ID of the file being annotated */ |
| 1984 | char *zLabel; /* Label to apply to a line */ |
| 1985 | Stmt q; /* Query returning all ancestor versions */ |
| 1986 | int cnt = 0; /* Number of versions examined */ |
| 1987 | |
| 1988 | /* Initialize the annotation */ |
| 1989 | rid = db_int(0, "SELECT fid FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid); |
| 1990 | if( rid==0 ){ |
| 1991 | fossil_panic("file #%d is unchanged in manifest #%d", fnid, mid); |
| 1992 | } |
| 1993 | if( !content_get(rid, &toAnnotate) ){ |
| 1994 | fossil_panic("unable to retrieve content of artifact #%d", rid); |
| 1995 | } |
| 1996 | if( iLimit<=0 ) iLimit = 1000000000; |
| 1997 | annotation_start(p, &toAnnotate); |
| 1998 | |
| 1999 | db_prepare(&q, |
| 2000 | "SELECT (SELECT uuid FROM blob WHERE rid=mlink.%s)," |
| 2001 | " date(event.mtime)," |
| 2002 | " coalesce(event.euser,event.user)," |
| 2003 | " mlink.pid" |
| 2004 | " FROM mlink, event" |
| 2005 | " WHERE mlink.fid=:rid" |
| 2006 | " AND event.objid=mlink.mid" |
| 2007 | " ORDER BY event.mtime", |
| 2008 | (annFlags & ANN_FILE_VERS)!=0 ? "fid" : "mid" |
| 2009 | ); |
| 2010 | |
| 2011 | db_bind_int(&q, ":rid", rid); |
| 2012 | if( iLimit==0 ) iLimit = 1000000000; |
| 2013 | while( rid && iLimit>cnt && db_step(&q)==SQLITE_ROW ){ |
| 2014 | const char *zUuid = db_column_text(&q, 0); |
| 2015 | const char *zDate = db_column_text(&q, 1); |
| 2016 | const char *zUser = db_column_text(&q, 2); |
| 2017 | int prevId = db_column_int(&q, 3); |
| 2018 | if( webLabel ){ |
| 2019 | zLabel = mprintf( |
| 2020 | "<a href='%R/info/%s' target='infowindow'>%.10s</a> %s %13.13s", |
| 2021 | zUuid, zUuid, zDate, zUser |
| 2022 | ); |
| @@ -2026,13 +2024,17 @@ | |
| 2024 | zLabel = mprintf("%.10s %s %13.13s", zUuid, zDate, zUser); |
| 2025 | } |
| 2026 | p->nVers++; |
| 2027 | p->azVers = fossil_realloc(p->azVers, p->nVers*sizeof(p->azVers[0]) ); |
| 2028 | p->azVers[p->nVers-1] = zLabel; |
| 2029 | content_get(rid, &step); |
| 2030 | annotation_step(p, &step, zLabel); |
| 2031 | blob_reset(&step); |
| 2032 | db_reset(&q); |
| 2033 | rid = prevId; |
| 2034 | db_bind_int(&q, ":rid", prevId); |
| 2035 | cnt++; |
| 2036 | } |
| 2037 | db_finalize(&q); |
| 2038 | } |
| 2039 | |
| 2040 | /* |
| 2041 |
+35
-2
| --- src/finfo.c | ||
| +++ src/finfo.c | ||
| @@ -204,10 +204,12 @@ | ||
| 204 | 204 | db_finalize(&q); |
| 205 | 205 | blob_reset(&fname); |
| 206 | 206 | } |
| 207 | 207 | } |
| 208 | 208 | |
| 209 | +/* Values for the debug= query parameter to finfo */ | |
| 210 | +#define FINFO_DEBUG_MLINK 0x01 | |
| 209 | 211 | |
| 210 | 212 | /* |
| 211 | 213 | ** WEBPAGE: finfo |
| 212 | 214 | ** URL: /finfo?name=FILENAME |
| 213 | 215 | ** |
| @@ -227,17 +229,19 @@ | ||
| 227 | 229 | const char *zFilename; |
| 228 | 230 | char zPrevDate[20]; |
| 229 | 231 | const char *zA; |
| 230 | 232 | const char *zB; |
| 231 | 233 | int n; |
| 234 | + | |
| 232 | 235 | Blob title; |
| 233 | 236 | Blob sql; |
| 234 | 237 | HQuery url; |
| 235 | 238 | GraphContext *pGraph; |
| 236 | 239 | int brBg = P("brbg")!=0; |
| 237 | 240 | int uBg = P("ubg")!=0; |
| 238 | 241 | int firstChngOnly = atoi(PD("fco","1"))!=0; |
| 242 | + int fDebug = atoi(PD("debug","0")); | |
| 239 | 243 | |
| 240 | 244 | login_check_credentials(); |
| 241 | 245 | if( !g.perm.Read ){ login_needed(); return; } |
| 242 | 246 | style_header("File History"); |
| 243 | 247 | login_anonymous_available(); |
| @@ -260,11 +264,13 @@ | ||
| 260 | 264 | " (SELECT uuid FROM blob WHERE rid=mlink.pid)," /* Parent file uuid */ |
| 261 | 265 | " (SELECT uuid FROM blob WHERE rid=mlink.fid)," /* Current file uuid */ |
| 262 | 266 | " (SELECT uuid FROM blob WHERE rid=mlink.mid)," /* Check-in uuid */ |
| 263 | 267 | " event.bgcolor," /* Background color */ |
| 264 | 268 | " (SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0" |
| 265 | - " AND tagxref.rid=mlink.mid)", /* Tags */ | |
| 269 | + " AND tagxref.rid=mlink.mid)," /* Tags */ | |
| 270 | + " mlink.mid," /* check-in ID */ | |
| 271 | + " mlink.pfnid", /* Previous filename */ | |
| 266 | 272 | TAG_BRANCH |
| 267 | 273 | ); |
| 268 | 274 | if( firstChngOnly ){ |
| 269 | 275 | blob_appendf(&sql, ", min(event.mtime)"); |
| 270 | 276 | } |
| @@ -316,10 +322,12 @@ | ||
| 316 | 322 | const char *zPUuid = db_column_text(&q, 5); |
| 317 | 323 | const char *zUuid = db_column_text(&q, 6); |
| 318 | 324 | const char *zCkin = db_column_text(&q,7); |
| 319 | 325 | const char *zBgClr = db_column_text(&q, 8); |
| 320 | 326 | const char *zBr = db_column_text(&q, 9); |
| 327 | + int fmid = db_column_int(&q, 10); | |
| 328 | + int pfnid = db_column_int(&q, 11); | |
| 321 | 329 | int gidx; |
| 322 | 330 | char zTime[10]; |
| 323 | 331 | char zShort[20]; |
| 324 | 332 | char zShortCkin[20]; |
| 325 | 333 | if( zBr==0 ) zBr = "trunk"; |
| @@ -346,13 +354,34 @@ | ||
| 346 | 354 | @ <td class="timelineTableCell"> |
| 347 | 355 | } |
| 348 | 356 | sqlite3_snprintf(sizeof(zShort), zShort, "%.10s", zUuid); |
| 349 | 357 | sqlite3_snprintf(sizeof(zShortCkin), zShortCkin, "%.10s", zCkin); |
| 350 | 358 | if( zUuid ){ |
| 359 | + if( fpid==0 ){ | |
| 360 | + @ <b>Added</b> | |
| 361 | + }else if( pfnid ){ | |
| 362 | + char *zPrevName = db_text(0, "SELECT name FROM filename WHERE fnid=%d", | |
| 363 | + pfnid); | |
| 364 | + @ <b>Renamed</b> from | |
| 365 | + @ %z(href("%R/finfo?name=%t", zPrevName))%h(zPrevName)</a> | |
| 366 | + } | |
| 351 | 367 | @ %z(href("%R/artifact/%s",zUuid))[%S(zUuid)]</a> part of check-in |
| 352 | 368 | }else{ |
| 353 | - @ <b>Deleted</b> by check-in | |
| 369 | + char *zNewName; | |
| 370 | + zNewName = db_text(0, | |
| 371 | + "SELECT name FROM filename WHERE fnid = " | |
| 372 | + " (SELECT fnid FROM mlink" | |
| 373 | + " WHERE mid=%d" | |
| 374 | + " AND pfnid IN (SELECT fnid FROM filename WHERE name=%Q %s))", | |
| 375 | + fmid, zFilename, filename_collation()); | |
| 376 | + if( zNewName ){ | |
| 377 | + @ <b>Renamed</b> to | |
| 378 | + @ %z(href("%R/finfo?name=%t",zNewName))%h(zNewName)</a> by check-in | |
| 379 | + fossil_free(zNewName); | |
| 380 | + }else{ | |
| 381 | + @ <b>Deleted</b> by check-in | |
| 382 | + } | |
| 354 | 383 | } |
| 355 | 384 | hyperlink_to_uuid(zShortCkin); |
| 356 | 385 | @ %h(zCom) (user: |
| 357 | 386 | hyperlink_to_user(zUser, zDate, ""); |
| 358 | 387 | @ branch: %h(zBr)) |
| @@ -361,10 +390,14 @@ | ||
| 361 | 390 | if( fpid ){ |
| 362 | 391 | @ %z(href("%R/fdiff?v1=%S&v2=%S",zPUuid,zUuid))[diff]</a> |
| 363 | 392 | } |
| 364 | 393 | @ %z(href("%R/annotate?checkin=%S&filename=%h",zCkin,z)) |
| 365 | 394 | @ [annotate]</a> |
| 395 | + @ %z(href("%R/timeline?n=200&uf=%S",zUuid))[checkins using]</a> | |
| 396 | + } | |
| 397 | + if( fDebug & FINFO_DEBUG_MLINK ){ | |
| 398 | + @ fid=%d(frid), pid=%d(fpid), mid=%d(fmid) | |
| 366 | 399 | } |
| 367 | 400 | @ </td></tr> |
| 368 | 401 | } |
| 369 | 402 | db_finalize(&q); |
| 370 | 403 | if( pGraph ){ |
| 371 | 404 |
| --- src/finfo.c | |
| +++ src/finfo.c | |
| @@ -204,10 +204,12 @@ | |
| 204 | db_finalize(&q); |
| 205 | blob_reset(&fname); |
| 206 | } |
| 207 | } |
| 208 | |
| 209 | |
| 210 | /* |
| 211 | ** WEBPAGE: finfo |
| 212 | ** URL: /finfo?name=FILENAME |
| 213 | ** |
| @@ -227,17 +229,19 @@ | |
| 227 | const char *zFilename; |
| 228 | char zPrevDate[20]; |
| 229 | const char *zA; |
| 230 | const char *zB; |
| 231 | int n; |
| 232 | Blob title; |
| 233 | Blob sql; |
| 234 | HQuery url; |
| 235 | GraphContext *pGraph; |
| 236 | int brBg = P("brbg")!=0; |
| 237 | int uBg = P("ubg")!=0; |
| 238 | int firstChngOnly = atoi(PD("fco","1"))!=0; |
| 239 | |
| 240 | login_check_credentials(); |
| 241 | if( !g.perm.Read ){ login_needed(); return; } |
| 242 | style_header("File History"); |
| 243 | login_anonymous_available(); |
| @@ -260,11 +264,13 @@ | |
| 260 | " (SELECT uuid FROM blob WHERE rid=mlink.pid)," /* Parent file uuid */ |
| 261 | " (SELECT uuid FROM blob WHERE rid=mlink.fid)," /* Current file uuid */ |
| 262 | " (SELECT uuid FROM blob WHERE rid=mlink.mid)," /* Check-in uuid */ |
| 263 | " event.bgcolor," /* Background color */ |
| 264 | " (SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0" |
| 265 | " AND tagxref.rid=mlink.mid)", /* Tags */ |
| 266 | TAG_BRANCH |
| 267 | ); |
| 268 | if( firstChngOnly ){ |
| 269 | blob_appendf(&sql, ", min(event.mtime)"); |
| 270 | } |
| @@ -316,10 +322,12 @@ | |
| 316 | const char *zPUuid = db_column_text(&q, 5); |
| 317 | const char *zUuid = db_column_text(&q, 6); |
| 318 | const char *zCkin = db_column_text(&q,7); |
| 319 | const char *zBgClr = db_column_text(&q, 8); |
| 320 | const char *zBr = db_column_text(&q, 9); |
| 321 | int gidx; |
| 322 | char zTime[10]; |
| 323 | char zShort[20]; |
| 324 | char zShortCkin[20]; |
| 325 | if( zBr==0 ) zBr = "trunk"; |
| @@ -346,13 +354,34 @@ | |
| 346 | @ <td class="timelineTableCell"> |
| 347 | } |
| 348 | sqlite3_snprintf(sizeof(zShort), zShort, "%.10s", zUuid); |
| 349 | sqlite3_snprintf(sizeof(zShortCkin), zShortCkin, "%.10s", zCkin); |
| 350 | if( zUuid ){ |
| 351 | @ %z(href("%R/artifact/%s",zUuid))[%S(zUuid)]</a> part of check-in |
| 352 | }else{ |
| 353 | @ <b>Deleted</b> by check-in |
| 354 | } |
| 355 | hyperlink_to_uuid(zShortCkin); |
| 356 | @ %h(zCom) (user: |
| 357 | hyperlink_to_user(zUser, zDate, ""); |
| 358 | @ branch: %h(zBr)) |
| @@ -361,10 +390,14 @@ | |
| 361 | if( fpid ){ |
| 362 | @ %z(href("%R/fdiff?v1=%S&v2=%S",zPUuid,zUuid))[diff]</a> |
| 363 | } |
| 364 | @ %z(href("%R/annotate?checkin=%S&filename=%h",zCkin,z)) |
| 365 | @ [annotate]</a> |
| 366 | } |
| 367 | @ </td></tr> |
| 368 | } |
| 369 | db_finalize(&q); |
| 370 | if( pGraph ){ |
| 371 |
| --- src/finfo.c | |
| +++ src/finfo.c | |
| @@ -204,10 +204,12 @@ | |
| 204 | db_finalize(&q); |
| 205 | blob_reset(&fname); |
| 206 | } |
| 207 | } |
| 208 | |
| 209 | /* Values for the debug= query parameter to finfo */ |
| 210 | #define FINFO_DEBUG_MLINK 0x01 |
| 211 | |
| 212 | /* |
| 213 | ** WEBPAGE: finfo |
| 214 | ** URL: /finfo?name=FILENAME |
| 215 | ** |
| @@ -227,17 +229,19 @@ | |
| 229 | const char *zFilename; |
| 230 | char zPrevDate[20]; |
| 231 | const char *zA; |
| 232 | const char *zB; |
| 233 | int n; |
| 234 | |
| 235 | Blob title; |
| 236 | Blob sql; |
| 237 | HQuery url; |
| 238 | GraphContext *pGraph; |
| 239 | int brBg = P("brbg")!=0; |
| 240 | int uBg = P("ubg")!=0; |
| 241 | int firstChngOnly = atoi(PD("fco","1"))!=0; |
| 242 | int fDebug = atoi(PD("debug","0")); |
| 243 | |
| 244 | login_check_credentials(); |
| 245 | if( !g.perm.Read ){ login_needed(); return; } |
| 246 | style_header("File History"); |
| 247 | login_anonymous_available(); |
| @@ -260,11 +264,13 @@ | |
| 264 | " (SELECT uuid FROM blob WHERE rid=mlink.pid)," /* Parent file uuid */ |
| 265 | " (SELECT uuid FROM blob WHERE rid=mlink.fid)," /* Current file uuid */ |
| 266 | " (SELECT uuid FROM blob WHERE rid=mlink.mid)," /* Check-in uuid */ |
| 267 | " event.bgcolor," /* Background color */ |
| 268 | " (SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0" |
| 269 | " AND tagxref.rid=mlink.mid)," /* Tags */ |
| 270 | " mlink.mid," /* check-in ID */ |
| 271 | " mlink.pfnid", /* Previous filename */ |
| 272 | TAG_BRANCH |
| 273 | ); |
| 274 | if( firstChngOnly ){ |
| 275 | blob_appendf(&sql, ", min(event.mtime)"); |
| 276 | } |
| @@ -316,10 +322,12 @@ | |
| 322 | const char *zPUuid = db_column_text(&q, 5); |
| 323 | const char *zUuid = db_column_text(&q, 6); |
| 324 | const char *zCkin = db_column_text(&q,7); |
| 325 | const char *zBgClr = db_column_text(&q, 8); |
| 326 | const char *zBr = db_column_text(&q, 9); |
| 327 | int fmid = db_column_int(&q, 10); |
| 328 | int pfnid = db_column_int(&q, 11); |
| 329 | int gidx; |
| 330 | char zTime[10]; |
| 331 | char zShort[20]; |
| 332 | char zShortCkin[20]; |
| 333 | if( zBr==0 ) zBr = "trunk"; |
| @@ -346,13 +354,34 @@ | |
| 354 | @ <td class="timelineTableCell"> |
| 355 | } |
| 356 | sqlite3_snprintf(sizeof(zShort), zShort, "%.10s", zUuid); |
| 357 | sqlite3_snprintf(sizeof(zShortCkin), zShortCkin, "%.10s", zCkin); |
| 358 | if( zUuid ){ |
| 359 | if( fpid==0 ){ |
| 360 | @ <b>Added</b> |
| 361 | }else if( pfnid ){ |
| 362 | char *zPrevName = db_text(0, "SELECT name FROM filename WHERE fnid=%d", |
| 363 | pfnid); |
| 364 | @ <b>Renamed</b> from |
| 365 | @ %z(href("%R/finfo?name=%t", zPrevName))%h(zPrevName)</a> |
| 366 | } |
| 367 | @ %z(href("%R/artifact/%s",zUuid))[%S(zUuid)]</a> part of check-in |
| 368 | }else{ |
| 369 | char *zNewName; |
| 370 | zNewName = db_text(0, |
| 371 | "SELECT name FROM filename WHERE fnid = " |
| 372 | " (SELECT fnid FROM mlink" |
| 373 | " WHERE mid=%d" |
| 374 | " AND pfnid IN (SELECT fnid FROM filename WHERE name=%Q %s))", |
| 375 | fmid, zFilename, filename_collation()); |
| 376 | if( zNewName ){ |
| 377 | @ <b>Renamed</b> to |
| 378 | @ %z(href("%R/finfo?name=%t",zNewName))%h(zNewName)</a> by check-in |
| 379 | fossil_free(zNewName); |
| 380 | }else{ |
| 381 | @ <b>Deleted</b> by check-in |
| 382 | } |
| 383 | } |
| 384 | hyperlink_to_uuid(zShortCkin); |
| 385 | @ %h(zCom) (user: |
| 386 | hyperlink_to_user(zUser, zDate, ""); |
| 387 | @ branch: %h(zBr)) |
| @@ -361,10 +390,14 @@ | |
| 390 | if( fpid ){ |
| 391 | @ %z(href("%R/fdiff?v1=%S&v2=%S",zPUuid,zUuid))[diff]</a> |
| 392 | } |
| 393 | @ %z(href("%R/annotate?checkin=%S&filename=%h",zCkin,z)) |
| 394 | @ [annotate]</a> |
| 395 | @ %z(href("%R/timeline?n=200&uf=%S",zUuid))[checkins using]</a> |
| 396 | } |
| 397 | if( fDebug & FINFO_DEBUG_MLINK ){ |
| 398 | @ fid=%d(frid), pid=%d(fpid), mid=%d(fmid) |
| 399 | } |
| 400 | @ </td></tr> |
| 401 | } |
| 402 | db_finalize(&q); |
| 403 | if( pGraph ){ |
| 404 |
+75
-21
| --- src/http_transport.c | ||
| +++ src/http_transport.c | ||
| @@ -97,10 +97,84 @@ | ||
| 97 | 97 | #ifdef __MINGW32__ |
| 98 | 98 | static char zDefaultSshCmd[] = "ssh -T"; |
| 99 | 99 | #else |
| 100 | 100 | static char zDefaultSshCmd[] = "ssh -e none -T"; |
| 101 | 101 | #endif |
| 102 | + | |
| 103 | +/* | |
| 104 | +** Generate a random SSH link problem keyword | |
| 105 | +*/ | |
| 106 | +static int random_probe(char *zProbe, int nProbe){ | |
| 107 | + unsigned r[4]; | |
| 108 | + sqlite3_randomness(sizeof(r), r); | |
| 109 | + sqlite3_snprintf(nProbe, zProbe, "probe-%08x%08x%08x%08x", | |
| 110 | + r[0], r[1], r[2], r[3]); | |
| 111 | + return (int)strlen(zProbe); | |
| 112 | +} | |
| 113 | + | |
| 114 | +/* | |
| 115 | +** Bring up an SSH link. This involves sending some "echo" commands and | |
| 116 | +** get back appropriate responses. The point is to move past the MOTD and | |
| 117 | +** verify that the link is working. | |
| 118 | +*/ | |
| 119 | +static void transport_ssh_startup(void){ | |
| 120 | + char *zIn; /* An input line received back from remote */ | |
| 121 | + int nWait; /* Number of times waiting for the MOTD */ | |
| 122 | + char zProbe[40]; /* Text of the random probe */ | |
| 123 | + int nProbe; /* Size of probe message */ | |
| 124 | + int nIn; /* Size of input */ | |
| 125 | + static const int nBuf = 10000; /* Size of input buffer */ | |
| 126 | + | |
| 127 | + zIn = fossil_malloc(nBuf); | |
| 128 | + nProbe = random_probe(zProbe, sizeof(zProbe)); | |
| 129 | + fprintf(sshOut, "echo %s\n", zProbe); | |
| 130 | + fflush(sshOut); | |
| 131 | + if( g.fSshTrace ){ | |
| 132 | + printf("Sent: [echo %s]\n", zProbe); | |
| 133 | + fflush(stdout); | |
| 134 | + } | |
| 135 | + memset(zIn, '*', nProbe); | |
| 136 | + for(nWait=1; nWait<=10; nWait++){ | |
| 137 | + sshin_read(zIn+nProbe, nBuf-nProbe); | |
| 138 | + if( g.fSshTrace ){ | |
| 139 | + printf("Got back-----------------------------------------------\n" | |
| 140 | + "%s\n" | |
| 141 | + "-------------------------------------------------------\n", | |
| 142 | + zIn+nProbe); | |
| 143 | + } | |
| 144 | + if( strstr(zIn, zProbe) ) break; | |
| 145 | + sqlite3_sleep(100*nWait); | |
| 146 | + nIn = (int)strlen(zIn); | |
| 147 | + memcpy(zIn, zIn+(nIn-nProbe), nProbe); | |
| 148 | + if( g.fSshTrace ){ | |
| 149 | + printf("Fetching more text. Looking for [%s]...\n", zProbe); | |
| 150 | + fflush(stdout); | |
| 151 | + } | |
| 152 | + } | |
| 153 | + nProbe = random_probe(zProbe, sizeof(zProbe)); | |
| 154 | + fprintf(sshOut, "echo %s\n", zProbe); | |
| 155 | + fflush(sshOut); | |
| 156 | + if( g.fSshTrace ){ | |
| 157 | + printf("Sent: [echo %s]\n", zProbe); | |
| 158 | + fflush(stdout); | |
| 159 | + } | |
| 160 | + sshin_read(zIn, nBuf); | |
| 161 | + if( zIn[0]==0 ){ | |
| 162 | + sqlite3_sleep(250); | |
| 163 | + sshin_read(zIn, nBuf); | |
| 164 | + } | |
| 165 | + if( g.fSshTrace ){ | |
| 166 | + printf("Got back-----------------------------------------------\n" | |
| 167 | + "%s\n" | |
| 168 | + "-------------------------------------------------------\n", zIn); | |
| 169 | + } | |
| 170 | + if( memcmp(zIn, zProbe, nProbe)!=0 ){ | |
| 171 | + pclose2(sshIn, sshOut, sshPid); | |
| 172 | + fossil_fatal("ssh connection failed: [%s]", zIn); | |
| 173 | + } | |
| 174 | + fossil_free(zIn); | |
| 175 | +} | |
| 102 | 176 | |
| 103 | 177 | /* |
| 104 | 178 | ** Global initialization of the transport layer |
| 105 | 179 | */ |
| 106 | 180 | void transport_global_startup(void){ |
| @@ -109,13 +183,10 @@ | ||
| 109 | 183 | ** and run an SSH command to talk to the remote machine. |
| 110 | 184 | */ |
| 111 | 185 | const char *zSsh; /* The base SSH command */ |
| 112 | 186 | Blob zCmd; /* The SSH command */ |
| 113 | 187 | char *zHost; /* The host name to contact */ |
| 114 | - char *zIn; /* An input line received back from remote */ | |
| 115 | - unsigned iRandom; | |
| 116 | - char zProbe[30]; | |
| 117 | 188 | |
| 118 | 189 | zSsh = db_get("ssh-command", zDefaultSshCmd); |
| 119 | 190 | blob_init(&zCmd, zSsh, -1); |
| 120 | 191 | if( g.urlPort!=g.urlDfltPort ){ |
| 121 | 192 | #ifdef __MINGW32__ |
| @@ -156,28 +227,11 @@ | ||
| 156 | 227 | popen2(blob_str(&zCmd), &sshIn, &sshOut, &sshPid); |
| 157 | 228 | if( sshPid==0 ){ |
| 158 | 229 | fossil_fatal("cannot start ssh tunnel using [%b]", &zCmd); |
| 159 | 230 | } |
| 160 | 231 | blob_reset(&zCmd); |
| 161 | - | |
| 162 | - /* Send a couple of "echo" command to the other side to make sure that the | |
| 163 | - ** connection is up and working. | |
| 164 | - */ | |
| 165 | - fprintf(sshOut, "echo test1\n"); | |
| 166 | - fflush(sshOut); | |
| 167 | - zIn = fossil_malloc(50000); | |
| 168 | - sshin_read(zIn, 50000); | |
| 169 | - sqlite3_randomness(sizeof(iRandom), &iRandom); | |
| 170 | - sqlite3_snprintf(sizeof(zProbe), zProbe, "probe-%08x", iRandom); | |
| 171 | - fprintf(sshOut, "echo %s\n", zProbe); | |
| 172 | - fflush(sshOut); | |
| 173 | - sshin_read(zIn, 500); | |
| 174 | - if( memcmp(zIn, zProbe, 14)!=0 ){ | |
| 175 | - pclose2(sshIn, sshOut, sshPid); | |
| 176 | - fossil_fatal("ssh connection failed: [%s]", zIn); | |
| 177 | - } | |
| 178 | - fossil_free(zIn); | |
| 232 | + transport_ssh_startup(); | |
| 179 | 233 | } |
| 180 | 234 | } |
| 181 | 235 | |
| 182 | 236 | /* |
| 183 | 237 | ** Open a connection to the server. The server is defined by the following |
| 184 | 238 |
| --- src/http_transport.c | |
| +++ src/http_transport.c | |
| @@ -97,10 +97,84 @@ | |
| 97 | #ifdef __MINGW32__ |
| 98 | static char zDefaultSshCmd[] = "ssh -T"; |
| 99 | #else |
| 100 | static char zDefaultSshCmd[] = "ssh -e none -T"; |
| 101 | #endif |
| 102 | |
| 103 | /* |
| 104 | ** Global initialization of the transport layer |
| 105 | */ |
| 106 | void transport_global_startup(void){ |
| @@ -109,13 +183,10 @@ | |
| 109 | ** and run an SSH command to talk to the remote machine. |
| 110 | */ |
| 111 | const char *zSsh; /* The base SSH command */ |
| 112 | Blob zCmd; /* The SSH command */ |
| 113 | char *zHost; /* The host name to contact */ |
| 114 | char *zIn; /* An input line received back from remote */ |
| 115 | unsigned iRandom; |
| 116 | char zProbe[30]; |
| 117 | |
| 118 | zSsh = db_get("ssh-command", zDefaultSshCmd); |
| 119 | blob_init(&zCmd, zSsh, -1); |
| 120 | if( g.urlPort!=g.urlDfltPort ){ |
| 121 | #ifdef __MINGW32__ |
| @@ -156,28 +227,11 @@ | |
| 156 | popen2(blob_str(&zCmd), &sshIn, &sshOut, &sshPid); |
| 157 | if( sshPid==0 ){ |
| 158 | fossil_fatal("cannot start ssh tunnel using [%b]", &zCmd); |
| 159 | } |
| 160 | blob_reset(&zCmd); |
| 161 | |
| 162 | /* Send a couple of "echo" command to the other side to make sure that the |
| 163 | ** connection is up and working. |
| 164 | */ |
| 165 | fprintf(sshOut, "echo test1\n"); |
| 166 | fflush(sshOut); |
| 167 | zIn = fossil_malloc(50000); |
| 168 | sshin_read(zIn, 50000); |
| 169 | sqlite3_randomness(sizeof(iRandom), &iRandom); |
| 170 | sqlite3_snprintf(sizeof(zProbe), zProbe, "probe-%08x", iRandom); |
| 171 | fprintf(sshOut, "echo %s\n", zProbe); |
| 172 | fflush(sshOut); |
| 173 | sshin_read(zIn, 500); |
| 174 | if( memcmp(zIn, zProbe, 14)!=0 ){ |
| 175 | pclose2(sshIn, sshOut, sshPid); |
| 176 | fossil_fatal("ssh connection failed: [%s]", zIn); |
| 177 | } |
| 178 | fossil_free(zIn); |
| 179 | } |
| 180 | } |
| 181 | |
| 182 | /* |
| 183 | ** Open a connection to the server. The server is defined by the following |
| 184 |
| --- src/http_transport.c | |
| +++ src/http_transport.c | |
| @@ -97,10 +97,84 @@ | |
| 97 | #ifdef __MINGW32__ |
| 98 | static char zDefaultSshCmd[] = "ssh -T"; |
| 99 | #else |
| 100 | static char zDefaultSshCmd[] = "ssh -e none -T"; |
| 101 | #endif |
| 102 | |
| 103 | /* |
| 104 | ** Generate a random SSH link problem keyword |
| 105 | */ |
| 106 | static int random_probe(char *zProbe, int nProbe){ |
| 107 | unsigned r[4]; |
| 108 | sqlite3_randomness(sizeof(r), r); |
| 109 | sqlite3_snprintf(nProbe, zProbe, "probe-%08x%08x%08x%08x", |
| 110 | r[0], r[1], r[2], r[3]); |
| 111 | return (int)strlen(zProbe); |
| 112 | } |
| 113 | |
| 114 | /* |
| 115 | ** Bring up an SSH link. This involves sending some "echo" commands and |
| 116 | ** get back appropriate responses. The point is to move past the MOTD and |
| 117 | ** verify that the link is working. |
| 118 | */ |
| 119 | static void transport_ssh_startup(void){ |
| 120 | char *zIn; /* An input line received back from remote */ |
| 121 | int nWait; /* Number of times waiting for the MOTD */ |
| 122 | char zProbe[40]; /* Text of the random probe */ |
| 123 | int nProbe; /* Size of probe message */ |
| 124 | int nIn; /* Size of input */ |
| 125 | static const int nBuf = 10000; /* Size of input buffer */ |
| 126 | |
| 127 | zIn = fossil_malloc(nBuf); |
| 128 | nProbe = random_probe(zProbe, sizeof(zProbe)); |
| 129 | fprintf(sshOut, "echo %s\n", zProbe); |
| 130 | fflush(sshOut); |
| 131 | if( g.fSshTrace ){ |
| 132 | printf("Sent: [echo %s]\n", zProbe); |
| 133 | fflush(stdout); |
| 134 | } |
| 135 | memset(zIn, '*', nProbe); |
| 136 | for(nWait=1; nWait<=10; nWait++){ |
| 137 | sshin_read(zIn+nProbe, nBuf-nProbe); |
| 138 | if( g.fSshTrace ){ |
| 139 | printf("Got back-----------------------------------------------\n" |
| 140 | "%s\n" |
| 141 | "-------------------------------------------------------\n", |
| 142 | zIn+nProbe); |
| 143 | } |
| 144 | if( strstr(zIn, zProbe) ) break; |
| 145 | sqlite3_sleep(100*nWait); |
| 146 | nIn = (int)strlen(zIn); |
| 147 | memcpy(zIn, zIn+(nIn-nProbe), nProbe); |
| 148 | if( g.fSshTrace ){ |
| 149 | printf("Fetching more text. Looking for [%s]...\n", zProbe); |
| 150 | fflush(stdout); |
| 151 | } |
| 152 | } |
| 153 | nProbe = random_probe(zProbe, sizeof(zProbe)); |
| 154 | fprintf(sshOut, "echo %s\n", zProbe); |
| 155 | fflush(sshOut); |
| 156 | if( g.fSshTrace ){ |
| 157 | printf("Sent: [echo %s]\n", zProbe); |
| 158 | fflush(stdout); |
| 159 | } |
| 160 | sshin_read(zIn, nBuf); |
| 161 | if( zIn[0]==0 ){ |
| 162 | sqlite3_sleep(250); |
| 163 | sshin_read(zIn, nBuf); |
| 164 | } |
| 165 | if( g.fSshTrace ){ |
| 166 | printf("Got back-----------------------------------------------\n" |
| 167 | "%s\n" |
| 168 | "-------------------------------------------------------\n", zIn); |
| 169 | } |
| 170 | if( memcmp(zIn, zProbe, nProbe)!=0 ){ |
| 171 | pclose2(sshIn, sshOut, sshPid); |
| 172 | fossil_fatal("ssh connection failed: [%s]", zIn); |
| 173 | } |
| 174 | fossil_free(zIn); |
| 175 | } |
| 176 | |
| 177 | /* |
| 178 | ** Global initialization of the transport layer |
| 179 | */ |
| 180 | void transport_global_startup(void){ |
| @@ -109,13 +183,10 @@ | |
| 183 | ** and run an SSH command to talk to the remote machine. |
| 184 | */ |
| 185 | const char *zSsh; /* The base SSH command */ |
| 186 | Blob zCmd; /* The SSH command */ |
| 187 | char *zHost; /* The host name to contact */ |
| 188 | |
| 189 | zSsh = db_get("ssh-command", zDefaultSshCmd); |
| 190 | blob_init(&zCmd, zSsh, -1); |
| 191 | if( g.urlPort!=g.urlDfltPort ){ |
| 192 | #ifdef __MINGW32__ |
| @@ -156,28 +227,11 @@ | |
| 227 | popen2(blob_str(&zCmd), &sshIn, &sshOut, &sshPid); |
| 228 | if( sshPid==0 ){ |
| 229 | fossil_fatal("cannot start ssh tunnel using [%b]", &zCmd); |
| 230 | } |
| 231 | blob_reset(&zCmd); |
| 232 | transport_ssh_startup(); |
| 233 | } |
| 234 | } |
| 235 | |
| 236 | /* |
| 237 | ** Open a connection to the server. The server is defined by the following |
| 238 |
+5
-1
| --- src/info.c | ||
| +++ src/info.c | ||
| @@ -1597,11 +1597,15 @@ | ||
| 1597 | 1597 | @ <h2>Artifact %s(zUuid):</h2> |
| 1598 | 1598 | } |
| 1599 | 1599 | blob_zero(&downloadName); |
| 1600 | 1600 | objType = object_description(rid, 0, &downloadName); |
| 1601 | 1601 | style_submenu_element("Download", "Download", |
| 1602 | - "%s/raw/%T?name=%s", g.zTop, blob_str(&downloadName), zUuid); | |
| 1602 | + "%R/raw/%T?name=%s", blob_str(&downloadName), zUuid); | |
| 1603 | + if( db_exists("SELECT 1 FROM mlink WHERE fid=%d", rid) ){ | |
| 1604 | + style_submenu_element("Checkins Using", "Checkins Using", | |
| 1605 | + "%R/timeline?uf=%s&n=200",zUuid); | |
| 1606 | + } | |
| 1603 | 1607 | asText = P("txt")!=0; |
| 1604 | 1608 | zMime = mimetype_from_name(blob_str(&downloadName)); |
| 1605 | 1609 | if( zMime ){ |
| 1606 | 1610 | if( fossil_strcmp(zMime, "text/html")==0 ){ |
| 1607 | 1611 | if( asText ){ |
| 1608 | 1612 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -1597,11 +1597,15 @@ | |
| 1597 | @ <h2>Artifact %s(zUuid):</h2> |
| 1598 | } |
| 1599 | blob_zero(&downloadName); |
| 1600 | objType = object_description(rid, 0, &downloadName); |
| 1601 | style_submenu_element("Download", "Download", |
| 1602 | "%s/raw/%T?name=%s", g.zTop, blob_str(&downloadName), zUuid); |
| 1603 | asText = P("txt")!=0; |
| 1604 | zMime = mimetype_from_name(blob_str(&downloadName)); |
| 1605 | if( zMime ){ |
| 1606 | if( fossil_strcmp(zMime, "text/html")==0 ){ |
| 1607 | if( asText ){ |
| 1608 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -1597,11 +1597,15 @@ | |
| 1597 | @ <h2>Artifact %s(zUuid):</h2> |
| 1598 | } |
| 1599 | blob_zero(&downloadName); |
| 1600 | objType = object_description(rid, 0, &downloadName); |
| 1601 | style_submenu_element("Download", "Download", |
| 1602 | "%R/raw/%T?name=%s", blob_str(&downloadName), zUuid); |
| 1603 | if( db_exists("SELECT 1 FROM mlink WHERE fid=%d", rid) ){ |
| 1604 | style_submenu_element("Checkins Using", "Checkins Using", |
| 1605 | "%R/timeline?uf=%s&n=200",zUuid); |
| 1606 | } |
| 1607 | asText = P("txt")!=0; |
| 1608 | zMime = mimetype_from_name(blob_str(&downloadName)); |
| 1609 | if( zMime ){ |
| 1610 | if( fossil_strcmp(zMime, "text/html")==0 ){ |
| 1611 | if( asText ){ |
| 1612 |
+27
-9
| --- src/main.c | ||
| +++ src/main.c | ||
| @@ -129,10 +129,11 @@ | ||
| 129 | 129 | int fSqlStats; /* True if --sqltrace or --sqlstats are present */ |
| 130 | 130 | int fSqlPrint; /* True if -sqlprint flag is present */ |
| 131 | 131 | int fQuiet; /* True if -quiet flag is present */ |
| 132 | 132 | int fHttpTrace; /* Trace outbound HTTP requests */ |
| 133 | 133 | int fSystemTrace; /* Trace calls to fossil_system(), --systemtrace */ |
| 134 | + int fSshTrace; /* Trace the SSH setup traffic */ | |
| 134 | 135 | int fNoSync; /* Do not do an autosync even. --nosync */ |
| 135 | 136 | char *zPath; /* Name of webpage being served */ |
| 136 | 137 | char *zExtra; /* Extra path information past the webpage name */ |
| 137 | 138 | char *zBaseURL; /* Full text of the URL being served */ |
| 138 | 139 | char *zTop; /* Parent directory of zPath */ |
| @@ -611,10 +612,11 @@ | ||
| 611 | 612 | g.isHTTP = 0; |
| 612 | 613 | g.fQuiet = find_option("quiet", 0, 0)!=0; |
| 613 | 614 | g.fSqlTrace = find_option("sqltrace", 0, 0)!=0; |
| 614 | 615 | g.fSqlStats = find_option("sqlstats", 0, 0)!=0; |
| 615 | 616 | g.fSystemTrace = find_option("systemtrace", 0, 0)!=0; |
| 617 | + g.fSshTrace = find_option("sshtrace", 0, 0)!=0; | |
| 616 | 618 | if( g.fSqlTrace ) g.fSqlStats = 1; |
| 617 | 619 | g.fSqlPrint = find_option("sqlprint", 0, 0)!=0; |
| 618 | 620 | g.fHttpTrace = find_option("httptrace", 0, 0)!=0; |
| 619 | 621 | g.zLogin = find_option("user", "U", 1); |
| 620 | 622 | g.zSSLIdentity = find_option("ssl-identity", 0, 1); |
| @@ -1379,27 +1381,39 @@ | ||
| 1379 | 1381 | while( 1 ){ |
| 1380 | 1382 | while( zPathInfo[i] && zPathInfo[i]!='/' ){ i++; } |
| 1381 | 1383 | zRepo = zToFree = mprintf("%s%.*s.fossil",g.zRepositoryName,i,zPathInfo); |
| 1382 | 1384 | |
| 1383 | 1385 | /* To avoid mischief, make sure the repository basename contains no |
| 1384 | - ** characters other than alphanumerics, "-", "/", and "_". | |
| 1386 | + ** characters other than alphanumerics, "-", "/", "_", and "." beside | |
| 1387 | + ** "/" or ".". | |
| 1385 | 1388 | */ |
| 1386 | 1389 | for(j=strlen(g.zRepositoryName)+1, k=0; zRepo[j] && k<i-1; j++, k++){ |
| 1387 | - if( !fossil_isalnum(zRepo[j]) && zRepo[j]!='-' && zRepo[j]!='/' ){ | |
| 1390 | + char c = zRepo[j]; | |
| 1391 | + if( !fossil_isalnum(c) && c!='-' && c!='/' | |
| 1392 | + && (c!='.' || zRepo[j+1]=='/' || zRepo[j-1]=='/' || zRepo[j+1]=='.') | |
| 1393 | + ){ | |
| 1388 | 1394 | zRepo[j] = '_'; |
| 1389 | 1395 | } |
| 1390 | 1396 | } |
| 1391 | 1397 | if( zRepo[0]=='/' && zRepo[1]=='/' ){ zRepo++; j--; } |
| 1392 | 1398 | |
| 1393 | 1399 | szFile = file_size(zRepo); |
| 1394 | - if( zPathInfo[i]=='/' && szFile<0 ){ | |
| 1400 | + if( szFile<0 ){ | |
| 1395 | 1401 | assert( fossil_strcmp(&zRepo[j], ".fossil")==0 ); |
| 1396 | 1402 | zRepo[j] = 0; |
| 1397 | - if( file_isdir(zRepo)==1 ){ | |
| 1403 | + if( zPathInfo[i]=='/' && file_isdir(zRepo)==1 ){ | |
| 1398 | 1404 | fossil_free(zToFree); |
| 1399 | 1405 | i++; |
| 1400 | 1406 | continue; |
| 1407 | + } | |
| 1408 | + if( file_isfile(zRepo) ){ | |
| 1409 | + Blob content; | |
| 1410 | + blob_read_from_file(&content, zRepo); | |
| 1411 | + cgi_set_content_type(mimetype_from_name(zRepo)); | |
| 1412 | + cgi_set_content(&content); | |
| 1413 | + cgi_reply(); | |
| 1414 | + return; | |
| 1401 | 1415 | } |
| 1402 | 1416 | zRepo[j] = '.'; |
| 1403 | 1417 | } |
| 1404 | 1418 | |
| 1405 | 1419 | if( szFile<1024 ){ |
| @@ -1740,13 +1754,17 @@ | ||
| 1740 | 1754 | ** is disallowed. |
| 1741 | 1755 | */ |
| 1742 | 1756 | static void find_server_repository(int disallowDir){ |
| 1743 | 1757 | if( g.argc<3 ){ |
| 1744 | 1758 | db_must_be_within_tree(); |
| 1745 | - }else if( !disallowDir && file_isdir(g.argv[2])==1 ){ | |
| 1746 | - g.zRepositoryName = mprintf("%s", g.argv[2]); | |
| 1747 | - file_simplify_name(g.zRepositoryName, -1, 0); | |
| 1759 | + }else if( file_isdir(g.argv[2])==1 ){ | |
| 1760 | + if( disallowDir ){ | |
| 1761 | + fossil_fatal("\"%s\" is a directory, not a repository file", g.argv[2]); | |
| 1762 | + }else{ | |
| 1763 | + g.zRepositoryName = mprintf("%s", g.argv[2]); | |
| 1764 | + file_simplify_name(g.zRepositoryName, -1, 0); | |
| 1765 | + } | |
| 1748 | 1766 | }else{ |
| 1749 | 1767 | db_open_repository(g.argv[2]); |
| 1750 | 1768 | } |
| 1751 | 1769 | } |
| 1752 | 1770 | |
| @@ -1934,11 +1952,11 @@ | ||
| 1934 | 1952 | isUiCmd = g.argv[1][0]=='u'; |
| 1935 | 1953 | if( isUiCmd ){ |
| 1936 | 1954 | flags |= HTTP_SERVER_LOCALHOST; |
| 1937 | 1955 | g.useLocalauth = 1; |
| 1938 | 1956 | } |
| 1939 | - find_server_repository(isUiCmd); | |
| 1957 | + find_server_repository(isUiCmd && zNotFound==0); | |
| 1940 | 1958 | if( zPort ){ |
| 1941 | 1959 | iPort = mxPort = atoi(zPort); |
| 1942 | 1960 | }else{ |
| 1943 | 1961 | iPort = db_get_int("http-port", 8080); |
| 1944 | 1962 | mxPort = iPort+100; |
| @@ -1973,11 +1991,11 @@ | ||
| 1973 | 1991 | g.httpOut = stdout; |
| 1974 | 1992 | if( g.fHttpTrace || g.fSqlTrace ){ |
| 1975 | 1993 | fprintf(stderr, "====== SERVER pid %d =======\n", getpid()); |
| 1976 | 1994 | } |
| 1977 | 1995 | g.cgiOutput = 1; |
| 1978 | - find_server_repository(isUiCmd); | |
| 1996 | + find_server_repository(isUiCmd && zNotFound==0); | |
| 1979 | 1997 | g.zRepositoryName = enter_chroot_jail(g.zRepositoryName); |
| 1980 | 1998 | cgi_handle_http_request(0); |
| 1981 | 1999 | process_one_web_page(zNotFound); |
| 1982 | 2000 | #else |
| 1983 | 2001 | /* Win32 implementation */ |
| 1984 | 2002 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -129,10 +129,11 @@ | |
| 129 | int fSqlStats; /* True if --sqltrace or --sqlstats are present */ |
| 130 | int fSqlPrint; /* True if -sqlprint flag is present */ |
| 131 | int fQuiet; /* True if -quiet flag is present */ |
| 132 | int fHttpTrace; /* Trace outbound HTTP requests */ |
| 133 | int fSystemTrace; /* Trace calls to fossil_system(), --systemtrace */ |
| 134 | int fNoSync; /* Do not do an autosync even. --nosync */ |
| 135 | char *zPath; /* Name of webpage being served */ |
| 136 | char *zExtra; /* Extra path information past the webpage name */ |
| 137 | char *zBaseURL; /* Full text of the URL being served */ |
| 138 | char *zTop; /* Parent directory of zPath */ |
| @@ -611,10 +612,11 @@ | |
| 611 | g.isHTTP = 0; |
| 612 | g.fQuiet = find_option("quiet", 0, 0)!=0; |
| 613 | g.fSqlTrace = find_option("sqltrace", 0, 0)!=0; |
| 614 | g.fSqlStats = find_option("sqlstats", 0, 0)!=0; |
| 615 | g.fSystemTrace = find_option("systemtrace", 0, 0)!=0; |
| 616 | if( g.fSqlTrace ) g.fSqlStats = 1; |
| 617 | g.fSqlPrint = find_option("sqlprint", 0, 0)!=0; |
| 618 | g.fHttpTrace = find_option("httptrace", 0, 0)!=0; |
| 619 | g.zLogin = find_option("user", "U", 1); |
| 620 | g.zSSLIdentity = find_option("ssl-identity", 0, 1); |
| @@ -1379,27 +1381,39 @@ | |
| 1379 | while( 1 ){ |
| 1380 | while( zPathInfo[i] && zPathInfo[i]!='/' ){ i++; } |
| 1381 | zRepo = zToFree = mprintf("%s%.*s.fossil",g.zRepositoryName,i,zPathInfo); |
| 1382 | |
| 1383 | /* To avoid mischief, make sure the repository basename contains no |
| 1384 | ** characters other than alphanumerics, "-", "/", and "_". |
| 1385 | */ |
| 1386 | for(j=strlen(g.zRepositoryName)+1, k=0; zRepo[j] && k<i-1; j++, k++){ |
| 1387 | if( !fossil_isalnum(zRepo[j]) && zRepo[j]!='-' && zRepo[j]!='/' ){ |
| 1388 | zRepo[j] = '_'; |
| 1389 | } |
| 1390 | } |
| 1391 | if( zRepo[0]=='/' && zRepo[1]=='/' ){ zRepo++; j--; } |
| 1392 | |
| 1393 | szFile = file_size(zRepo); |
| 1394 | if( zPathInfo[i]=='/' && szFile<0 ){ |
| 1395 | assert( fossil_strcmp(&zRepo[j], ".fossil")==0 ); |
| 1396 | zRepo[j] = 0; |
| 1397 | if( file_isdir(zRepo)==1 ){ |
| 1398 | fossil_free(zToFree); |
| 1399 | i++; |
| 1400 | continue; |
| 1401 | } |
| 1402 | zRepo[j] = '.'; |
| 1403 | } |
| 1404 | |
| 1405 | if( szFile<1024 ){ |
| @@ -1740,13 +1754,17 @@ | |
| 1740 | ** is disallowed. |
| 1741 | */ |
| 1742 | static void find_server_repository(int disallowDir){ |
| 1743 | if( g.argc<3 ){ |
| 1744 | db_must_be_within_tree(); |
| 1745 | }else if( !disallowDir && file_isdir(g.argv[2])==1 ){ |
| 1746 | g.zRepositoryName = mprintf("%s", g.argv[2]); |
| 1747 | file_simplify_name(g.zRepositoryName, -1, 0); |
| 1748 | }else{ |
| 1749 | db_open_repository(g.argv[2]); |
| 1750 | } |
| 1751 | } |
| 1752 | |
| @@ -1934,11 +1952,11 @@ | |
| 1934 | isUiCmd = g.argv[1][0]=='u'; |
| 1935 | if( isUiCmd ){ |
| 1936 | flags |= HTTP_SERVER_LOCALHOST; |
| 1937 | g.useLocalauth = 1; |
| 1938 | } |
| 1939 | find_server_repository(isUiCmd); |
| 1940 | if( zPort ){ |
| 1941 | iPort = mxPort = atoi(zPort); |
| 1942 | }else{ |
| 1943 | iPort = db_get_int("http-port", 8080); |
| 1944 | mxPort = iPort+100; |
| @@ -1973,11 +1991,11 @@ | |
| 1973 | g.httpOut = stdout; |
| 1974 | if( g.fHttpTrace || g.fSqlTrace ){ |
| 1975 | fprintf(stderr, "====== SERVER pid %d =======\n", getpid()); |
| 1976 | } |
| 1977 | g.cgiOutput = 1; |
| 1978 | find_server_repository(isUiCmd); |
| 1979 | g.zRepositoryName = enter_chroot_jail(g.zRepositoryName); |
| 1980 | cgi_handle_http_request(0); |
| 1981 | process_one_web_page(zNotFound); |
| 1982 | #else |
| 1983 | /* Win32 implementation */ |
| 1984 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -129,10 +129,11 @@ | |
| 129 | int fSqlStats; /* True if --sqltrace or --sqlstats are present */ |
| 130 | int fSqlPrint; /* True if -sqlprint flag is present */ |
| 131 | int fQuiet; /* True if -quiet flag is present */ |
| 132 | int fHttpTrace; /* Trace outbound HTTP requests */ |
| 133 | int fSystemTrace; /* Trace calls to fossil_system(), --systemtrace */ |
| 134 | int fSshTrace; /* Trace the SSH setup traffic */ |
| 135 | int fNoSync; /* Do not do an autosync even. --nosync */ |
| 136 | char *zPath; /* Name of webpage being served */ |
| 137 | char *zExtra; /* Extra path information past the webpage name */ |
| 138 | char *zBaseURL; /* Full text of the URL being served */ |
| 139 | char *zTop; /* Parent directory of zPath */ |
| @@ -611,10 +612,11 @@ | |
| 612 | g.isHTTP = 0; |
| 613 | g.fQuiet = find_option("quiet", 0, 0)!=0; |
| 614 | g.fSqlTrace = find_option("sqltrace", 0, 0)!=0; |
| 615 | g.fSqlStats = find_option("sqlstats", 0, 0)!=0; |
| 616 | g.fSystemTrace = find_option("systemtrace", 0, 0)!=0; |
| 617 | g.fSshTrace = find_option("sshtrace", 0, 0)!=0; |
| 618 | if( g.fSqlTrace ) g.fSqlStats = 1; |
| 619 | g.fSqlPrint = find_option("sqlprint", 0, 0)!=0; |
| 620 | g.fHttpTrace = find_option("httptrace", 0, 0)!=0; |
| 621 | g.zLogin = find_option("user", "U", 1); |
| 622 | g.zSSLIdentity = find_option("ssl-identity", 0, 1); |
| @@ -1379,27 +1381,39 @@ | |
| 1381 | while( 1 ){ |
| 1382 | while( zPathInfo[i] && zPathInfo[i]!='/' ){ i++; } |
| 1383 | zRepo = zToFree = mprintf("%s%.*s.fossil",g.zRepositoryName,i,zPathInfo); |
| 1384 | |
| 1385 | /* To avoid mischief, make sure the repository basename contains no |
| 1386 | ** characters other than alphanumerics, "-", "/", "_", and "." beside |
| 1387 | ** "/" or ".". |
| 1388 | */ |
| 1389 | for(j=strlen(g.zRepositoryName)+1, k=0; zRepo[j] && k<i-1; j++, k++){ |
| 1390 | char c = zRepo[j]; |
| 1391 | if( !fossil_isalnum(c) && c!='-' && c!='/' |
| 1392 | && (c!='.' || zRepo[j+1]=='/' || zRepo[j-1]=='/' || zRepo[j+1]=='.') |
| 1393 | ){ |
| 1394 | zRepo[j] = '_'; |
| 1395 | } |
| 1396 | } |
| 1397 | if( zRepo[0]=='/' && zRepo[1]=='/' ){ zRepo++; j--; } |
| 1398 | |
| 1399 | szFile = file_size(zRepo); |
| 1400 | if( szFile<0 ){ |
| 1401 | assert( fossil_strcmp(&zRepo[j], ".fossil")==0 ); |
| 1402 | zRepo[j] = 0; |
| 1403 | if( zPathInfo[i]=='/' && file_isdir(zRepo)==1 ){ |
| 1404 | fossil_free(zToFree); |
| 1405 | i++; |
| 1406 | continue; |
| 1407 | } |
| 1408 | if( file_isfile(zRepo) ){ |
| 1409 | Blob content; |
| 1410 | blob_read_from_file(&content, zRepo); |
| 1411 | cgi_set_content_type(mimetype_from_name(zRepo)); |
| 1412 | cgi_set_content(&content); |
| 1413 | cgi_reply(); |
| 1414 | return; |
| 1415 | } |
| 1416 | zRepo[j] = '.'; |
| 1417 | } |
| 1418 | |
| 1419 | if( szFile<1024 ){ |
| @@ -1740,13 +1754,17 @@ | |
| 1754 | ** is disallowed. |
| 1755 | */ |
| 1756 | static void find_server_repository(int disallowDir){ |
| 1757 | if( g.argc<3 ){ |
| 1758 | db_must_be_within_tree(); |
| 1759 | }else if( file_isdir(g.argv[2])==1 ){ |
| 1760 | if( disallowDir ){ |
| 1761 | fossil_fatal("\"%s\" is a directory, not a repository file", g.argv[2]); |
| 1762 | }else{ |
| 1763 | g.zRepositoryName = mprintf("%s", g.argv[2]); |
| 1764 | file_simplify_name(g.zRepositoryName, -1, 0); |
| 1765 | } |
| 1766 | }else{ |
| 1767 | db_open_repository(g.argv[2]); |
| 1768 | } |
| 1769 | } |
| 1770 | |
| @@ -1934,11 +1952,11 @@ | |
| 1952 | isUiCmd = g.argv[1][0]=='u'; |
| 1953 | if( isUiCmd ){ |
| 1954 | flags |= HTTP_SERVER_LOCALHOST; |
| 1955 | g.useLocalauth = 1; |
| 1956 | } |
| 1957 | find_server_repository(isUiCmd && zNotFound==0); |
| 1958 | if( zPort ){ |
| 1959 | iPort = mxPort = atoi(zPort); |
| 1960 | }else{ |
| 1961 | iPort = db_get_int("http-port", 8080); |
| 1962 | mxPort = iPort+100; |
| @@ -1973,11 +1991,11 @@ | |
| 1991 | g.httpOut = stdout; |
| 1992 | if( g.fHttpTrace || g.fSqlTrace ){ |
| 1993 | fprintf(stderr, "====== SERVER pid %d =======\n", getpid()); |
| 1994 | } |
| 1995 | g.cgiOutput = 1; |
| 1996 | find_server_repository(isUiCmd && zNotFound==0); |
| 1997 | g.zRepositoryName = enter_chroot_jail(g.zRepositoryName); |
| 1998 | cgi_handle_http_request(0); |
| 1999 | process_one_web_page(zNotFound); |
| 2000 | #else |
| 2001 | /* Win32 implementation */ |
| 2002 |
+40
-24
| --- src/skins.c | ||
| +++ src/skins.c | ||
| @@ -44,10 +44,11 @@ | ||
| 44 | 44 | @ font-size: 2em; |
| 45 | 45 | @ font-weight: bold; |
| 46 | 46 | @ background-color: #707070; |
| 47 | 47 | @ color: #ffffff; |
| 48 | 48 | @ min-width: 200px; |
| 49 | +@ white-space: nowrap; | |
| 49 | 50 | @ } |
| 50 | 51 | @ |
| 51 | 52 | @ /* The page title centered at the top of each page */ |
| 52 | 53 | @ div.title { |
| 53 | 54 | @ display: table-cell; |
| @@ -67,10 +68,11 @@ | ||
| 67 | 68 | @ vertical-align: bottom; |
| 68 | 69 | @ color: #404040; |
| 69 | 70 | @ font-size: 0.8em; |
| 70 | 71 | @ font-weight: bold; |
| 71 | 72 | @ min-width: 200px; |
| 73 | +@ white-space: nowrap; | |
| 72 | 74 | @ } |
| 73 | 75 | @ |
| 74 | 76 | @ /* The header across the top of the page */ |
| 75 | 77 | @ div.header { |
| 76 | 78 | @ display: table; |
| @@ -125,10 +127,11 @@ | ||
| 125 | 127 | @ padding: 1px 1px 1px 1px; |
| 126 | 128 | @ font-size: 1.2em; |
| 127 | 129 | @ font-weight: bold; |
| 128 | 130 | @ background-color: #404040; |
| 129 | 131 | @ color: white; |
| 132 | +@ white-space: nowrap; | |
| 130 | 133 | @ } |
| 131 | 134 | @ |
| 132 | 135 | @ /* The "Date" that occurs on the left hand side of timelines */ |
| 133 | 136 | @ div.divider { |
| 134 | 137 | @ background: #a0a0a0; |
| @@ -136,10 +139,11 @@ | ||
| 136 | 139 | @ font-size: 1em; font-weight: normal; |
| 137 | 140 | @ padding: .25em; |
| 138 | 141 | @ margin: .2em 0 .2em 0; |
| 139 | 142 | @ float: left; |
| 140 | 143 | @ clear: left; |
| 144 | +@ white-space: nowrap; | |
| 141 | 145 | @ } |
| 142 | 146 | @ |
| 143 | 147 | @ /* The footer at the very bottom of the page */ |
| 144 | 148 | @ div.footer { |
| 145 | 149 | @ font-size: 0.8em; |
| @@ -166,17 +170,17 @@ | ||
| 166 | 170 | @ media="screen"> |
| 167 | 171 | @ </head> |
| 168 | 172 | @ <body> |
| 169 | 173 | @ <div class="header"> |
| 170 | 174 | @ <div class="title"><small>$<project_name></small><br />$<title></div> |
| 171 | -@ <div class="status"><nobr><th1> | |
| 175 | +@ <div class="status"><th1> | |
| 172 | 176 | @ if {[info exists login]} { |
| 173 | 177 | @ puts "Logged in as $login" |
| 174 | 178 | @ } else { |
| 175 | 179 | @ puts "Not logged in" |
| 176 | 180 | @ } |
| 177 | -@ </th1></nobr></div> | |
| 181 | +@ </th1></div> | |
| 178 | 182 | @ </div> |
| 179 | 183 | @ <div class="mainmenu"> |
| 180 | 184 | @ <th1> |
| 181 | 185 | @ html "<a href=''$home$index_page''>Home</a>\n" |
| 182 | 186 | @ if {[anycap jor]} { |
| @@ -235,10 +239,11 @@ | ||
| 235 | 239 | @ text-align: center; |
| 236 | 240 | @ vertical-align: bottom; |
| 237 | 241 | @ font-weight: bold; |
| 238 | 242 | @ font-size: 2.5em; |
| 239 | 243 | @ color: #a09048; |
| 244 | +@ white-space: nowrap; | |
| 240 | 245 | @ } |
| 241 | 246 | @ |
| 242 | 247 | @ /* The page title centered at the top of each page */ |
| 243 | 248 | @ div.title { |
| 244 | 249 | @ display: table-cell; |
| @@ -258,10 +263,11 @@ | ||
| 258 | 263 | @ vertical-align: bottom; |
| 259 | 264 | @ color: #a09048; |
| 260 | 265 | @ padding: 5px 5px 0 0; |
| 261 | 266 | @ font-size: 0.8em; |
| 262 | 267 | @ font-weight: bold; |
| 268 | +@ white-space: nowrap; | |
| 263 | 269 | @ } |
| 264 | 270 | @ |
| 265 | 271 | @ /* The header across the top of the page */ |
| 266 | 272 | @ div.header { |
| 267 | 273 | @ display: table; |
| @@ -316,10 +322,11 @@ | ||
| 316 | 322 | @ padding: 3px 3px 0 3px; |
| 317 | 323 | @ font-size: 1.2em; |
| 318 | 324 | @ font-weight: bold; |
| 319 | 325 | @ background-color: #a09048; |
| 320 | 326 | @ color: white; |
| 327 | +@ white-space: nowrap; | |
| 321 | 328 | @ } |
| 322 | 329 | @ |
| 323 | 330 | @ /* The "Date" that occurs on the left hand side of timelines */ |
| 324 | 331 | @ div.divider { |
| 325 | 332 | @ background: #e1d498; |
| @@ -327,10 +334,11 @@ | ||
| 327 | 334 | @ font-size: 1em; font-weight: normal; |
| 328 | 335 | @ padding: .25em; |
| 329 | 336 | @ margin: .2em 0 .2em 0; |
| 330 | 337 | @ float: left; |
| 331 | 338 | @ clear: left; |
| 339 | +@ white-space: nowrap; | |
| 332 | 340 | @ } |
| 333 | 341 | @ |
| 334 | 342 | @ /* The footer at the very bottom of the page */ |
| 335 | 343 | @ div.footer { |
| 336 | 344 | @ font-size: 0.8em; |
| @@ -370,18 +378,18 @@ | ||
| 370 | 378 | @ </head> |
| 371 | 379 | @ <body> |
| 372 | 380 | @ <div class="header"> |
| 373 | 381 | @ <div class="title">$<title></div> |
| 374 | 382 | @ <div class="status"> |
| 375 | -@ <div class="logo"><nobr>$<project_name></nobr></div><br/> | |
| 376 | -@ <nobr><th1> | |
| 383 | +@ <div class="logo">$<project_name></div><br/> | |
| 384 | +@ <th1> | |
| 377 | 385 | @ if {[info exists login]} { |
| 378 | 386 | @ puts "Logged in as $login" |
| 379 | 387 | @ } else { |
| 380 | 388 | @ puts "Not logged in" |
| 381 | 389 | @ } |
| 382 | -@ </th1></nobr></div> | |
| 390 | +@ </th1></div> | |
| 383 | 391 | @ </div> |
| 384 | 392 | @ <div class="mainmenu"> |
| 385 | 393 | @ <th1> |
| 386 | 394 | @ html "<a href=''$home$index_page''>Home</a>\n" |
| 387 | 395 | @ if {[anycap jor]} { |
| @@ -448,10 +456,11 @@ | ||
| 448 | 456 | @ display: table-cell; |
| 449 | 457 | @ text-align: left; |
| 450 | 458 | @ vertical-align: bottom; |
| 451 | 459 | @ font-weight: bold; |
| 452 | 460 | @ color: #333; |
| 461 | +@ white-space: nowrap; | |
| 453 | 462 | @ } |
| 454 | 463 | @ |
| 455 | 464 | @ /* The page title centered at the top of each page */ |
| 456 | 465 | @ div.title { |
| 457 | 466 | @ display: table-cell; |
| @@ -471,10 +480,11 @@ | ||
| 471 | 480 | @ vertical-align: bottom; |
| 472 | 481 | @ padding-bottom: 5px; |
| 473 | 482 | @ color: #333; |
| 474 | 483 | @ font-size: 0.8em; |
| 475 | 484 | @ font-weight: bold; |
| 485 | +@ white-space: nowrap; | |
| 476 | 486 | @ } |
| 477 | 487 | @ |
| 478 | 488 | @ /* The header across the top of the page */ |
| 479 | 489 | @ div.header { |
| 480 | 490 | @ margin:10px 0px 10px 0px; |
| @@ -557,10 +567,11 @@ | ||
| 557 | 567 | @ border-style:solid; |
| 558 | 568 | @ border-color:#999; |
| 559 | 569 | @ border-width:1px 0px; |
| 560 | 570 | @ background-color: #eee; |
| 561 | 571 | @ color: #333; |
| 572 | +@ white-space: nowrap; | |
| 562 | 573 | @ } |
| 563 | 574 | @ |
| 564 | 575 | @ /* The "Date" that occurs on the left hand side of timelines */ |
| 565 | 576 | @ div.divider { |
| 566 | 577 | @ background: #eee; |
| @@ -568,11 +579,12 @@ | ||
| 568 | 579 | @ font-size: 1em; font-weight: normal; |
| 569 | 580 | @ padding: .25em; |
| 570 | 581 | @ margin: .2em 0 .2em 0; |
| 571 | 582 | @ float: left; |
| 572 | 583 | @ clear: left; |
| 573 | -@ color: #333 | |
| 584 | +@ color: #333; | |
| 585 | +@ white-space: nowrap; | |
| 574 | 586 | @ } |
| 575 | 587 | @ |
| 576 | 588 | @ /* The footer at the very bottom of the page */ |
| 577 | 589 | @ div.footer { |
| 578 | 590 | @ font-size: 0.8em; |
| @@ -606,20 +618,20 @@ | ||
| 606 | 618 | @ </head> |
| 607 | 619 | @ <body> |
| 608 | 620 | @ <div class="header"> |
| 609 | 621 | @ <div class="logo"> |
| 610 | 622 | @ <img src="$home/logo" alt="logo"> |
| 611 | -@ <br /><nobr>$<project_name></nobr> | |
| 623 | +@ <br />$<project_name> | |
| 612 | 624 | @ </div> |
| 613 | 625 | @ <div class="title">$<title></div> |
| 614 | -@ <div class="status"><nobr><th1> | |
| 626 | +@ <div class="status"><th1> | |
| 615 | 627 | @ if {[info exists login]} { |
| 616 | 628 | @ puts "Logged in as $login" |
| 617 | 629 | @ } else { |
| 618 | 630 | @ puts "Not logged in" |
| 619 | 631 | @ } |
| 620 | -@ </th1></nobr></div> | |
| 632 | +@ </th1></div> | |
| 621 | 633 | @ </div> |
| 622 | 634 | @ <div class="mainmenu"> |
| 623 | 635 | @ <th1> |
| 624 | 636 | @ html "<a href=''$home$index_page''>Home</a>\n" |
| 625 | 637 | @ if {[anycap jor]} { |
| @@ -682,10 +694,11 @@ | ||
| 682 | 694 | @ div.logo { |
| 683 | 695 | @ display: table-cell; |
| 684 | 696 | @ text-align: right; |
| 685 | 697 | @ vertical-align: bottom; |
| 686 | 698 | @ font-weight: normal; |
| 699 | +@ white-space: nowrap; | |
| 687 | 700 | @ } |
| 688 | 701 | @ |
| 689 | 702 | @ /* Widths */ |
| 690 | 703 | @ div.header, div.mainmenu, div.submenu, div.content, div.footer { |
| 691 | 704 | @ max-width: 900px; |
| @@ -714,10 +727,11 @@ | ||
| 714 | 727 | @ display: table-cell; |
| 715 | 728 | @ text-align: right; |
| 716 | 729 | @ vertical-align: bottom; |
| 717 | 730 | @ color: #333; |
| 718 | 731 | @ margin-right: -20px; |
| 732 | +@ white-space: nowrap; | |
| 719 | 733 | @ } |
| 720 | 734 | @ |
| 721 | 735 | @ /* The main menu bar that appears at the top of the page beneath |
| 722 | 736 | @ ** the header */ |
| 723 | 737 | @ div.mainmenu { |
| @@ -793,10 +807,11 @@ | ||
| 793 | 807 | @ text-align: center; |
| 794 | 808 | @ color: white; |
| 795 | 809 | @ border-radius: 5px; |
| 796 | 810 | @ background-color: #446979; |
| 797 | 811 | @ box-shadow: 0px 3px 4px #333333; |
| 812 | +@ white-space: nowrap; | |
| 798 | 813 | @ } |
| 799 | 814 | @ |
| 800 | 815 | @ /* The "Date" that occurs on the left hand side of timelines */ |
| 801 | 816 | @ div.divider { |
| 802 | 817 | @ font-size: 1.2em; |
| @@ -869,20 +884,20 @@ | ||
| 869 | 884 | @ </head> |
| 870 | 885 | @ <body> |
| 871 | 886 | @ <div class="header"> |
| 872 | 887 | @ <div class="logo"> |
| 873 | 888 | @ <img src="$home/logo" alt="logo"> |
| 874 | -@ <br /><nobr>$<project_name></nobr> | |
| 889 | +@ <br />$<project_name> | |
| 875 | 890 | @ </div> |
| 876 | 891 | @ <div class="title">$<title></div> |
| 877 | -@ <div class="status"><nobr><th1> | |
| 892 | +@ <div class="status"><th1> | |
| 878 | 893 | @ if {[info exists login]} { |
| 879 | 894 | @ puts "Logged in as $login" |
| 880 | 895 | @ } else { |
| 881 | 896 | @ puts "Not logged in" |
| 882 | 897 | @ } |
| 883 | -@ </th1></nobr></div> | |
| 898 | +@ </th1></div> | |
| 884 | 899 | @ </div> |
| 885 | 900 | @ <div class="mainmenu"> |
| 886 | 901 | @ <th1> |
| 887 | 902 | @ html "<a href=''$home$index_page''>Home</a>\n" |
| 888 | 903 | @ if {[anycap jor]} { |
| @@ -955,10 +970,11 @@ | ||
| 955 | 970 | @ text-align: center; |
| 956 | 971 | @ vertical-align: bottom; |
| 957 | 972 | @ font-weight: bold; |
| 958 | 973 | @ color: #558195; |
| 959 | 974 | @ min-width: 200px; |
| 975 | +@ white-space: nowrap; | |
| 960 | 976 | @ } |
| 961 | 977 | @ |
| 962 | 978 | @ /* The page title centered at the top of each page */ |
| 963 | 979 | @ div.title { |
| 964 | 980 | @ display: table-cell; |
| @@ -1159,46 +1175,46 @@ | ||
| 1159 | 1175 | @ <a href="$logourl"> |
| 1160 | 1176 | @ <img src="$baseurl/logo" border="0" alt="$project_name"> |
| 1161 | 1177 | @ </a> |
| 1162 | 1178 | @ </div> |
| 1163 | 1179 | @ <div class="title"><small>$<project_name></small><br />$<title></div> |
| 1164 | -@ <div class="status"><nobr><th1> | |
| 1180 | +@ <div class="status"><th1> | |
| 1165 | 1181 | @ if {[info exists login]} { |
| 1166 | 1182 | @ puts "Logged in as $login" |
| 1167 | 1183 | @ } else { |
| 1168 | 1184 | @ puts "Not logged in" |
| 1169 | 1185 | @ } |
| 1170 | -@ </th1></nobr></div> | |
| 1186 | +@ </th1></div> | |
| 1171 | 1187 | @ </div> |
| 1172 | 1188 | @ <div class="mainmenu"> |
| 1173 | 1189 | @ <th1> |
| 1174 | 1190 | @ html "<a href=''$home$index_page''>Home</a>\n" |
| 1175 | 1191 | @ if {[anycap jor]} { |
| 1176 | -@ html "<a href=''timeline''>Timeline</a>\n" | |
| 1192 | +@ html "<a href=''$home/timeline''>Timeline</a>\n" | |
| 1177 | 1193 | @ } |
| 1178 | 1194 | @ if {[hascap oh]} { |
| 1179 | -@ html "<a href=''dir?ci=tip''>Files</a>\n" | |
| 1195 | +@ html "<a href=''$home/dir?ci=tip''>Files</a>\n" | |
| 1180 | 1196 | @ } |
| 1181 | 1197 | @ if {[hascap o]} { |
| 1182 | -@ html "<a href=''brlist''>Branches</a>\n" | |
| 1183 | -@ html "<a href=''taglist''>Tags</a>\n" | |
| 1198 | +@ html "<a href=''$home/brlist''>Branches</a>\n" | |
| 1199 | +@ html "<a href=''$home/taglist''>Tags</a>\n" | |
| 1184 | 1200 | @ } |
| 1185 | 1201 | @ if {[hascap r]} { |
| 1186 | -@ html "<a href=''reportlist''>Tickets</a>\n" | |
| 1202 | +@ html "<a href=''$home/reportlist''>Tickets</a>\n" | |
| 1187 | 1203 | @ } |
| 1188 | 1204 | @ if {[hascap j]} { |
| 1189 | -@ html "<a href=''wiki''>Wiki</a>\n" | |
| 1205 | +@ html "<a href=''$home/wiki''>Wiki</a>\n" | |
| 1190 | 1206 | @ } |
| 1191 | 1207 | @ if {[hascap s]} { |
| 1192 | -@ html "<a href=''setup''>Admin</a>\n" | |
| 1208 | +@ html "<a href=''$home/setup''>Admin</a>\n" | |
| 1193 | 1209 | @ } elseif {[hascap a]} { |
| 1194 | -@ html "<a href=''setup_ulist''>Users</a>\n" | |
| 1210 | +@ html "<a href=''$home/setup_ulist''>Users</a>\n" | |
| 1195 | 1211 | @ } |
| 1196 | 1212 | @ if {[info exists login]} { |
| 1197 | -@ html "<a href=''login''>Logout</a>\n" | |
| 1213 | +@ html "<a href=''$home/login''>Logout</a>\n" | |
| 1198 | 1214 | @ } else { |
| 1199 | -@ html "<a href=''login''>Login</a>\n" | |
| 1215 | +@ html "<a href=''$home/login''>Login</a>\n" | |
| 1200 | 1216 | @ } |
| 1201 | 1217 | @ </th1></div> |
| 1202 | 1218 | @ '); |
| 1203 | 1219 | @ REPLACE INTO config(name,mtime,value) |
| 1204 | 1220 | @ VALUES('footer',now(),'<div class="footer"> |
| 1205 | 1221 |
| --- src/skins.c | |
| +++ src/skins.c | |
| @@ -44,10 +44,11 @@ | |
| 44 | @ font-size: 2em; |
| 45 | @ font-weight: bold; |
| 46 | @ background-color: #707070; |
| 47 | @ color: #ffffff; |
| 48 | @ min-width: 200px; |
| 49 | @ } |
| 50 | @ |
| 51 | @ /* The page title centered at the top of each page */ |
| 52 | @ div.title { |
| 53 | @ display: table-cell; |
| @@ -67,10 +68,11 @@ | |
| 67 | @ vertical-align: bottom; |
| 68 | @ color: #404040; |
| 69 | @ font-size: 0.8em; |
| 70 | @ font-weight: bold; |
| 71 | @ min-width: 200px; |
| 72 | @ } |
| 73 | @ |
| 74 | @ /* The header across the top of the page */ |
| 75 | @ div.header { |
| 76 | @ display: table; |
| @@ -125,10 +127,11 @@ | |
| 125 | @ padding: 1px 1px 1px 1px; |
| 126 | @ font-size: 1.2em; |
| 127 | @ font-weight: bold; |
| 128 | @ background-color: #404040; |
| 129 | @ color: white; |
| 130 | @ } |
| 131 | @ |
| 132 | @ /* The "Date" that occurs on the left hand side of timelines */ |
| 133 | @ div.divider { |
| 134 | @ background: #a0a0a0; |
| @@ -136,10 +139,11 @@ | |
| 136 | @ font-size: 1em; font-weight: normal; |
| 137 | @ padding: .25em; |
| 138 | @ margin: .2em 0 .2em 0; |
| 139 | @ float: left; |
| 140 | @ clear: left; |
| 141 | @ } |
| 142 | @ |
| 143 | @ /* The footer at the very bottom of the page */ |
| 144 | @ div.footer { |
| 145 | @ font-size: 0.8em; |
| @@ -166,17 +170,17 @@ | |
| 166 | @ media="screen"> |
| 167 | @ </head> |
| 168 | @ <body> |
| 169 | @ <div class="header"> |
| 170 | @ <div class="title"><small>$<project_name></small><br />$<title></div> |
| 171 | @ <div class="status"><nobr><th1> |
| 172 | @ if {[info exists login]} { |
| 173 | @ puts "Logged in as $login" |
| 174 | @ } else { |
| 175 | @ puts "Not logged in" |
| 176 | @ } |
| 177 | @ </th1></nobr></div> |
| 178 | @ </div> |
| 179 | @ <div class="mainmenu"> |
| 180 | @ <th1> |
| 181 | @ html "<a href=''$home$index_page''>Home</a>\n" |
| 182 | @ if {[anycap jor]} { |
| @@ -235,10 +239,11 @@ | |
| 235 | @ text-align: center; |
| 236 | @ vertical-align: bottom; |
| 237 | @ font-weight: bold; |
| 238 | @ font-size: 2.5em; |
| 239 | @ color: #a09048; |
| 240 | @ } |
| 241 | @ |
| 242 | @ /* The page title centered at the top of each page */ |
| 243 | @ div.title { |
| 244 | @ display: table-cell; |
| @@ -258,10 +263,11 @@ | |
| 258 | @ vertical-align: bottom; |
| 259 | @ color: #a09048; |
| 260 | @ padding: 5px 5px 0 0; |
| 261 | @ font-size: 0.8em; |
| 262 | @ font-weight: bold; |
| 263 | @ } |
| 264 | @ |
| 265 | @ /* The header across the top of the page */ |
| 266 | @ div.header { |
| 267 | @ display: table; |
| @@ -316,10 +322,11 @@ | |
| 316 | @ padding: 3px 3px 0 3px; |
| 317 | @ font-size: 1.2em; |
| 318 | @ font-weight: bold; |
| 319 | @ background-color: #a09048; |
| 320 | @ color: white; |
| 321 | @ } |
| 322 | @ |
| 323 | @ /* The "Date" that occurs on the left hand side of timelines */ |
| 324 | @ div.divider { |
| 325 | @ background: #e1d498; |
| @@ -327,10 +334,11 @@ | |
| 327 | @ font-size: 1em; font-weight: normal; |
| 328 | @ padding: .25em; |
| 329 | @ margin: .2em 0 .2em 0; |
| 330 | @ float: left; |
| 331 | @ clear: left; |
| 332 | @ } |
| 333 | @ |
| 334 | @ /* The footer at the very bottom of the page */ |
| 335 | @ div.footer { |
| 336 | @ font-size: 0.8em; |
| @@ -370,18 +378,18 @@ | |
| 370 | @ </head> |
| 371 | @ <body> |
| 372 | @ <div class="header"> |
| 373 | @ <div class="title">$<title></div> |
| 374 | @ <div class="status"> |
| 375 | @ <div class="logo"><nobr>$<project_name></nobr></div><br/> |
| 376 | @ <nobr><th1> |
| 377 | @ if {[info exists login]} { |
| 378 | @ puts "Logged in as $login" |
| 379 | @ } else { |
| 380 | @ puts "Not logged in" |
| 381 | @ } |
| 382 | @ </th1></nobr></div> |
| 383 | @ </div> |
| 384 | @ <div class="mainmenu"> |
| 385 | @ <th1> |
| 386 | @ html "<a href=''$home$index_page''>Home</a>\n" |
| 387 | @ if {[anycap jor]} { |
| @@ -448,10 +456,11 @@ | |
| 448 | @ display: table-cell; |
| 449 | @ text-align: left; |
| 450 | @ vertical-align: bottom; |
| 451 | @ font-weight: bold; |
| 452 | @ color: #333; |
| 453 | @ } |
| 454 | @ |
| 455 | @ /* The page title centered at the top of each page */ |
| 456 | @ div.title { |
| 457 | @ display: table-cell; |
| @@ -471,10 +480,11 @@ | |
| 471 | @ vertical-align: bottom; |
| 472 | @ padding-bottom: 5px; |
| 473 | @ color: #333; |
| 474 | @ font-size: 0.8em; |
| 475 | @ font-weight: bold; |
| 476 | @ } |
| 477 | @ |
| 478 | @ /* The header across the top of the page */ |
| 479 | @ div.header { |
| 480 | @ margin:10px 0px 10px 0px; |
| @@ -557,10 +567,11 @@ | |
| 557 | @ border-style:solid; |
| 558 | @ border-color:#999; |
| 559 | @ border-width:1px 0px; |
| 560 | @ background-color: #eee; |
| 561 | @ color: #333; |
| 562 | @ } |
| 563 | @ |
| 564 | @ /* The "Date" that occurs on the left hand side of timelines */ |
| 565 | @ div.divider { |
| 566 | @ background: #eee; |
| @@ -568,11 +579,12 @@ | |
| 568 | @ font-size: 1em; font-weight: normal; |
| 569 | @ padding: .25em; |
| 570 | @ margin: .2em 0 .2em 0; |
| 571 | @ float: left; |
| 572 | @ clear: left; |
| 573 | @ color: #333 |
| 574 | @ } |
| 575 | @ |
| 576 | @ /* The footer at the very bottom of the page */ |
| 577 | @ div.footer { |
| 578 | @ font-size: 0.8em; |
| @@ -606,20 +618,20 @@ | |
| 606 | @ </head> |
| 607 | @ <body> |
| 608 | @ <div class="header"> |
| 609 | @ <div class="logo"> |
| 610 | @ <img src="$home/logo" alt="logo"> |
| 611 | @ <br /><nobr>$<project_name></nobr> |
| 612 | @ </div> |
| 613 | @ <div class="title">$<title></div> |
| 614 | @ <div class="status"><nobr><th1> |
| 615 | @ if {[info exists login]} { |
| 616 | @ puts "Logged in as $login" |
| 617 | @ } else { |
| 618 | @ puts "Not logged in" |
| 619 | @ } |
| 620 | @ </th1></nobr></div> |
| 621 | @ </div> |
| 622 | @ <div class="mainmenu"> |
| 623 | @ <th1> |
| 624 | @ html "<a href=''$home$index_page''>Home</a>\n" |
| 625 | @ if {[anycap jor]} { |
| @@ -682,10 +694,11 @@ | |
| 682 | @ div.logo { |
| 683 | @ display: table-cell; |
| 684 | @ text-align: right; |
| 685 | @ vertical-align: bottom; |
| 686 | @ font-weight: normal; |
| 687 | @ } |
| 688 | @ |
| 689 | @ /* Widths */ |
| 690 | @ div.header, div.mainmenu, div.submenu, div.content, div.footer { |
| 691 | @ max-width: 900px; |
| @@ -714,10 +727,11 @@ | |
| 714 | @ display: table-cell; |
| 715 | @ text-align: right; |
| 716 | @ vertical-align: bottom; |
| 717 | @ color: #333; |
| 718 | @ margin-right: -20px; |
| 719 | @ } |
| 720 | @ |
| 721 | @ /* The main menu bar that appears at the top of the page beneath |
| 722 | @ ** the header */ |
| 723 | @ div.mainmenu { |
| @@ -793,10 +807,11 @@ | |
| 793 | @ text-align: center; |
| 794 | @ color: white; |
| 795 | @ border-radius: 5px; |
| 796 | @ background-color: #446979; |
| 797 | @ box-shadow: 0px 3px 4px #333333; |
| 798 | @ } |
| 799 | @ |
| 800 | @ /* The "Date" that occurs on the left hand side of timelines */ |
| 801 | @ div.divider { |
| 802 | @ font-size: 1.2em; |
| @@ -869,20 +884,20 @@ | |
| 869 | @ </head> |
| 870 | @ <body> |
| 871 | @ <div class="header"> |
| 872 | @ <div class="logo"> |
| 873 | @ <img src="$home/logo" alt="logo"> |
| 874 | @ <br /><nobr>$<project_name></nobr> |
| 875 | @ </div> |
| 876 | @ <div class="title">$<title></div> |
| 877 | @ <div class="status"><nobr><th1> |
| 878 | @ if {[info exists login]} { |
| 879 | @ puts "Logged in as $login" |
| 880 | @ } else { |
| 881 | @ puts "Not logged in" |
| 882 | @ } |
| 883 | @ </th1></nobr></div> |
| 884 | @ </div> |
| 885 | @ <div class="mainmenu"> |
| 886 | @ <th1> |
| 887 | @ html "<a href=''$home$index_page''>Home</a>\n" |
| 888 | @ if {[anycap jor]} { |
| @@ -955,10 +970,11 @@ | |
| 955 | @ text-align: center; |
| 956 | @ vertical-align: bottom; |
| 957 | @ font-weight: bold; |
| 958 | @ color: #558195; |
| 959 | @ min-width: 200px; |
| 960 | @ } |
| 961 | @ |
| 962 | @ /* The page title centered at the top of each page */ |
| 963 | @ div.title { |
| 964 | @ display: table-cell; |
| @@ -1159,46 +1175,46 @@ | |
| 1159 | @ <a href="$logourl"> |
| 1160 | @ <img src="$baseurl/logo" border="0" alt="$project_name"> |
| 1161 | @ </a> |
| 1162 | @ </div> |
| 1163 | @ <div class="title"><small>$<project_name></small><br />$<title></div> |
| 1164 | @ <div class="status"><nobr><th1> |
| 1165 | @ if {[info exists login]} { |
| 1166 | @ puts "Logged in as $login" |
| 1167 | @ } else { |
| 1168 | @ puts "Not logged in" |
| 1169 | @ } |
| 1170 | @ </th1></nobr></div> |
| 1171 | @ </div> |
| 1172 | @ <div class="mainmenu"> |
| 1173 | @ <th1> |
| 1174 | @ html "<a href=''$home$index_page''>Home</a>\n" |
| 1175 | @ if {[anycap jor]} { |
| 1176 | @ html "<a href=''timeline''>Timeline</a>\n" |
| 1177 | @ } |
| 1178 | @ if {[hascap oh]} { |
| 1179 | @ html "<a href=''dir?ci=tip''>Files</a>\n" |
| 1180 | @ } |
| 1181 | @ if {[hascap o]} { |
| 1182 | @ html "<a href=''brlist''>Branches</a>\n" |
| 1183 | @ html "<a href=''taglist''>Tags</a>\n" |
| 1184 | @ } |
| 1185 | @ if {[hascap r]} { |
| 1186 | @ html "<a href=''reportlist''>Tickets</a>\n" |
| 1187 | @ } |
| 1188 | @ if {[hascap j]} { |
| 1189 | @ html "<a href=''wiki''>Wiki</a>\n" |
| 1190 | @ } |
| 1191 | @ if {[hascap s]} { |
| 1192 | @ html "<a href=''setup''>Admin</a>\n" |
| 1193 | @ } elseif {[hascap a]} { |
| 1194 | @ html "<a href=''setup_ulist''>Users</a>\n" |
| 1195 | @ } |
| 1196 | @ if {[info exists login]} { |
| 1197 | @ html "<a href=''login''>Logout</a>\n" |
| 1198 | @ } else { |
| 1199 | @ html "<a href=''login''>Login</a>\n" |
| 1200 | @ } |
| 1201 | @ </th1></div> |
| 1202 | @ '); |
| 1203 | @ REPLACE INTO config(name,mtime,value) |
| 1204 | @ VALUES('footer',now(),'<div class="footer"> |
| 1205 |
| --- src/skins.c | |
| +++ src/skins.c | |
| @@ -44,10 +44,11 @@ | |
| 44 | @ font-size: 2em; |
| 45 | @ font-weight: bold; |
| 46 | @ background-color: #707070; |
| 47 | @ color: #ffffff; |
| 48 | @ min-width: 200px; |
| 49 | @ white-space: nowrap; |
| 50 | @ } |
| 51 | @ |
| 52 | @ /* The page title centered at the top of each page */ |
| 53 | @ div.title { |
| 54 | @ display: table-cell; |
| @@ -67,10 +68,11 @@ | |
| 68 | @ vertical-align: bottom; |
| 69 | @ color: #404040; |
| 70 | @ font-size: 0.8em; |
| 71 | @ font-weight: bold; |
| 72 | @ min-width: 200px; |
| 73 | @ white-space: nowrap; |
| 74 | @ } |
| 75 | @ |
| 76 | @ /* The header across the top of the page */ |
| 77 | @ div.header { |
| 78 | @ display: table; |
| @@ -125,10 +127,11 @@ | |
| 127 | @ padding: 1px 1px 1px 1px; |
| 128 | @ font-size: 1.2em; |
| 129 | @ font-weight: bold; |
| 130 | @ background-color: #404040; |
| 131 | @ color: white; |
| 132 | @ white-space: nowrap; |
| 133 | @ } |
| 134 | @ |
| 135 | @ /* The "Date" that occurs on the left hand side of timelines */ |
| 136 | @ div.divider { |
| 137 | @ background: #a0a0a0; |
| @@ -136,10 +139,11 @@ | |
| 139 | @ font-size: 1em; font-weight: normal; |
| 140 | @ padding: .25em; |
| 141 | @ margin: .2em 0 .2em 0; |
| 142 | @ float: left; |
| 143 | @ clear: left; |
| 144 | @ white-space: nowrap; |
| 145 | @ } |
| 146 | @ |
| 147 | @ /* The footer at the very bottom of the page */ |
| 148 | @ div.footer { |
| 149 | @ font-size: 0.8em; |
| @@ -166,17 +170,17 @@ | |
| 170 | @ media="screen"> |
| 171 | @ </head> |
| 172 | @ <body> |
| 173 | @ <div class="header"> |
| 174 | @ <div class="title"><small>$<project_name></small><br />$<title></div> |
| 175 | @ <div class="status"><th1> |
| 176 | @ if {[info exists login]} { |
| 177 | @ puts "Logged in as $login" |
| 178 | @ } else { |
| 179 | @ puts "Not logged in" |
| 180 | @ } |
| 181 | @ </th1></div> |
| 182 | @ </div> |
| 183 | @ <div class="mainmenu"> |
| 184 | @ <th1> |
| 185 | @ html "<a href=''$home$index_page''>Home</a>\n" |
| 186 | @ if {[anycap jor]} { |
| @@ -235,10 +239,11 @@ | |
| 239 | @ text-align: center; |
| 240 | @ vertical-align: bottom; |
| 241 | @ font-weight: bold; |
| 242 | @ font-size: 2.5em; |
| 243 | @ color: #a09048; |
| 244 | @ white-space: nowrap; |
| 245 | @ } |
| 246 | @ |
| 247 | @ /* The page title centered at the top of each page */ |
| 248 | @ div.title { |
| 249 | @ display: table-cell; |
| @@ -258,10 +263,11 @@ | |
| 263 | @ vertical-align: bottom; |
| 264 | @ color: #a09048; |
| 265 | @ padding: 5px 5px 0 0; |
| 266 | @ font-size: 0.8em; |
| 267 | @ font-weight: bold; |
| 268 | @ white-space: nowrap; |
| 269 | @ } |
| 270 | @ |
| 271 | @ /* The header across the top of the page */ |
| 272 | @ div.header { |
| 273 | @ display: table; |
| @@ -316,10 +322,11 @@ | |
| 322 | @ padding: 3px 3px 0 3px; |
| 323 | @ font-size: 1.2em; |
| 324 | @ font-weight: bold; |
| 325 | @ background-color: #a09048; |
| 326 | @ color: white; |
| 327 | @ white-space: nowrap; |
| 328 | @ } |
| 329 | @ |
| 330 | @ /* The "Date" that occurs on the left hand side of timelines */ |
| 331 | @ div.divider { |
| 332 | @ background: #e1d498; |
| @@ -327,10 +334,11 @@ | |
| 334 | @ font-size: 1em; font-weight: normal; |
| 335 | @ padding: .25em; |
| 336 | @ margin: .2em 0 .2em 0; |
| 337 | @ float: left; |
| 338 | @ clear: left; |
| 339 | @ white-space: nowrap; |
| 340 | @ } |
| 341 | @ |
| 342 | @ /* The footer at the very bottom of the page */ |
| 343 | @ div.footer { |
| 344 | @ font-size: 0.8em; |
| @@ -370,18 +378,18 @@ | |
| 378 | @ </head> |
| 379 | @ <body> |
| 380 | @ <div class="header"> |
| 381 | @ <div class="title">$<title></div> |
| 382 | @ <div class="status"> |
| 383 | @ <div class="logo">$<project_name></div><br/> |
| 384 | @ <th1> |
| 385 | @ if {[info exists login]} { |
| 386 | @ puts "Logged in as $login" |
| 387 | @ } else { |
| 388 | @ puts "Not logged in" |
| 389 | @ } |
| 390 | @ </th1></div> |
| 391 | @ </div> |
| 392 | @ <div class="mainmenu"> |
| 393 | @ <th1> |
| 394 | @ html "<a href=''$home$index_page''>Home</a>\n" |
| 395 | @ if {[anycap jor]} { |
| @@ -448,10 +456,11 @@ | |
| 456 | @ display: table-cell; |
| 457 | @ text-align: left; |
| 458 | @ vertical-align: bottom; |
| 459 | @ font-weight: bold; |
| 460 | @ color: #333; |
| 461 | @ white-space: nowrap; |
| 462 | @ } |
| 463 | @ |
| 464 | @ /* The page title centered at the top of each page */ |
| 465 | @ div.title { |
| 466 | @ display: table-cell; |
| @@ -471,10 +480,11 @@ | |
| 480 | @ vertical-align: bottom; |
| 481 | @ padding-bottom: 5px; |
| 482 | @ color: #333; |
| 483 | @ font-size: 0.8em; |
| 484 | @ font-weight: bold; |
| 485 | @ white-space: nowrap; |
| 486 | @ } |
| 487 | @ |
| 488 | @ /* The header across the top of the page */ |
| 489 | @ div.header { |
| 490 | @ margin:10px 0px 10px 0px; |
| @@ -557,10 +567,11 @@ | |
| 567 | @ border-style:solid; |
| 568 | @ border-color:#999; |
| 569 | @ border-width:1px 0px; |
| 570 | @ background-color: #eee; |
| 571 | @ color: #333; |
| 572 | @ white-space: nowrap; |
| 573 | @ } |
| 574 | @ |
| 575 | @ /* The "Date" that occurs on the left hand side of timelines */ |
| 576 | @ div.divider { |
| 577 | @ background: #eee; |
| @@ -568,11 +579,12 @@ | |
| 579 | @ font-size: 1em; font-weight: normal; |
| 580 | @ padding: .25em; |
| 581 | @ margin: .2em 0 .2em 0; |
| 582 | @ float: left; |
| 583 | @ clear: left; |
| 584 | @ color: #333; |
| 585 | @ white-space: nowrap; |
| 586 | @ } |
| 587 | @ |
| 588 | @ /* The footer at the very bottom of the page */ |
| 589 | @ div.footer { |
| 590 | @ font-size: 0.8em; |
| @@ -606,20 +618,20 @@ | |
| 618 | @ </head> |
| 619 | @ <body> |
| 620 | @ <div class="header"> |
| 621 | @ <div class="logo"> |
| 622 | @ <img src="$home/logo" alt="logo"> |
| 623 | @ <br />$<project_name> |
| 624 | @ </div> |
| 625 | @ <div class="title">$<title></div> |
| 626 | @ <div class="status"><th1> |
| 627 | @ if {[info exists login]} { |
| 628 | @ puts "Logged in as $login" |
| 629 | @ } else { |
| 630 | @ puts "Not logged in" |
| 631 | @ } |
| 632 | @ </th1></div> |
| 633 | @ </div> |
| 634 | @ <div class="mainmenu"> |
| 635 | @ <th1> |
| 636 | @ html "<a href=''$home$index_page''>Home</a>\n" |
| 637 | @ if {[anycap jor]} { |
| @@ -682,10 +694,11 @@ | |
| 694 | @ div.logo { |
| 695 | @ display: table-cell; |
| 696 | @ text-align: right; |
| 697 | @ vertical-align: bottom; |
| 698 | @ font-weight: normal; |
| 699 | @ white-space: nowrap; |
| 700 | @ } |
| 701 | @ |
| 702 | @ /* Widths */ |
| 703 | @ div.header, div.mainmenu, div.submenu, div.content, div.footer { |
| 704 | @ max-width: 900px; |
| @@ -714,10 +727,11 @@ | |
| 727 | @ display: table-cell; |
| 728 | @ text-align: right; |
| 729 | @ vertical-align: bottom; |
| 730 | @ color: #333; |
| 731 | @ margin-right: -20px; |
| 732 | @ white-space: nowrap; |
| 733 | @ } |
| 734 | @ |
| 735 | @ /* The main menu bar that appears at the top of the page beneath |
| 736 | @ ** the header */ |
| 737 | @ div.mainmenu { |
| @@ -793,10 +807,11 @@ | |
| 807 | @ text-align: center; |
| 808 | @ color: white; |
| 809 | @ border-radius: 5px; |
| 810 | @ background-color: #446979; |
| 811 | @ box-shadow: 0px 3px 4px #333333; |
| 812 | @ white-space: nowrap; |
| 813 | @ } |
| 814 | @ |
| 815 | @ /* The "Date" that occurs on the left hand side of timelines */ |
| 816 | @ div.divider { |
| 817 | @ font-size: 1.2em; |
| @@ -869,20 +884,20 @@ | |
| 884 | @ </head> |
| 885 | @ <body> |
| 886 | @ <div class="header"> |
| 887 | @ <div class="logo"> |
| 888 | @ <img src="$home/logo" alt="logo"> |
| 889 | @ <br />$<project_name> |
| 890 | @ </div> |
| 891 | @ <div class="title">$<title></div> |
| 892 | @ <div class="status"><th1> |
| 893 | @ if {[info exists login]} { |
| 894 | @ puts "Logged in as $login" |
| 895 | @ } else { |
| 896 | @ puts "Not logged in" |
| 897 | @ } |
| 898 | @ </th1></div> |
| 899 | @ </div> |
| 900 | @ <div class="mainmenu"> |
| 901 | @ <th1> |
| 902 | @ html "<a href=''$home$index_page''>Home</a>\n" |
| 903 | @ if {[anycap jor]} { |
| @@ -955,10 +970,11 @@ | |
| 970 | @ text-align: center; |
| 971 | @ vertical-align: bottom; |
| 972 | @ font-weight: bold; |
| 973 | @ color: #558195; |
| 974 | @ min-width: 200px; |
| 975 | @ white-space: nowrap; |
| 976 | @ } |
| 977 | @ |
| 978 | @ /* The page title centered at the top of each page */ |
| 979 | @ div.title { |
| 980 | @ display: table-cell; |
| @@ -1159,46 +1175,46 @@ | |
| 1175 | @ <a href="$logourl"> |
| 1176 | @ <img src="$baseurl/logo" border="0" alt="$project_name"> |
| 1177 | @ </a> |
| 1178 | @ </div> |
| 1179 | @ <div class="title"><small>$<project_name></small><br />$<title></div> |
| 1180 | @ <div class="status"><th1> |
| 1181 | @ if {[info exists login]} { |
| 1182 | @ puts "Logged in as $login" |
| 1183 | @ } else { |
| 1184 | @ puts "Not logged in" |
| 1185 | @ } |
| 1186 | @ </th1></div> |
| 1187 | @ </div> |
| 1188 | @ <div class="mainmenu"> |
| 1189 | @ <th1> |
| 1190 | @ html "<a href=''$home$index_page''>Home</a>\n" |
| 1191 | @ if {[anycap jor]} { |
| 1192 | @ html "<a href=''$home/timeline''>Timeline</a>\n" |
| 1193 | @ } |
| 1194 | @ if {[hascap oh]} { |
| 1195 | @ html "<a href=''$home/dir?ci=tip''>Files</a>\n" |
| 1196 | @ } |
| 1197 | @ if {[hascap o]} { |
| 1198 | @ html "<a href=''$home/brlist''>Branches</a>\n" |
| 1199 | @ html "<a href=''$home/taglist''>Tags</a>\n" |
| 1200 | @ } |
| 1201 | @ if {[hascap r]} { |
| 1202 | @ html "<a href=''$home/reportlist''>Tickets</a>\n" |
| 1203 | @ } |
| 1204 | @ if {[hascap j]} { |
| 1205 | @ html "<a href=''$home/wiki''>Wiki</a>\n" |
| 1206 | @ } |
| 1207 | @ if {[hascap s]} { |
| 1208 | @ html "<a href=''$home/setup''>Admin</a>\n" |
| 1209 | @ } elseif {[hascap a]} { |
| 1210 | @ html "<a href=''$home/setup_ulist''>Users</a>\n" |
| 1211 | @ } |
| 1212 | @ if {[info exists login]} { |
| 1213 | @ html "<a href=''$home/login''>Logout</a>\n" |
| 1214 | @ } else { |
| 1215 | @ html "<a href=''$home/login''>Login</a>\n" |
| 1216 | @ } |
| 1217 | @ </th1></div> |
| 1218 | @ '); |
| 1219 | @ REPLACE INTO config(name,mtime,value) |
| 1220 | @ VALUES('footer',now(),'<div class="footer"> |
| 1221 |
+11
-10
| --- src/style.c | ||
| +++ src/style.c | ||
| @@ -366,34 +366,34 @@ | ||
| 366 | 366 | @ </div> |
| 367 | 367 | @ <div class="mainmenu"> |
| 368 | 368 | @ <th1> |
| 369 | 369 | @ html "<a href='$home$index_page'>Home</a>\n" |
| 370 | 370 | @ if {[anycap jor]} { |
| 371 | -@ html "<a href='timeline'>Timeline</a>\n" | |
| 371 | +@ html "<a href='$home/timeline'>Timeline</a>\n" | |
| 372 | 372 | @ } |
| 373 | 373 | @ if {[hascap oh]} { |
| 374 | -@ html "<a href='dir?ci=tip'>Files</a>\n" | |
| 374 | +@ html "<a href='$home/dir?ci=tip'>Files</a>\n" | |
| 375 | 375 | @ } |
| 376 | 376 | @ if {[hascap o]} { |
| 377 | -@ html "<a href='brlist'>Branches</a>\n" | |
| 378 | -@ html "<a href='taglist'>Tags</a>\n" | |
| 377 | +@ html "<a href='$home/brlist'>Branches</a>\n" | |
| 378 | +@ html "<a href='$home/taglist'>Tags</a>\n" | |
| 379 | 379 | @ } |
| 380 | 380 | @ if {[hascap r]} { |
| 381 | -@ html "<a href='reportlist'>Tickets</a>\n" | |
| 381 | +@ html "<a href='$home/reportlist'>Tickets</a>\n" | |
| 382 | 382 | @ } |
| 383 | 383 | @ if {[hascap j]} { |
| 384 | -@ html "<a href='wiki'>Wiki</a>\n" | |
| 384 | +@ html "<a href='$home/wiki'>Wiki</a>\n" | |
| 385 | 385 | @ } |
| 386 | 386 | @ if {[hascap s]} { |
| 387 | -@ html "<a href='setup'>Admin</a>\n" | |
| 387 | +@ html "<a href='$home/setup'>Admin</a>\n" | |
| 388 | 388 | @ } elseif {[hascap a]} { |
| 389 | -@ html "<a href='setup_ulist'>Users</a>\n" | |
| 389 | +@ html "<a href='$home/setup_ulist'>Users</a>\n" | |
| 390 | 390 | @ } |
| 391 | 391 | @ if {[info exists login]} { |
| 392 | -@ html "<a href='login'>Logout</a>\n" | |
| 392 | +@ html "<a href='$home/login'>Logout</a>\n" | |
| 393 | 393 | @ } else { |
| 394 | -@ html "<a href='login'>Login</a>\n" | |
| 394 | +@ html "<a href='$home/login'>Login</a>\n" | |
| 395 | 395 | @ } |
| 396 | 396 | @ </th1></div> |
| 397 | 397 | ; |
| 398 | 398 | |
| 399 | 399 | /* |
| @@ -428,10 +428,11 @@ | ||
| 428 | 428 | @ text-align: center; |
| 429 | 429 | @ vertical-align: bottom; |
| 430 | 430 | @ font-weight: bold; |
| 431 | 431 | @ color: #558195; |
| 432 | 432 | @ min-width: 200px; |
| 433 | +@ white-space: nowrap; | |
| 433 | 434 | @ } |
| 434 | 435 | @ |
| 435 | 436 | @ /* The page title centered at the top of each page */ |
| 436 | 437 | @ div.title { |
| 437 | 438 | @ display: table-cell; |
| 438 | 439 |
| --- src/style.c | |
| +++ src/style.c | |
| @@ -366,34 +366,34 @@ | |
| 366 | @ </div> |
| 367 | @ <div class="mainmenu"> |
| 368 | @ <th1> |
| 369 | @ html "<a href='$home$index_page'>Home</a>\n" |
| 370 | @ if {[anycap jor]} { |
| 371 | @ html "<a href='timeline'>Timeline</a>\n" |
| 372 | @ } |
| 373 | @ if {[hascap oh]} { |
| 374 | @ html "<a href='dir?ci=tip'>Files</a>\n" |
| 375 | @ } |
| 376 | @ if {[hascap o]} { |
| 377 | @ html "<a href='brlist'>Branches</a>\n" |
| 378 | @ html "<a href='taglist'>Tags</a>\n" |
| 379 | @ } |
| 380 | @ if {[hascap r]} { |
| 381 | @ html "<a href='reportlist'>Tickets</a>\n" |
| 382 | @ } |
| 383 | @ if {[hascap j]} { |
| 384 | @ html "<a href='wiki'>Wiki</a>\n" |
| 385 | @ } |
| 386 | @ if {[hascap s]} { |
| 387 | @ html "<a href='setup'>Admin</a>\n" |
| 388 | @ } elseif {[hascap a]} { |
| 389 | @ html "<a href='setup_ulist'>Users</a>\n" |
| 390 | @ } |
| 391 | @ if {[info exists login]} { |
| 392 | @ html "<a href='login'>Logout</a>\n" |
| 393 | @ } else { |
| 394 | @ html "<a href='login'>Login</a>\n" |
| 395 | @ } |
| 396 | @ </th1></div> |
| 397 | ; |
| 398 | |
| 399 | /* |
| @@ -428,10 +428,11 @@ | |
| 428 | @ text-align: center; |
| 429 | @ vertical-align: bottom; |
| 430 | @ font-weight: bold; |
| 431 | @ color: #558195; |
| 432 | @ min-width: 200px; |
| 433 | @ } |
| 434 | @ |
| 435 | @ /* The page title centered at the top of each page */ |
| 436 | @ div.title { |
| 437 | @ display: table-cell; |
| 438 |
| --- src/style.c | |
| +++ src/style.c | |
| @@ -366,34 +366,34 @@ | |
| 366 | @ </div> |
| 367 | @ <div class="mainmenu"> |
| 368 | @ <th1> |
| 369 | @ html "<a href='$home$index_page'>Home</a>\n" |
| 370 | @ if {[anycap jor]} { |
| 371 | @ html "<a href='$home/timeline'>Timeline</a>\n" |
| 372 | @ } |
| 373 | @ if {[hascap oh]} { |
| 374 | @ html "<a href='$home/dir?ci=tip'>Files</a>\n" |
| 375 | @ } |
| 376 | @ if {[hascap o]} { |
| 377 | @ html "<a href='$home/brlist'>Branches</a>\n" |
| 378 | @ html "<a href='$home/taglist'>Tags</a>\n" |
| 379 | @ } |
| 380 | @ if {[hascap r]} { |
| 381 | @ html "<a href='$home/reportlist'>Tickets</a>\n" |
| 382 | @ } |
| 383 | @ if {[hascap j]} { |
| 384 | @ html "<a href='$home/wiki'>Wiki</a>\n" |
| 385 | @ } |
| 386 | @ if {[hascap s]} { |
| 387 | @ html "<a href='$home/setup'>Admin</a>\n" |
| 388 | @ } elseif {[hascap a]} { |
| 389 | @ html "<a href='$home/setup_ulist'>Users</a>\n" |
| 390 | @ } |
| 391 | @ if {[info exists login]} { |
| 392 | @ html "<a href='$home/login'>Logout</a>\n" |
| 393 | @ } else { |
| 394 | @ html "<a href='$home/login'>Login</a>\n" |
| 395 | @ } |
| 396 | @ </th1></div> |
| 397 | ; |
| 398 | |
| 399 | /* |
| @@ -428,10 +428,11 @@ | |
| 428 | @ text-align: center; |
| 429 | @ vertical-align: bottom; |
| 430 | @ font-weight: bold; |
| 431 | @ color: #558195; |
| 432 | @ min-width: 200px; |
| 433 | @ white-space: nowrap; |
| 434 | @ } |
| 435 | @ |
| 436 | @ /* The page title centered at the top of each page */ |
| 437 | @ div.title { |
| 438 | @ display: table-cell; |
| 439 |
+49
-3
| --- src/timeline.c | ||
| +++ src/timeline.c | ||
| @@ -257,11 +257,11 @@ | ||
| 257 | 257 | } |
| 258 | 258 | } |
| 259 | 259 | prevTagid = tagid; |
| 260 | 260 | if( suppressCnt ){ |
| 261 | 261 | @ <span class="timelineDisabled">... %d(suppressCnt) similar |
| 262 | - @ event%s(suppressCnt>1?"s":"") omitted.</span></td></tr> | |
| 262 | + @ event%s(suppressCnt>1?"s":"") omitted.</span> | |
| 263 | 263 | suppressCnt = 0; |
| 264 | 264 | } |
| 265 | 265 | if( pendingEndTr ){ |
| 266 | 266 | @ </td></tr> |
| 267 | 267 | pendingEndTr = 0; |
| @@ -373,11 +373,11 @@ | ||
| 373 | 373 | /* Generate the "user: USERNAME" at the end of the comment, together |
| 374 | 374 | ** with a hyperlink to another timeline for that user. |
| 375 | 375 | */ |
| 376 | 376 | if( zTagList && zTagList[0]==0 ) zTagList = 0; |
| 377 | 377 | if( g.perm.Hyperlink && fossil_strcmp(zUser, zThisUser)!=0 ){ |
| 378 | - char *zLink = mprintf("%R/timeline?u=%h&c=%t&nd", zUser, zDate); | |
| 378 | + char *zLink = mprintf("%R/timeline?u=%h&c=%t&nd", zUser, zDate); | |
| 379 | 379 | @ (user: %z(href("%z",zLink))%h(zUser)</a>%s(zTagList?",":"\051") |
| 380 | 380 | }else{ |
| 381 | 381 | @ (user: %h(zUser)%s(zTagList?",":"\051") |
| 382 | 382 | } |
| 383 | 383 | |
| @@ -477,11 +477,11 @@ | ||
| 477 | 477 | } |
| 478 | 478 | pendingEndTr = 1; |
| 479 | 479 | } |
| 480 | 480 | if( suppressCnt ){ |
| 481 | 481 | @ <span class="timelineDisabled">... %d(suppressCnt) similar |
| 482 | - @ event%s(suppressCnt>1?"s":"") omitted.</span></td></tr> | |
| 482 | + @ event%s(suppressCnt>1?"s":"") omitted.</span> | |
| 483 | 483 | suppressCnt = 0; |
| 484 | 484 | } |
| 485 | 485 | if( pendingEndTr ){ |
| 486 | 486 | @ </td></tr> |
| 487 | 487 | } |
| @@ -878,10 +878,34 @@ | ||
| 878 | 878 | rDate+ONE_SECOND |
| 879 | 879 | ); |
| 880 | 880 | fossil_free(zToDel); |
| 881 | 881 | } |
| 882 | 882 | |
| 883 | +/* | |
| 884 | +** Return all possible names for file zUuid. | |
| 885 | +*/ | |
| 886 | +char *names_of_file(const char *zUuid){ | |
| 887 | + Stmt q; | |
| 888 | + Blob out; | |
| 889 | + const char *zSep = ""; | |
| 890 | + db_prepare(&q, | |
| 891 | + "SELECT DISTINCT filename.name FROM mlink, filename" | |
| 892 | + " WHERE mlink.fid=(SELECT rid FROM blob WHERE uuid='%s')" | |
| 893 | + " AND filename.fnid=mlink.fnid", | |
| 894 | + zUuid | |
| 895 | + ); | |
| 896 | + blob_zero(&out); | |
| 897 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 898 | + const char *zFN = db_column_text(&q, 0); | |
| 899 | + blob_appendf(&out, "%s%z%h</a>", zSep, | |
| 900 | + href("%R/finfo?name=%t", zFN), zFN); | |
| 901 | + zSep = " or "; | |
| 902 | + } | |
| 903 | + db_finalize(&q); | |
| 904 | + return blob_str(&out); | |
| 905 | +} | |
| 906 | + | |
| 883 | 907 | |
| 884 | 908 | /* |
| 885 | 909 | ** WEBPAGE: timeline |
| 886 | 910 | ** |
| 887 | 911 | ** Query parameters: |
| @@ -930,10 +954,11 @@ | ||
| 930 | 954 | const char *zBefore = P("b"); /* Events before this time */ |
| 931 | 955 | const char *zCirca = P("c"); /* Events near this time */ |
| 932 | 956 | const char *zTagName = P("t"); /* Show events with this tag */ |
| 933 | 957 | const char *zBrName = P("r"); /* Show events related to this tag */ |
| 934 | 958 | const char *zSearch = P("s"); /* Search string */ |
| 959 | + const char *zUses = P("uf"); /* Only show checkins hold this file */ | |
| 935 | 960 | int useDividers = P("nd")==0; /* Show dividers if "nd" is missing */ |
| 936 | 961 | int tagid; /* Tag ID */ |
| 937 | 962 | int tmFlags; /* Timeline flags */ |
| 938 | 963 | const char *zThisTag = 0; /* Suppress links to this tag */ |
| 939 | 964 | const char *zThisUser = 0; /* Suppress links to this user */ |
| @@ -981,10 +1006,22 @@ | ||
| 981 | 1006 | url_add_parameter(&url, "brbg", 0); |
| 982 | 1007 | } |
| 983 | 1008 | if( P("ubg")!=0 ){ |
| 984 | 1009 | tmFlags |= TIMELINE_UCOLOR; |
| 985 | 1010 | url_add_parameter(&url, "ubg", 0); |
| 1011 | + } | |
| 1012 | + if( zUses!=0 ){ | |
| 1013 | + int ufid = db_int(0, "SELECT rid FROM blob WHERE uuid GLOB '%q*'", zUses); | |
| 1014 | + if( ufid ){ | |
| 1015 | + zUses = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", ufid); | |
| 1016 | + url_add_parameter(&url, "uf", zUses); | |
| 1017 | + db_multi_exec("CREATE TEMP TABLE usesfile(rid INTEGER PRIMARY KEY)"); | |
| 1018 | + compute_uses_file("usesfile", ufid, 0); | |
| 1019 | + zType = "ci"; | |
| 1020 | + }else{ | |
| 1021 | + zUses = 0; | |
| 1022 | + } | |
| 986 | 1023 | } |
| 987 | 1024 | |
| 988 | 1025 | style_header("Timeline"); |
| 989 | 1026 | login_anonymous_available(); |
| 990 | 1027 | timeline_temp_table(); |
| @@ -1085,10 +1122,13 @@ | ||
| 1085 | 1122 | int n; |
| 1086 | 1123 | const char *zEType = "timeline item"; |
| 1087 | 1124 | char *zDate; |
| 1088 | 1125 | char *zNEntry = mprintf("%d", nEntry); |
| 1089 | 1126 | url_add_parameter(&url, "n", zNEntry); |
| 1127 | + if( zUses ){ | |
| 1128 | + blob_appendf(&sql, " AND event.objid IN usesfile "); | |
| 1129 | + } | |
| 1090 | 1130 | if( tagid>0 ){ |
| 1091 | 1131 | blob_appendf(&sql, |
| 1092 | 1132 | "AND (EXISTS(SELECT 1 FROM tagxref" |
| 1093 | 1133 | " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid)", tagid); |
| 1094 | 1134 | |
| @@ -1220,10 +1260,16 @@ | ||
| 1220 | 1260 | if( zAfter==0 && zBefore==0 && zCirca==0 ){ |
| 1221 | 1261 | blob_appendf(&desc, "%d most recent %ss", n, zEType); |
| 1222 | 1262 | }else{ |
| 1223 | 1263 | blob_appendf(&desc, "%d %ss", n, zEType); |
| 1224 | 1264 | } |
| 1265 | + if( zUses ){ | |
| 1266 | + char *zFilenames = names_of_file(zUses); | |
| 1267 | + blob_appendf(&desc, " using file %s version %z%S</a>", zFilenames, | |
| 1268 | + href("%R/artifact/%S",zUses), zUses); | |
| 1269 | + tmFlags |= TIMELINE_DISJOINT; | |
| 1270 | + } | |
| 1225 | 1271 | if( zUser ){ |
| 1226 | 1272 | blob_appendf(&desc, " by user %h", zUser); |
| 1227 | 1273 | tmFlags |= TIMELINE_DISJOINT; |
| 1228 | 1274 | } |
| 1229 | 1275 | if( zTagName ){ |
| 1230 | 1276 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -257,11 +257,11 @@ | |
| 257 | } |
| 258 | } |
| 259 | prevTagid = tagid; |
| 260 | if( suppressCnt ){ |
| 261 | @ <span class="timelineDisabled">... %d(suppressCnt) similar |
| 262 | @ event%s(suppressCnt>1?"s":"") omitted.</span></td></tr> |
| 263 | suppressCnt = 0; |
| 264 | } |
| 265 | if( pendingEndTr ){ |
| 266 | @ </td></tr> |
| 267 | pendingEndTr = 0; |
| @@ -373,11 +373,11 @@ | |
| 373 | /* Generate the "user: USERNAME" at the end of the comment, together |
| 374 | ** with a hyperlink to another timeline for that user. |
| 375 | */ |
| 376 | if( zTagList && zTagList[0]==0 ) zTagList = 0; |
| 377 | if( g.perm.Hyperlink && fossil_strcmp(zUser, zThisUser)!=0 ){ |
| 378 | char *zLink = mprintf("%R/timeline?u=%h&c=%t&nd", zUser, zDate); |
| 379 | @ (user: %z(href("%z",zLink))%h(zUser)</a>%s(zTagList?",":"\051") |
| 380 | }else{ |
| 381 | @ (user: %h(zUser)%s(zTagList?",":"\051") |
| 382 | } |
| 383 | |
| @@ -477,11 +477,11 @@ | |
| 477 | } |
| 478 | pendingEndTr = 1; |
| 479 | } |
| 480 | if( suppressCnt ){ |
| 481 | @ <span class="timelineDisabled">... %d(suppressCnt) similar |
| 482 | @ event%s(suppressCnt>1?"s":"") omitted.</span></td></tr> |
| 483 | suppressCnt = 0; |
| 484 | } |
| 485 | if( pendingEndTr ){ |
| 486 | @ </td></tr> |
| 487 | } |
| @@ -878,10 +878,34 @@ | |
| 878 | rDate+ONE_SECOND |
| 879 | ); |
| 880 | fossil_free(zToDel); |
| 881 | } |
| 882 | |
| 883 | |
| 884 | /* |
| 885 | ** WEBPAGE: timeline |
| 886 | ** |
| 887 | ** Query parameters: |
| @@ -930,10 +954,11 @@ | |
| 930 | const char *zBefore = P("b"); /* Events before this time */ |
| 931 | const char *zCirca = P("c"); /* Events near this time */ |
| 932 | const char *zTagName = P("t"); /* Show events with this tag */ |
| 933 | const char *zBrName = P("r"); /* Show events related to this tag */ |
| 934 | const char *zSearch = P("s"); /* Search string */ |
| 935 | int useDividers = P("nd")==0; /* Show dividers if "nd" is missing */ |
| 936 | int tagid; /* Tag ID */ |
| 937 | int tmFlags; /* Timeline flags */ |
| 938 | const char *zThisTag = 0; /* Suppress links to this tag */ |
| 939 | const char *zThisUser = 0; /* Suppress links to this user */ |
| @@ -981,10 +1006,22 @@ | |
| 981 | url_add_parameter(&url, "brbg", 0); |
| 982 | } |
| 983 | if( P("ubg")!=0 ){ |
| 984 | tmFlags |= TIMELINE_UCOLOR; |
| 985 | url_add_parameter(&url, "ubg", 0); |
| 986 | } |
| 987 | |
| 988 | style_header("Timeline"); |
| 989 | login_anonymous_available(); |
| 990 | timeline_temp_table(); |
| @@ -1085,10 +1122,13 @@ | |
| 1085 | int n; |
| 1086 | const char *zEType = "timeline item"; |
| 1087 | char *zDate; |
| 1088 | char *zNEntry = mprintf("%d", nEntry); |
| 1089 | url_add_parameter(&url, "n", zNEntry); |
| 1090 | if( tagid>0 ){ |
| 1091 | blob_appendf(&sql, |
| 1092 | "AND (EXISTS(SELECT 1 FROM tagxref" |
| 1093 | " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid)", tagid); |
| 1094 | |
| @@ -1220,10 +1260,16 @@ | |
| 1220 | if( zAfter==0 && zBefore==0 && zCirca==0 ){ |
| 1221 | blob_appendf(&desc, "%d most recent %ss", n, zEType); |
| 1222 | }else{ |
| 1223 | blob_appendf(&desc, "%d %ss", n, zEType); |
| 1224 | } |
| 1225 | if( zUser ){ |
| 1226 | blob_appendf(&desc, " by user %h", zUser); |
| 1227 | tmFlags |= TIMELINE_DISJOINT; |
| 1228 | } |
| 1229 | if( zTagName ){ |
| 1230 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -257,11 +257,11 @@ | |
| 257 | } |
| 258 | } |
| 259 | prevTagid = tagid; |
| 260 | if( suppressCnt ){ |
| 261 | @ <span class="timelineDisabled">... %d(suppressCnt) similar |
| 262 | @ event%s(suppressCnt>1?"s":"") omitted.</span> |
| 263 | suppressCnt = 0; |
| 264 | } |
| 265 | if( pendingEndTr ){ |
| 266 | @ </td></tr> |
| 267 | pendingEndTr = 0; |
| @@ -373,11 +373,11 @@ | |
| 373 | /* Generate the "user: USERNAME" at the end of the comment, together |
| 374 | ** with a hyperlink to another timeline for that user. |
| 375 | */ |
| 376 | if( zTagList && zTagList[0]==0 ) zTagList = 0; |
| 377 | if( g.perm.Hyperlink && fossil_strcmp(zUser, zThisUser)!=0 ){ |
| 378 | char *zLink = mprintf("%R/timeline?u=%h&c=%t&nd", zUser, zDate); |
| 379 | @ (user: %z(href("%z",zLink))%h(zUser)</a>%s(zTagList?",":"\051") |
| 380 | }else{ |
| 381 | @ (user: %h(zUser)%s(zTagList?",":"\051") |
| 382 | } |
| 383 | |
| @@ -477,11 +477,11 @@ | |
| 477 | } |
| 478 | pendingEndTr = 1; |
| 479 | } |
| 480 | if( suppressCnt ){ |
| 481 | @ <span class="timelineDisabled">... %d(suppressCnt) similar |
| 482 | @ event%s(suppressCnt>1?"s":"") omitted.</span> |
| 483 | suppressCnt = 0; |
| 484 | } |
| 485 | if( pendingEndTr ){ |
| 486 | @ </td></tr> |
| 487 | } |
| @@ -878,10 +878,34 @@ | |
| 878 | rDate+ONE_SECOND |
| 879 | ); |
| 880 | fossil_free(zToDel); |
| 881 | } |
| 882 | |
| 883 | /* |
| 884 | ** Return all possible names for file zUuid. |
| 885 | */ |
| 886 | char *names_of_file(const char *zUuid){ |
| 887 | Stmt q; |
| 888 | Blob out; |
| 889 | const char *zSep = ""; |
| 890 | db_prepare(&q, |
| 891 | "SELECT DISTINCT filename.name FROM mlink, filename" |
| 892 | " WHERE mlink.fid=(SELECT rid FROM blob WHERE uuid='%s')" |
| 893 | " AND filename.fnid=mlink.fnid", |
| 894 | zUuid |
| 895 | ); |
| 896 | blob_zero(&out); |
| 897 | while( db_step(&q)==SQLITE_ROW ){ |
| 898 | const char *zFN = db_column_text(&q, 0); |
| 899 | blob_appendf(&out, "%s%z%h</a>", zSep, |
| 900 | href("%R/finfo?name=%t", zFN), zFN); |
| 901 | zSep = " or "; |
| 902 | } |
| 903 | db_finalize(&q); |
| 904 | return blob_str(&out); |
| 905 | } |
| 906 | |
| 907 | |
| 908 | /* |
| 909 | ** WEBPAGE: timeline |
| 910 | ** |
| 911 | ** Query parameters: |
| @@ -930,10 +954,11 @@ | |
| 954 | const char *zBefore = P("b"); /* Events before this time */ |
| 955 | const char *zCirca = P("c"); /* Events near this time */ |
| 956 | const char *zTagName = P("t"); /* Show events with this tag */ |
| 957 | const char *zBrName = P("r"); /* Show events related to this tag */ |
| 958 | const char *zSearch = P("s"); /* Search string */ |
| 959 | const char *zUses = P("uf"); /* Only show checkins hold this file */ |
| 960 | int useDividers = P("nd")==0; /* Show dividers if "nd" is missing */ |
| 961 | int tagid; /* Tag ID */ |
| 962 | int tmFlags; /* Timeline flags */ |
| 963 | const char *zThisTag = 0; /* Suppress links to this tag */ |
| 964 | const char *zThisUser = 0; /* Suppress links to this user */ |
| @@ -981,10 +1006,22 @@ | |
| 1006 | url_add_parameter(&url, "brbg", 0); |
| 1007 | } |
| 1008 | if( P("ubg")!=0 ){ |
| 1009 | tmFlags |= TIMELINE_UCOLOR; |
| 1010 | url_add_parameter(&url, "ubg", 0); |
| 1011 | } |
| 1012 | if( zUses!=0 ){ |
| 1013 | int ufid = db_int(0, "SELECT rid FROM blob WHERE uuid GLOB '%q*'", zUses); |
| 1014 | if( ufid ){ |
| 1015 | zUses = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", ufid); |
| 1016 | url_add_parameter(&url, "uf", zUses); |
| 1017 | db_multi_exec("CREATE TEMP TABLE usesfile(rid INTEGER PRIMARY KEY)"); |
| 1018 | compute_uses_file("usesfile", ufid, 0); |
| 1019 | zType = "ci"; |
| 1020 | }else{ |
| 1021 | zUses = 0; |
| 1022 | } |
| 1023 | } |
| 1024 | |
| 1025 | style_header("Timeline"); |
| 1026 | login_anonymous_available(); |
| 1027 | timeline_temp_table(); |
| @@ -1085,10 +1122,13 @@ | |
| 1122 | int n; |
| 1123 | const char *zEType = "timeline item"; |
| 1124 | char *zDate; |
| 1125 | char *zNEntry = mprintf("%d", nEntry); |
| 1126 | url_add_parameter(&url, "n", zNEntry); |
| 1127 | if( zUses ){ |
| 1128 | blob_appendf(&sql, " AND event.objid IN usesfile "); |
| 1129 | } |
| 1130 | if( tagid>0 ){ |
| 1131 | blob_appendf(&sql, |
| 1132 | "AND (EXISTS(SELECT 1 FROM tagxref" |
| 1133 | " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid)", tagid); |
| 1134 | |
| @@ -1220,10 +1260,16 @@ | |
| 1260 | if( zAfter==0 && zBefore==0 && zCirca==0 ){ |
| 1261 | blob_appendf(&desc, "%d most recent %ss", n, zEType); |
| 1262 | }else{ |
| 1263 | blob_appendf(&desc, "%d %ss", n, zEType); |
| 1264 | } |
| 1265 | if( zUses ){ |
| 1266 | char *zFilenames = names_of_file(zUses); |
| 1267 | blob_appendf(&desc, " using file %s version %z%S</a>", zFilenames, |
| 1268 | href("%R/artifact/%S",zUses), zUses); |
| 1269 | tmFlags |= TIMELINE_DISJOINT; |
| 1270 | } |
| 1271 | if( zUser ){ |
| 1272 | blob_appendf(&desc, " by user %h", zUser); |
| 1273 | tmFlags |= TIMELINE_DISJOINT; |
| 1274 | } |
| 1275 | if( zTagName ){ |
| 1276 |
+9
-9
| --- src/xfer.c | ||
| +++ src/xfer.c | ||
| @@ -273,19 +273,15 @@ | ||
| 273 | 273 | Blob *pUuid /* The UUID of the file to send */ |
| 274 | 274 | ){ |
| 275 | 275 | static const char *const azQuery[] = { |
| 276 | 276 | "SELECT pid FROM plink x" |
| 277 | 277 | " WHERE cid=%d" |
| 278 | - " AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=pid)" | |
| 279 | - " AND NOT EXISTS(SELECT 1 FROM plink y" | |
| 280 | - " WHERE y.pid=x.cid AND y.cid=x.pid)", | |
| 281 | - | |
| 282 | - "SELECT pid FROM mlink x" | |
| 278 | + " AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=pid)", | |
| 279 | + | |
| 280 | + "SELECT pid, min(mtime) FROM mlink, event ON mlink.mid=event.objid" | |
| 283 | 281 | " WHERE fid=%d" |
| 284 | 282 | " AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=pid)" |
| 285 | - " AND NOT EXISTS(SELECT 1 FROM mlink y" | |
| 286 | - " WHERE y.pid=x.fid AND y.fid=x.pid)" | |
| 287 | 283 | }; |
| 288 | 284 | int i; |
| 289 | 285 | Blob src, delta; |
| 290 | 286 | int size = 0; |
| 291 | 287 | int srcId = 0; |
| @@ -303,11 +299,11 @@ | ||
| 303 | 299 | if( size>=blob_size(pContent)-50 ){ |
| 304 | 300 | size = 0; |
| 305 | 301 | }else if( uuid_is_shunned(zUuid) ){ |
| 306 | 302 | size = 0; |
| 307 | 303 | }else{ |
| 308 | - if( isPrivate ) blob_append(pXfer->pOut, "private\n", -1); | |
| 304 | + if( isPrivate ) blob_append(pXfer->pOut, "private\n", -1); | |
| 309 | 305 | blob_appendf(pXfer->pOut, "file %b %s %d\n", pUuid, zUuid, size); |
| 310 | 306 | blob_append(pXfer->pOut, blob_buffer(&delta), size); |
| 311 | 307 | } |
| 312 | 308 | blob_reset(&delta); |
| 313 | 309 | free(zUuid); |
| @@ -1659,11 +1655,15 @@ | ||
| 1659 | 1655 | ** to the next cycle. |
| 1660 | 1656 | */ |
| 1661 | 1657 | if( blob_eq(&xfer.aToken[0],"message") && xfer.nToken==2 ){ |
| 1662 | 1658 | char *zMsg = blob_terminate(&xfer.aToken[1]); |
| 1663 | 1659 | defossilize(zMsg); |
| 1664 | - if( zMsg ) fossil_print("\rServer says: %s\n", zMsg); | |
| 1660 | + if( pushFlag && zMsg && strglob("pull only *", zMsg) ){ | |
| 1661 | + pushFlag = 0; | |
| 1662 | + zMsg = 0; | |
| 1663 | + } | |
| 1664 | + fossil_print("\rServer says: %s\n", zMsg); | |
| 1665 | 1665 | }else |
| 1666 | 1666 | |
| 1667 | 1667 | /* pragma NAME VALUE... |
| 1668 | 1668 | ** |
| 1669 | 1669 | ** The server can send pragmas to try to convey meta-information to |
| 1670 | 1670 |
| --- src/xfer.c | |
| +++ src/xfer.c | |
| @@ -273,19 +273,15 @@ | |
| 273 | Blob *pUuid /* The UUID of the file to send */ |
| 274 | ){ |
| 275 | static const char *const azQuery[] = { |
| 276 | "SELECT pid FROM plink x" |
| 277 | " WHERE cid=%d" |
| 278 | " AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=pid)" |
| 279 | " AND NOT EXISTS(SELECT 1 FROM plink y" |
| 280 | " WHERE y.pid=x.cid AND y.cid=x.pid)", |
| 281 | |
| 282 | "SELECT pid FROM mlink x" |
| 283 | " WHERE fid=%d" |
| 284 | " AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=pid)" |
| 285 | " AND NOT EXISTS(SELECT 1 FROM mlink y" |
| 286 | " WHERE y.pid=x.fid AND y.fid=x.pid)" |
| 287 | }; |
| 288 | int i; |
| 289 | Blob src, delta; |
| 290 | int size = 0; |
| 291 | int srcId = 0; |
| @@ -303,11 +299,11 @@ | |
| 303 | if( size>=blob_size(pContent)-50 ){ |
| 304 | size = 0; |
| 305 | }else if( uuid_is_shunned(zUuid) ){ |
| 306 | size = 0; |
| 307 | }else{ |
| 308 | if( isPrivate ) blob_append(pXfer->pOut, "private\n", -1); |
| 309 | blob_appendf(pXfer->pOut, "file %b %s %d\n", pUuid, zUuid, size); |
| 310 | blob_append(pXfer->pOut, blob_buffer(&delta), size); |
| 311 | } |
| 312 | blob_reset(&delta); |
| 313 | free(zUuid); |
| @@ -1659,11 +1655,15 @@ | |
| 1659 | ** to the next cycle. |
| 1660 | */ |
| 1661 | if( blob_eq(&xfer.aToken[0],"message") && xfer.nToken==2 ){ |
| 1662 | char *zMsg = blob_terminate(&xfer.aToken[1]); |
| 1663 | defossilize(zMsg); |
| 1664 | if( zMsg ) fossil_print("\rServer says: %s\n", zMsg); |
| 1665 | }else |
| 1666 | |
| 1667 | /* pragma NAME VALUE... |
| 1668 | ** |
| 1669 | ** The server can send pragmas to try to convey meta-information to |
| 1670 |
| --- src/xfer.c | |
| +++ src/xfer.c | |
| @@ -273,19 +273,15 @@ | |
| 273 | Blob *pUuid /* The UUID of the file to send */ |
| 274 | ){ |
| 275 | static const char *const azQuery[] = { |
| 276 | "SELECT pid FROM plink x" |
| 277 | " WHERE cid=%d" |
| 278 | " AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=pid)", |
| 279 | |
| 280 | "SELECT pid, min(mtime) FROM mlink, event ON mlink.mid=event.objid" |
| 281 | " WHERE fid=%d" |
| 282 | " AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=pid)" |
| 283 | }; |
| 284 | int i; |
| 285 | Blob src, delta; |
| 286 | int size = 0; |
| 287 | int srcId = 0; |
| @@ -303,11 +299,11 @@ | |
| 299 | if( size>=blob_size(pContent)-50 ){ |
| 300 | size = 0; |
| 301 | }else if( uuid_is_shunned(zUuid) ){ |
| 302 | size = 0; |
| 303 | }else{ |
| 304 | if( isPrivate ) blob_append(pXfer->pOut, "private\n", -1); |
| 305 | blob_appendf(pXfer->pOut, "file %b %s %d\n", pUuid, zUuid, size); |
| 306 | blob_append(pXfer->pOut, blob_buffer(&delta), size); |
| 307 | } |
| 308 | blob_reset(&delta); |
| 309 | free(zUuid); |
| @@ -1659,11 +1655,15 @@ | |
| 1655 | ** to the next cycle. |
| 1656 | */ |
| 1657 | if( blob_eq(&xfer.aToken[0],"message") && xfer.nToken==2 ){ |
| 1658 | char *zMsg = blob_terminate(&xfer.aToken[1]); |
| 1659 | defossilize(zMsg); |
| 1660 | if( pushFlag && zMsg && strglob("pull only *", zMsg) ){ |
| 1661 | pushFlag = 0; |
| 1662 | zMsg = 0; |
| 1663 | } |
| 1664 | fossil_print("\rServer says: %s\n", zMsg); |
| 1665 | }else |
| 1666 | |
| 1667 | /* pragma NAME VALUE... |
| 1668 | ** |
| 1669 | ** The server can send pragmas to try to convey meta-information to |
| 1670 |
+1
-1
| --- win/Makefile.mingw.mistachkin | ||
| +++ win/Makefile.mingw.mistachkin | ||
| @@ -112,11 +112,11 @@ | ||
| 112 | 112 | # will run on the target platform. This is usually the same |
| 113 | 113 | # as BCC, unless you are cross-compiling. This C compiler builds |
| 114 | 114 | # the finished binary for fossil. The BCC compiler above is used |
| 115 | 115 | # for building intermediate code-generator tools. |
| 116 | 116 | # |
| 117 | -TCC = $(PREFIX)gcc -Os -Wall -L$(ZLIBDIR) -I$(ZINCDIR) | |
| 117 | +TCC = $(PREFIX)gcc -g -Os -Wall -L$(ZLIBDIR) -I$(ZINCDIR) | |
| 118 | 118 | |
| 119 | 119 | #### Compile resources for use in building executables that will run |
| 120 | 120 | # on the target platform. |
| 121 | 121 | # |
| 122 | 122 | RCC = $(PREFIX)windres -I$(SRCDIR) -I$(ZINCDIR) |
| 123 | 123 |
| --- win/Makefile.mingw.mistachkin | |
| +++ win/Makefile.mingw.mistachkin | |
| @@ -112,11 +112,11 @@ | |
| 112 | # will run on the target platform. This is usually the same |
| 113 | # as BCC, unless you are cross-compiling. This C compiler builds |
| 114 | # the finished binary for fossil. The BCC compiler above is used |
| 115 | # for building intermediate code-generator tools. |
| 116 | # |
| 117 | TCC = $(PREFIX)gcc -Os -Wall -L$(ZLIBDIR) -I$(ZINCDIR) |
| 118 | |
| 119 | #### Compile resources for use in building executables that will run |
| 120 | # on the target platform. |
| 121 | # |
| 122 | RCC = $(PREFIX)windres -I$(SRCDIR) -I$(ZINCDIR) |
| 123 |
| --- win/Makefile.mingw.mistachkin | |
| +++ win/Makefile.mingw.mistachkin | |
| @@ -112,11 +112,11 @@ | |
| 112 | # will run on the target platform. This is usually the same |
| 113 | # as BCC, unless you are cross-compiling. This C compiler builds |
| 114 | # the finished binary for fossil. The BCC compiler above is used |
| 115 | # for building intermediate code-generator tools. |
| 116 | # |
| 117 | TCC = $(PREFIX)gcc -g -Os -Wall -L$(ZLIBDIR) -I$(ZINCDIR) |
| 118 | |
| 119 | #### Compile resources for use in building executables that will run |
| 120 | # on the target platform. |
| 121 | # |
| 122 | RCC = $(PREFIX)windres -I$(SRCDIR) -I$(ZINCDIR) |
| 123 |