Fossil SCM

merge trunk

jan.nijtmans 2012-11-17 20:19 UTC convert_before_commit merge
Commit 7e7dcdd2c9b6be29078470de7c42a55694338c0b
--- src/descendants.c
+++ src/descendants.c
@@ -441,5 +441,71 @@
441441
@ function xout(id){
442442
@ }
443443
@ </script>
444444
style_footer();
445445
}
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
+
446512
--- 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 @@
19811981
Blob toAnnotate; /* Text of the final (mid) version of the file */
19821982
Blob step; /* Text of previous revision */
19831983
int rid; /* Artifact ID of the file being annotated */
19841984
char *zLabel; /* Label to apply to a line */
19851985
Stmt q; /* Query returning all ancestor versions */
1986
+ int cnt = 0; /* Number of versions examined */
19861987
19871988
/* Initialize the annotation */
19881989
rid = db_int(0, "SELECT fid FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid);
19891990
if( rid==0 ){
19901991
fossil_panic("file #%d is unchanged in manifest #%d", fnid, mid);
19911992
}
19921993
if( !content_get(rid, &toAnnotate) ){
19931994
fossil_panic("unable to retrieve content of artifact #%d", rid);
19941995
}
1995
- db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)");
19961996
if( iLimit<=0 ) iLimit = 1000000000;
1997
- compute_direct_ancestors(mid, iLimit);
19981997
annotation_start(p, &toAnnotate);
1999
-
1998
+
20001999
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"
20142009
);
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);
20202018
if( webLabel ){
20212019
zLabel = mprintf(
20222020
"<a href='%R/info/%s' target='infowindow'>%.10s</a> %s %13.13s",
20232021
zUuid, zUuid, zDate, zUser
20242022
);
@@ -2026,13 +2024,17 @@
20262024
zLabel = mprintf("%.10s %s %13.13s", zUuid, zDate, zUser);
20272025
}
20282026
p->nVers++;
20292027
p->azVers = fossil_realloc(p->azVers, p->nVers*sizeof(p->azVers[0]) );
20302028
p->azVers[p->nVers-1] = zLabel;
2031
- content_get(pid, &step);
2029
+ content_get(rid, &step);
20322030
annotation_step(p, &step, zLabel);
20332031
blob_reset(&step);
2032
+ db_reset(&q);
2033
+ rid = prevId;
2034
+ db_bind_int(&q, ":rid", prevId);
2035
+ cnt++;
20342036
}
20352037
db_finalize(&q);
20362038
}
20372039
20382040
/*
20392041
--- 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 @@
204204
db_finalize(&q);
205205
blob_reset(&fname);
206206
}
207207
}
208208
209
+/* Values for the debug= query parameter to finfo */
210
+#define FINFO_DEBUG_MLINK 0x01
209211
210212
/*
211213
** WEBPAGE: finfo
212214
** URL: /finfo?name=FILENAME
213215
**
@@ -227,17 +229,19 @@
227229
const char *zFilename;
228230
char zPrevDate[20];
229231
const char *zA;
230232
const char *zB;
231233
int n;
234
+
232235
Blob title;
233236
Blob sql;
234237
HQuery url;
235238
GraphContext *pGraph;
236239
int brBg = P("brbg")!=0;
237240
int uBg = P("ubg")!=0;
238241
int firstChngOnly = atoi(PD("fco","1"))!=0;
242
+ int fDebug = atoi(PD("debug","0"));
239243
240244
login_check_credentials();
241245
if( !g.perm.Read ){ login_needed(); return; }
242246
style_header("File History");
243247
login_anonymous_available();
@@ -260,11 +264,13 @@
260264
" (SELECT uuid FROM blob WHERE rid=mlink.pid)," /* Parent file uuid */
261265
" (SELECT uuid FROM blob WHERE rid=mlink.fid)," /* Current file uuid */
262266
" (SELECT uuid FROM blob WHERE rid=mlink.mid)," /* Check-in uuid */
263267
" event.bgcolor," /* Background color */
264268
" (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 */
266272
TAG_BRANCH
267273
);
268274
if( firstChngOnly ){
269275
blob_appendf(&sql, ", min(event.mtime)");
270276
}
@@ -316,10 +322,12 @@
316322
const char *zPUuid = db_column_text(&q, 5);
317323
const char *zUuid = db_column_text(&q, 6);
318324
const char *zCkin = db_column_text(&q,7);
319325
const char *zBgClr = db_column_text(&q, 8);
320326
const char *zBr = db_column_text(&q, 9);
327
+ int fmid = db_column_int(&q, 10);
328
+ int pfnid = db_column_int(&q, 11);
321329
int gidx;
322330
char zTime[10];
323331
char zShort[20];
324332
char zShortCkin[20];
325333
if( zBr==0 ) zBr = "trunk";
@@ -346,13 +354,34 @@
346354
@ <td class="timelineTableCell">
347355
}
348356
sqlite3_snprintf(sizeof(zShort), zShort, "%.10s", zUuid);
349357
sqlite3_snprintf(sizeof(zShortCkin), zShortCkin, "%.10s", zCkin);
350358
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
+ }
351367
@ %z(href("%R/artifact/%s",zUuid))[%S(zUuid)]</a> part of check-in
352368
}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
+ }
354383
}
355384
hyperlink_to_uuid(zShortCkin);
356385
@ %h(zCom) (user:
357386
hyperlink_to_user(zUser, zDate, "");
358387
@ branch: %h(zBr))
@@ -361,10 +390,14 @@
361390
if( fpid ){
362391
@ %z(href("%R/fdiff?v1=%S&v2=%S",zPUuid,zUuid))[diff]</a>
363392
}
364393
@ %z(href("%R/annotate?checkin=%S&filename=%h",zCkin,z))
365394
@ [annotate]</a>
395
+ @ %z(href("%R/timeline?n=200&uf=%S",zUuid))[checkins&nbsp;using]</a>
396
+ }
397
+ if( fDebug & FINFO_DEBUG_MLINK ){
398
+ @ fid=%d(frid), pid=%d(fpid), mid=%d(fmid)
366399
}
367400
@ </td></tr>
368401
}
369402
db_finalize(&q);
370403
if( pGraph ){
371404
--- 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&nbsp;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
--- src/http_transport.c
+++ src/http_transport.c
@@ -97,10 +97,84 @@
9797
#ifdef __MINGW32__
9898
static char zDefaultSshCmd[] = "ssh -T";
9999
#else
100100
static char zDefaultSshCmd[] = "ssh -e none -T";
101101
#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
+}
102176
103177
/*
104178
** Global initialization of the transport layer
105179
*/
106180
void transport_global_startup(void){
@@ -109,13 +183,10 @@
109183
** and run an SSH command to talk to the remote machine.
110184
*/
111185
const char *zSsh; /* The base SSH command */
112186
Blob zCmd; /* The SSH command */
113187
char *zHost; /* The host name to contact */
114
- char *zIn; /* An input line received back from remote */
115
- unsigned iRandom;
116
- char zProbe[30];
117188
118189
zSsh = db_get("ssh-command", zDefaultSshCmd);
119190
blob_init(&zCmd, zSsh, -1);
120191
if( g.urlPort!=g.urlDfltPort ){
121192
#ifdef __MINGW32__
@@ -156,28 +227,11 @@
156227
popen2(blob_str(&zCmd), &sshIn, &sshOut, &sshPid);
157228
if( sshPid==0 ){
158229
fossil_fatal("cannot start ssh tunnel using [%b]", &zCmd);
159230
}
160231
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();
179233
}
180234
}
181235
182236
/*
183237
** Open a connection to the server. The server is defined by the following
184238
--- 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 @@
15971597
@ <h2>Artifact %s(zUuid):</h2>
15981598
}
15991599
blob_zero(&downloadName);
16001600
objType = object_description(rid, 0, &downloadName);
16011601
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
+ }
16031607
asText = P("txt")!=0;
16041608
zMime = mimetype_from_name(blob_str(&downloadName));
16051609
if( zMime ){
16061610
if( fossil_strcmp(zMime, "text/html")==0 ){
16071611
if( asText ){
16081612
--- 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 @@
129129
int fSqlStats; /* True if --sqltrace or --sqlstats are present */
130130
int fSqlPrint; /* True if -sqlprint flag is present */
131131
int fQuiet; /* True if -quiet flag is present */
132132
int fHttpTrace; /* Trace outbound HTTP requests */
133133
int fSystemTrace; /* Trace calls to fossil_system(), --systemtrace */
134
+ int fSshTrace; /* Trace the SSH setup traffic */
134135
int fNoSync; /* Do not do an autosync even. --nosync */
135136
char *zPath; /* Name of webpage being served */
136137
char *zExtra; /* Extra path information past the webpage name */
137138
char *zBaseURL; /* Full text of the URL being served */
138139
char *zTop; /* Parent directory of zPath */
@@ -611,10 +612,11 @@
611612
g.isHTTP = 0;
612613
g.fQuiet = find_option("quiet", 0, 0)!=0;
613614
g.fSqlTrace = find_option("sqltrace", 0, 0)!=0;
614615
g.fSqlStats = find_option("sqlstats", 0, 0)!=0;
615616
g.fSystemTrace = find_option("systemtrace", 0, 0)!=0;
617
+ g.fSshTrace = find_option("sshtrace", 0, 0)!=0;
616618
if( g.fSqlTrace ) g.fSqlStats = 1;
617619
g.fSqlPrint = find_option("sqlprint", 0, 0)!=0;
618620
g.fHttpTrace = find_option("httptrace", 0, 0)!=0;
619621
g.zLogin = find_option("user", "U", 1);
620622
g.zSSLIdentity = find_option("ssl-identity", 0, 1);
@@ -1379,27 +1381,39 @@
13791381
while( 1 ){
13801382
while( zPathInfo[i] && zPathInfo[i]!='/' ){ i++; }
13811383
zRepo = zToFree = mprintf("%s%.*s.fossil",g.zRepositoryName,i,zPathInfo);
13821384
13831385
/* 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 ".".
13851388
*/
13861389
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
+ ){
13881394
zRepo[j] = '_';
13891395
}
13901396
}
13911397
if( zRepo[0]=='/' && zRepo[1]=='/' ){ zRepo++; j--; }
13921398
13931399
szFile = file_size(zRepo);
1394
- if( zPathInfo[i]=='/' && szFile<0 ){
1400
+ if( szFile<0 ){
13951401
assert( fossil_strcmp(&zRepo[j], ".fossil")==0 );
13961402
zRepo[j] = 0;
1397
- if( file_isdir(zRepo)==1 ){
1403
+ if( zPathInfo[i]=='/' && file_isdir(zRepo)==1 ){
13981404
fossil_free(zToFree);
13991405
i++;
14001406
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;
14011415
}
14021416
zRepo[j] = '.';
14031417
}
14041418
14051419
if( szFile<1024 ){
@@ -1740,13 +1754,17 @@
17401754
** is disallowed.
17411755
*/
17421756
static void find_server_repository(int disallowDir){
17431757
if( g.argc<3 ){
17441758
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
+ }
17481766
}else{
17491767
db_open_repository(g.argv[2]);
17501768
}
17511769
}
17521770
@@ -1934,11 +1952,11 @@
19341952
isUiCmd = g.argv[1][0]=='u';
19351953
if( isUiCmd ){
19361954
flags |= HTTP_SERVER_LOCALHOST;
19371955
g.useLocalauth = 1;
19381956
}
1939
- find_server_repository(isUiCmd);
1957
+ find_server_repository(isUiCmd && zNotFound==0);
19401958
if( zPort ){
19411959
iPort = mxPort = atoi(zPort);
19421960
}else{
19431961
iPort = db_get_int("http-port", 8080);
19441962
mxPort = iPort+100;
@@ -1973,11 +1991,11 @@
19731991
g.httpOut = stdout;
19741992
if( g.fHttpTrace || g.fSqlTrace ){
19751993
fprintf(stderr, "====== SERVER pid %d =======\n", getpid());
19761994
}
19771995
g.cgiOutput = 1;
1978
- find_server_repository(isUiCmd);
1996
+ find_server_repository(isUiCmd && zNotFound==0);
19791997
g.zRepositoryName = enter_chroot_jail(g.zRepositoryName);
19801998
cgi_handle_http_request(0);
19811999
process_one_web_page(zNotFound);
19822000
#else
19832001
/* Win32 implementation */
19842002
--- 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 @@
4444
@ font-size: 2em;
4545
@ font-weight: bold;
4646
@ background-color: #707070;
4747
@ color: #ffffff;
4848
@ min-width: 200px;
49
+@ white-space: nowrap;
4950
@ }
5051
@
5152
@ /* The page title centered at the top of each page */
5253
@ div.title {
5354
@ display: table-cell;
@@ -67,10 +68,11 @@
6768
@ vertical-align: bottom;
6869
@ color: #404040;
6970
@ font-size: 0.8em;
7071
@ font-weight: bold;
7172
@ min-width: 200px;
73
+@ white-space: nowrap;
7274
@ }
7375
@
7476
@ /* The header across the top of the page */
7577
@ div.header {
7678
@ display: table;
@@ -125,10 +127,11 @@
125127
@ padding: 1px 1px 1px 1px;
126128
@ font-size: 1.2em;
127129
@ font-weight: bold;
128130
@ background-color: #404040;
129131
@ color: white;
132
+@ white-space: nowrap;
130133
@ }
131134
@
132135
@ /* The "Date" that occurs on the left hand side of timelines */
133136
@ div.divider {
134137
@ background: #a0a0a0;
@@ -136,10 +139,11 @@
136139
@ font-size: 1em; font-weight: normal;
137140
@ padding: .25em;
138141
@ margin: .2em 0 .2em 0;
139142
@ float: left;
140143
@ clear: left;
144
+@ white-space: nowrap;
141145
@ }
142146
@
143147
@ /* The footer at the very bottom of the page */
144148
@ div.footer {
145149
@ font-size: 0.8em;
@@ -166,17 +170,17 @@
166170
@ media="screen">
167171
@ </head>
168172
@ <body>
169173
@ <div class="header">
170174
@ <div class="title"><small>$<project_name></small><br />$<title></div>
171
-@ <div class="status"><nobr><th1>
175
+@ <div class="status"><th1>
172176
@ if {[info exists login]} {
173177
@ puts "Logged in as $login"
174178
@ } else {
175179
@ puts "Not logged in"
176180
@ }
177
-@ </th1></nobr></div>
181
+@ </th1></div>
178182
@ </div>
179183
@ <div class="mainmenu">
180184
@ <th1>
181185
@ html "<a href=''$home$index_page''>Home</a>\n"
182186
@ if {[anycap jor]} {
@@ -235,10 +239,11 @@
235239
@ text-align: center;
236240
@ vertical-align: bottom;
237241
@ font-weight: bold;
238242
@ font-size: 2.5em;
239243
@ color: #a09048;
244
+@ white-space: nowrap;
240245
@ }
241246
@
242247
@ /* The page title centered at the top of each page */
243248
@ div.title {
244249
@ display: table-cell;
@@ -258,10 +263,11 @@
258263
@ vertical-align: bottom;
259264
@ color: #a09048;
260265
@ padding: 5px 5px 0 0;
261266
@ font-size: 0.8em;
262267
@ font-weight: bold;
268
+@ white-space: nowrap;
263269
@ }
264270
@
265271
@ /* The header across the top of the page */
266272
@ div.header {
267273
@ display: table;
@@ -316,10 +322,11 @@
316322
@ padding: 3px 3px 0 3px;
317323
@ font-size: 1.2em;
318324
@ font-weight: bold;
319325
@ background-color: #a09048;
320326
@ color: white;
327
+@ white-space: nowrap;
321328
@ }
322329
@
323330
@ /* The "Date" that occurs on the left hand side of timelines */
324331
@ div.divider {
325332
@ background: #e1d498;
@@ -327,10 +334,11 @@
327334
@ font-size: 1em; font-weight: normal;
328335
@ padding: .25em;
329336
@ margin: .2em 0 .2em 0;
330337
@ float: left;
331338
@ clear: left;
339
+@ white-space: nowrap;
332340
@ }
333341
@
334342
@ /* The footer at the very bottom of the page */
335343
@ div.footer {
336344
@ font-size: 0.8em;
@@ -370,18 +378,18 @@
370378
@ </head>
371379
@ <body>
372380
@ <div class="header">
373381
@ <div class="title">$<title></div>
374382
@ <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>
377385
@ if {[info exists login]} {
378386
@ puts "Logged in as $login"
379387
@ } else {
380388
@ puts "Not logged in"
381389
@ }
382
-@ </th1></nobr></div>
390
+@ </th1></div>
383391
@ </div>
384392
@ <div class="mainmenu">
385393
@ <th1>
386394
@ html "<a href=''$home$index_page''>Home</a>\n"
387395
@ if {[anycap jor]} {
@@ -448,10 +456,11 @@
448456
@ display: table-cell;
449457
@ text-align: left;
450458
@ vertical-align: bottom;
451459
@ font-weight: bold;
452460
@ color: #333;
461
+@ white-space: nowrap;
453462
@ }
454463
@
455464
@ /* The page title centered at the top of each page */
456465
@ div.title {
457466
@ display: table-cell;
@@ -471,10 +480,11 @@
471480
@ vertical-align: bottom;
472481
@ padding-bottom: 5px;
473482
@ color: #333;
474483
@ font-size: 0.8em;
475484
@ font-weight: bold;
485
+@ white-space: nowrap;
476486
@ }
477487
@
478488
@ /* The header across the top of the page */
479489
@ div.header {
480490
@ margin:10px 0px 10px 0px;
@@ -557,10 +567,11 @@
557567
@ border-style:solid;
558568
@ border-color:#999;
559569
@ border-width:1px 0px;
560570
@ background-color: #eee;
561571
@ color: #333;
572
+@ white-space: nowrap;
562573
@ }
563574
@
564575
@ /* The "Date" that occurs on the left hand side of timelines */
565576
@ div.divider {
566577
@ background: #eee;
@@ -568,11 +579,12 @@
568579
@ font-size: 1em; font-weight: normal;
569580
@ padding: .25em;
570581
@ margin: .2em 0 .2em 0;
571582
@ float: left;
572583
@ clear: left;
573
-@ color: #333
584
+@ color: #333;
585
+@ white-space: nowrap;
574586
@ }
575587
@
576588
@ /* The footer at the very bottom of the page */
577589
@ div.footer {
578590
@ font-size: 0.8em;
@@ -606,20 +618,20 @@
606618
@ </head>
607619
@ <body>
608620
@ <div class="header">
609621
@ <div class="logo">
610622
@ <img src="$home/logo" alt="logo">
611
-@ <br /><nobr>$<project_name></nobr>
623
+@ <br />$<project_name>
612624
@ </div>
613625
@ <div class="title">$<title></div>
614
-@ <div class="status"><nobr><th1>
626
+@ <div class="status"><th1>
615627
@ if {[info exists login]} {
616628
@ puts "Logged in as $login"
617629
@ } else {
618630
@ puts "Not logged in"
619631
@ }
620
-@ </th1></nobr></div>
632
+@ </th1></div>
621633
@ </div>
622634
@ <div class="mainmenu">
623635
@ <th1>
624636
@ html "<a href=''$home$index_page''>Home</a>\n"
625637
@ if {[anycap jor]} {
@@ -682,10 +694,11 @@
682694
@ div.logo {
683695
@ display: table-cell;
684696
@ text-align: right;
685697
@ vertical-align: bottom;
686698
@ font-weight: normal;
699
+@ white-space: nowrap;
687700
@ }
688701
@
689702
@ /* Widths */
690703
@ div.header, div.mainmenu, div.submenu, div.content, div.footer {
691704
@ max-width: 900px;
@@ -714,10 +727,11 @@
714727
@ display: table-cell;
715728
@ text-align: right;
716729
@ vertical-align: bottom;
717730
@ color: #333;
718731
@ margin-right: -20px;
732
+@ white-space: nowrap;
719733
@ }
720734
@
721735
@ /* The main menu bar that appears at the top of the page beneath
722736
@ ** the header */
723737
@ div.mainmenu {
@@ -793,10 +807,11 @@
793807
@ text-align: center;
794808
@ color: white;
795809
@ border-radius: 5px;
796810
@ background-color: #446979;
797811
@ box-shadow: 0px 3px 4px #333333;
812
+@ white-space: nowrap;
798813
@ }
799814
@
800815
@ /* The "Date" that occurs on the left hand side of timelines */
801816
@ div.divider {
802817
@ font-size: 1.2em;
@@ -869,20 +884,20 @@
869884
@ </head>
870885
@ <body>
871886
@ <div class="header">
872887
@ <div class="logo">
873888
@ <img src="$home/logo" alt="logo">
874
-@ <br /><nobr>$<project_name></nobr>
889
+@ <br />$<project_name>
875890
@ </div>
876891
@ <div class="title">$<title></div>
877
-@ <div class="status"><nobr><th1>
892
+@ <div class="status"><th1>
878893
@ if {[info exists login]} {
879894
@ puts "Logged in as $login"
880895
@ } else {
881896
@ puts "Not logged in"
882897
@ }
883
-@ </th1></nobr></div>
898
+@ </th1></div>
884899
@ </div>
885900
@ <div class="mainmenu">
886901
@ <th1>
887902
@ html "<a href=''$home$index_page''>Home</a>\n"
888903
@ if {[anycap jor]} {
@@ -955,10 +970,11 @@
955970
@ text-align: center;
956971
@ vertical-align: bottom;
957972
@ font-weight: bold;
958973
@ color: #558195;
959974
@ min-width: 200px;
975
+@ white-space: nowrap;
960976
@ }
961977
@
962978
@ /* The page title centered at the top of each page */
963979
@ div.title {
964980
@ display: table-cell;
@@ -1159,46 +1175,46 @@
11591175
@ <a href="$logourl">
11601176
@ <img src="$baseurl/logo" border="0" alt="$project_name">
11611177
@ </a>
11621178
@ </div>
11631179
@ <div class="title"><small>$<project_name></small><br />$<title></div>
1164
-@ <div class="status"><nobr><th1>
1180
+@ <div class="status"><th1>
11651181
@ if {[info exists login]} {
11661182
@ puts "Logged in as $login"
11671183
@ } else {
11681184
@ puts "Not logged in"
11691185
@ }
1170
-@ </th1></nobr></div>
1186
+@ </th1></div>
11711187
@ </div>
11721188
@ <div class="mainmenu">
11731189
@ <th1>
11741190
@ html "<a href=''$home$index_page''>Home</a>\n"
11751191
@ if {[anycap jor]} {
1176
-@ html "<a href=''timeline''>Timeline</a>\n"
1192
+@ html "<a href=''$home/timeline''>Timeline</a>\n"
11771193
@ }
11781194
@ if {[hascap oh]} {
1179
-@ html "<a href=''dir?ci=tip''>Files</a>\n"
1195
+@ html "<a href=''$home/dir?ci=tip''>Files</a>\n"
11801196
@ }
11811197
@ 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"
11841200
@ }
11851201
@ if {[hascap r]} {
1186
-@ html "<a href=''reportlist''>Tickets</a>\n"
1202
+@ html "<a href=''$home/reportlist''>Tickets</a>\n"
11871203
@ }
11881204
@ if {[hascap j]} {
1189
-@ html "<a href=''wiki''>Wiki</a>\n"
1205
+@ html "<a href=''$home/wiki''>Wiki</a>\n"
11901206
@ }
11911207
@ if {[hascap s]} {
1192
-@ html "<a href=''setup''>Admin</a>\n"
1208
+@ html "<a href=''$home/setup''>Admin</a>\n"
11931209
@ } elseif {[hascap a]} {
1194
-@ html "<a href=''setup_ulist''>Users</a>\n"
1210
+@ html "<a href=''$home/setup_ulist''>Users</a>\n"
11951211
@ }
11961212
@ if {[info exists login]} {
1197
-@ html "<a href=''login''>Logout</a>\n"
1213
+@ html "<a href=''$home/login''>Logout</a>\n"
11981214
@ } else {
1199
-@ html "<a href=''login''>Login</a>\n"
1215
+@ html "<a href=''$home/login''>Login</a>\n"
12001216
@ }
12011217
@ </th1></div>
12021218
@ ');
12031219
@ REPLACE INTO config(name,mtime,value)
12041220
@ VALUES('footer',now(),'<div class="footer">
12051221
--- 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 @@
366366
@ </div>
367367
@ <div class="mainmenu">
368368
@ <th1>
369369
@ html "<a href='$home$index_page'>Home</a>\n"
370370
@ if {[anycap jor]} {
371
-@ html "<a href='timeline'>Timeline</a>\n"
371
+@ html "<a href='$home/timeline'>Timeline</a>\n"
372372
@ }
373373
@ if {[hascap oh]} {
374
-@ html "<a href='dir?ci=tip'>Files</a>\n"
374
+@ html "<a href='$home/dir?ci=tip'>Files</a>\n"
375375
@ }
376376
@ 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"
379379
@ }
380380
@ if {[hascap r]} {
381
-@ html "<a href='reportlist'>Tickets</a>\n"
381
+@ html "<a href='$home/reportlist'>Tickets</a>\n"
382382
@ }
383383
@ if {[hascap j]} {
384
-@ html "<a href='wiki'>Wiki</a>\n"
384
+@ html "<a href='$home/wiki'>Wiki</a>\n"
385385
@ }
386386
@ if {[hascap s]} {
387
-@ html "<a href='setup'>Admin</a>\n"
387
+@ html "<a href='$home/setup'>Admin</a>\n"
388388
@ } elseif {[hascap a]} {
389
-@ html "<a href='setup_ulist'>Users</a>\n"
389
+@ html "<a href='$home/setup_ulist'>Users</a>\n"
390390
@ }
391391
@ if {[info exists login]} {
392
-@ html "<a href='login'>Logout</a>\n"
392
+@ html "<a href='$home/login'>Logout</a>\n"
393393
@ } else {
394
-@ html "<a href='login'>Login</a>\n"
394
+@ html "<a href='$home/login'>Login</a>\n"
395395
@ }
396396
@ </th1></div>
397397
;
398398
399399
/*
@@ -428,10 +428,11 @@
428428
@ text-align: center;
429429
@ vertical-align: bottom;
430430
@ font-weight: bold;
431431
@ color: #558195;
432432
@ min-width: 200px;
433
+@ white-space: nowrap;
433434
@ }
434435
@
435436
@ /* The page title centered at the top of each page */
436437
@ div.title {
437438
@ display: table-cell;
438439
--- 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 @@
257257
}
258258
}
259259
prevTagid = tagid;
260260
if( suppressCnt ){
261261
@ <span class="timelineDisabled">... %d(suppressCnt) similar
262
- @ event%s(suppressCnt>1?"s":"") omitted.</span></td></tr>
262
+ @ event%s(suppressCnt>1?"s":"") omitted.</span>
263263
suppressCnt = 0;
264264
}
265265
if( pendingEndTr ){
266266
@ </td></tr>
267267
pendingEndTr = 0;
@@ -373,11 +373,11 @@
373373
/* Generate the "user: USERNAME" at the end of the comment, together
374374
** with a hyperlink to another timeline for that user.
375375
*/
376376
if( zTagList && zTagList[0]==0 ) zTagList = 0;
377377
if( g.perm.Hyperlink && fossil_strcmp(zUser, zThisUser)!=0 ){
378
- char *zLink = mprintf("%R/timeline?u=%h&c=%t&amp;nd", zUser, zDate);
378
+ char *zLink = mprintf("%R/timeline?u=%h&c=%t&nd", zUser, zDate);
379379
@ (user: %z(href("%z",zLink))%h(zUser)</a>%s(zTagList?",":"\051")
380380
}else{
381381
@ (user: %h(zUser)%s(zTagList?",":"\051")
382382
}
383383
@@ -477,11 +477,11 @@
477477
}
478478
pendingEndTr = 1;
479479
}
480480
if( suppressCnt ){
481481
@ <span class="timelineDisabled">... %d(suppressCnt) similar
482
- @ event%s(suppressCnt>1?"s":"") omitted.</span></td></tr>
482
+ @ event%s(suppressCnt>1?"s":"") omitted.</span>
483483
suppressCnt = 0;
484484
}
485485
if( pendingEndTr ){
486486
@ </td></tr>
487487
}
@@ -878,10 +878,34 @@
878878
rDate+ONE_SECOND
879879
);
880880
fossil_free(zToDel);
881881
}
882882
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
+
883907
884908
/*
885909
** WEBPAGE: timeline
886910
**
887911
** Query parameters:
@@ -930,10 +954,11 @@
930954
const char *zBefore = P("b"); /* Events before this time */
931955
const char *zCirca = P("c"); /* Events near this time */
932956
const char *zTagName = P("t"); /* Show events with this tag */
933957
const char *zBrName = P("r"); /* Show events related to this tag */
934958
const char *zSearch = P("s"); /* Search string */
959
+ const char *zUses = P("uf"); /* Only show checkins hold this file */
935960
int useDividers = P("nd")==0; /* Show dividers if "nd" is missing */
936961
int tagid; /* Tag ID */
937962
int tmFlags; /* Timeline flags */
938963
const char *zThisTag = 0; /* Suppress links to this tag */
939964
const char *zThisUser = 0; /* Suppress links to this user */
@@ -981,10 +1006,22 @@
9811006
url_add_parameter(&url, "brbg", 0);
9821007
}
9831008
if( P("ubg")!=0 ){
9841009
tmFlags |= TIMELINE_UCOLOR;
9851010
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
+ }
9861023
}
9871024
9881025
style_header("Timeline");
9891026
login_anonymous_available();
9901027
timeline_temp_table();
@@ -1085,10 +1122,13 @@
10851122
int n;
10861123
const char *zEType = "timeline item";
10871124
char *zDate;
10881125
char *zNEntry = mprintf("%d", nEntry);
10891126
url_add_parameter(&url, "n", zNEntry);
1127
+ if( zUses ){
1128
+ blob_appendf(&sql, " AND event.objid IN usesfile ");
1129
+ }
10901130
if( tagid>0 ){
10911131
blob_appendf(&sql,
10921132
"AND (EXISTS(SELECT 1 FROM tagxref"
10931133
" WHERE tagid=%d AND tagtype>0 AND rid=blob.rid)", tagid);
10941134
@@ -1220,10 +1260,16 @@
12201260
if( zAfter==0 && zBefore==0 && zCirca==0 ){
12211261
blob_appendf(&desc, "%d most recent %ss", n, zEType);
12221262
}else{
12231263
blob_appendf(&desc, "%d %ss", n, zEType);
12241264
}
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
+ }
12251271
if( zUser ){
12261272
blob_appendf(&desc, " by user %h", zUser);
12271273
tmFlags |= TIMELINE_DISJOINT;
12281274
}
12291275
if( zTagName ){
12301276
--- 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&amp;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 @@
273273
Blob *pUuid /* The UUID of the file to send */
274274
){
275275
static const char *const azQuery[] = {
276276
"SELECT pid FROM plink x"
277277
" 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"
283281
" WHERE fid=%d"
284282
" 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)"
287283
};
288284
int i;
289285
Blob src, delta;
290286
int size = 0;
291287
int srcId = 0;
@@ -303,11 +299,11 @@
303299
if( size>=blob_size(pContent)-50 ){
304300
size = 0;
305301
}else if( uuid_is_shunned(zUuid) ){
306302
size = 0;
307303
}else{
308
- if( isPrivate ) blob_append(pXfer->pOut, "private\n", -1);
304
+ if( isPrivate ) blob_append(pXfer->pOut, "private\n", -1);
309305
blob_appendf(pXfer->pOut, "file %b %s %d\n", pUuid, zUuid, size);
310306
blob_append(pXfer->pOut, blob_buffer(&delta), size);
311307
}
312308
blob_reset(&delta);
313309
free(zUuid);
@@ -1659,11 +1655,15 @@
16591655
** to the next cycle.
16601656
*/
16611657
if( blob_eq(&xfer.aToken[0],"message") && xfer.nToken==2 ){
16621658
char *zMsg = blob_terminate(&xfer.aToken[1]);
16631659
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);
16651665
}else
16661666
16671667
/* pragma NAME VALUE...
16681668
**
16691669
** The server can send pragmas to try to convey meta-information to
16701670
--- 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
--- win/Makefile.mingw.mistachkin
+++ win/Makefile.mingw.mistachkin
@@ -112,11 +112,11 @@
112112
# will run on the target platform. This is usually the same
113113
# as BCC, unless you are cross-compiling. This C compiler builds
114114
# the finished binary for fossil. The BCC compiler above is used
115115
# for building intermediate code-generator tools.
116116
#
117
-TCC = $(PREFIX)gcc -Os -Wall -L$(ZLIBDIR) -I$(ZINCDIR)
117
+TCC = $(PREFIX)gcc -g -Os -Wall -L$(ZLIBDIR) -I$(ZINCDIR)
118118
119119
#### Compile resources for use in building executables that will run
120120
# on the target platform.
121121
#
122122
RCC = $(PREFIX)windres -I$(SRCDIR) -I$(ZINCDIR)
123123
--- 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

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button