Fossil

Check-in [07f6780c98]
Login

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

Overview
Comment:Remove unsupported and incomplete webpage functionality: The admin_sql page and the "my" page.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 07f6780c981a2a69fadac09d51dff77c7d11ec43
User & Date: drh 2009-08-16 21:34:30.000
Context
2009-08-16
22:04
Add a small colored rendering of the logo image. check-in: 93992def02 user: drh tags: trunk
21:34
Remove unsupported and incomplete webpage functionality: The admin_sql page and the "my" page. check-in: 07f6780c98 user: drh tags: trunk
21:22
Cleanup of the "admin_sql" web page (formerly "admin/sql"). check-in: ef432c2014 user: drh tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Deleted src/admin.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
/*
** Copyright (c) 2007 D. Richard Hipp
** Copyright (c) 2008 Stephan Beal
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public
** License as published by the Free Software Foundation; either
** version 2 of the License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
** General Public License for more details.
**
** You should have received a copy of the GNU General Public
** License along with this library; if not, write to the
** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
** Boston, MA  02111-1307, USA.
**
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*******************************************************************************
**
** Implementation of the Admin SQL
*/
#include <assert.h>
#include "config.h"
#include "admin.h"

/*
** This SQLite authorizer callback prevents any SQL other than
** SELECT statements from running.
*/
static int selectOnly(
  void *NotUsed,           /* Application data - not used */
  int type,                /* Operation type */
  const char *zArg1,       /* Arguments.... */
  const char *zArg2,
  const char *zArg3,
  const char *zArg4
){
  int rc = SQLITE_DENY;
  switch( type ){
    case SQLITE_READ: {
      if( strcmp(zArg2,"pw")==0 ){
        rc = SQLITE_IGNORE;
      }else{
        rc = SQLITE_OK;
      }
      break;
    }
    case SQLITE_FUNCTION:
    case SQLITE_SELECT: {
      rc = SQLITE_OK;
      break;
    }
  }
  return rc;
}

/*
** WEBPAGE: admin_sql
*/
void admin_sql_page(void){
  const char *zSql = PD("sql","");
  login_check_credentials();
  if( !g.okAdmin ){
    login_needed();
    return;
  }
  style_header("Admin SQL");
  @ <h2>SQL:</h2>
  @ You can enter only SELECT statements here, and some SQL-side functions
  @ are also restricted.<br/>
  @ <form action='' method='post'>
  login_insert_csrf_secret();
  @ <textarea style='border:2px solid black' name='sql'
  @  cols='80' rows='5'>%h(zSql)</textarea>
  @ <br/><input type='submit' name='sql_submit'/> <input type='reset'/>
  @ </form>
  if( zSql[0] ){
    login_verify_csrf_secret();
    sqlite3_set_authorizer(g.db, selectOnly, 0);
    db_generic_query_view(zSql, 0);
    sqlite3_set_authorizer(g.db, 0, 0);
  }
  style_footer();
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




















































































































































































Changes to src/db.c.
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
    }else{
      print_setting(azName[i]);
    }
  }else{
    usage("?PROPERTY? ?VALUE?");
  }
}

/*
** SQL function to render a UUID as a hyperlink to a page describing
** that UUID.
*/
static void hyperlinkUuidFunc(
  sqlite3_context *pCxt,     /* function context */
  int argc,                  /* number of arguments to the function */
  sqlite3_value **argv       /* values of all function arguments */
){
  const char *zUuid;         /* The UUID to render */
  char *z;                   /* Rendered HTML text */

  zUuid = (const char*)sqlite3_value_text(argv[0]);
  if( g.okHistory && zUuid && strlen(zUuid)>=10 ){
    z = mprintf("<tt><a href='%s/info/%t'><span style='font-size:1.5em'>"
                "%#h</span>%h</a></tt>",
                g.zBaseURL, zUuid, 10, zUuid, &zUuid[10]);
    sqlite3_result_text(pCxt, z, -1, free);
  }else{
    sqlite3_result_text(pCxt, zUuid, -1, SQLITE_TRANSIENT);
  }
}

/*
** SQL function to render a TAGID as a hyperlink to a page describing
** that tag.
*/
static void hyperlinkTagidFunc(
  sqlite3_context *pCxt,     /* function context */
  int argc,                  /* number of arguments to the function */
  sqlite3_value **argv       /* values of all function arguments */
){
  int tagid;                 /* The tagid to render */
  char *z;                   /* rendered html text */

  tagid = sqlite3_value_int(argv[0]);
  if( g.okHistory ){
    z = mprintf("<a href='%s/tagview?tagid=%d'>%d</a>", 
                  g.zBaseURL, tagid, tagid);
  }else{
    z = mprintf("%d", tagid);
  }
  sqlite3_result_text(pCxt, z, -1, free);
}

/*
** SQL function to render a TAGNAME as a hyperlink to a page describing
** that tag.
*/
static void hyperlinkTagnameFunc(
  sqlite3_context *pCxt,     /* function context */
  int argc,                  /* number of arguments to the function */
  sqlite3_value **argv       /* values of all function arguments */
){
  const char *zTag;          /* The tag to render */
  char *z;                   /* rendered html text */

  zTag = (const char*)sqlite3_value_text(argv[0]);
  if( g.okHistory ){
    z = mprintf("<a href='%s/tagview?name=%T&raw=y'>%h</a>", 
                  g.zBaseURL, zTag, zTag);
  }else{
    z = mprintf("%h", zTag);
  }
  sqlite3_result_text(pCxt, z, -1, free);
}

/*
** SQL function to escape all characters in a string that have special
** meaning to HTML.
*/
static void htmlizeFunc(
  sqlite3_context *pCxt,     /* function context */
  int argc,                  /* number of arguments to the function */
  sqlite3_value **argv       /* values of all function arguments */
){
  const char *zText;         /* Text to be htmlized */
  char *z;                   /* rendered html text */

  zText = (const char*)sqlite3_value_text(argv[0]);
  z = htmlize(zText, -1);
  sqlite3_result_text(pCxt, z, -1, free);
}

/*
** This routine is a helper to run an SQL query and table-ize the
** results.
**
** The zSql parameter should be a single, complete SQL statement.
** Tableized output of the SQL statement is rendered back to the client.
**
** The isSafe flag is true if all query results have been processed 
** by routines such as
**
**        linkuuid()
**        linktagid()
**        linktagname()
**        htmlize()
**
** and are therefore safe for direct rendering.  If isSafe is false,
** then all characters in the query result that have special meaning
** to HTML are escaped.
**
** Returns SQLITE_OK on success and any other value on error.
*/
int db_generic_query_view(const char *zSql, int isSafe){
  sqlite3_stmt *pStmt;
  int rc;
  int nCol, i;
  int nRow;
  const char *zRow;
  static int once = 1;

  /* Install the special functions on the first call to this routine */
  if( once ){
    once = 0;
    sqlite3_create_function(g.db, "linkuuid", 1, SQLITE_UTF8, 0, 
                            hyperlinkUuidFunc, 0, 0);
    sqlite3_create_function(g.db, "linktagid", 1, SQLITE_UTF8, 0, 
                            hyperlinkTagidFunc, 0, 0);
    sqlite3_create_function(g.db, "linktagname", 1, SQLITE_UTF8, 0, 
                            hyperlinkTagnameFunc, 0, 0);
    sqlite3_create_function(g.db, "htmlize", 1, SQLITE_UTF8, 0, 
                            htmlizeFunc, 0, 0);
  }

  /*
  ** Use sqlite3_stmt directly rather than going through db_prepare(),
  ** so that we can treat errors a non-fatal.
  */
  rc = sqlite3_prepare(g.db, zSql, -1, &pStmt, 0);
  if( SQLITE_OK != rc ){
    @ <span style='color:red'>db_generic_query_view() SQL error:
    @ %h(sqlite3_errmsg(g.db))</span>
    return rc;
  }
  nCol = sqlite3_column_count(pStmt);
  @ <table class='fossil_db_generic_query_view'><tbody>
  @ <tr class='header'>
  for(i=0; i<nCol; ++i){
    @ <td>%h(sqlite3_column_name(pStmt,i))</td>
  }
  @ </tr>

  nRow = 0;
  while( SQLITE_ROW==sqlite3_step(pStmt) ){
    const char *azClass[] = { "even", "odd" };
    @ <tr class='%s(azClass[(nRow++)&1])'>
      for(i=0; i<nCol; i++){
        zRow = (char const*)sqlite3_column_text(pStmt,i);
        if( isSafe ){
          @ <td>%s(zRow)</td>
        }else{
          @ <td>%h(zRow)</td>
        }
      }
    @ </tr>
  }
  @ </tbody></table>
  sqlite3_finalize(pStmt);
  return SQLITE_OK;
}







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
1512
1513
1514
1515
1516
1517
1518



































































































































































    }else{
      print_setting(azName[i]);
    }
  }else{
    usage("?PROPERTY? ?VALUE?");
  }
}



































































































































































Changes to src/login.c.
101
102
103
104
105
106
107
108
109

110
111





112
113
114
115
116
117
118
  if( strcasecmp(zPw, zPassword)!=0 ) return 0;
  uid = db_int(0, "SELECT uid FROM user WHERE login='anonymous'"
                  " AND length(pw)>0 AND length(cap)>0");
  return uid;
}

/*
** WEBPAGE: /login
** WEBPAGE: /logout

**
** Generate the login page





*/
void login_page(void){
  const char *zUsername, *zPasswd;
  const char *zNew1, *zNew2;
  const char *zAnonPw = 0;
  int anonFlag;
  char *zErrMsg = "";







|
|
>

|
>
>
>
>
>







101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
  if( strcasecmp(zPw, zPassword)!=0 ) return 0;
  uid = db_int(0, "SELECT uid FROM user WHERE login='anonymous'"
                  " AND length(pw)>0 AND length(cap)>0");
  return uid;
}

/*
** WEBPAGE: login
** WEBPAGE: logout
** WEBPAGE: my
**
** Generate the login page.
**
** There used to be a page named "my" that was designed to show information
** about a specific user.  The "my" page was linked from the "Logged in as USER"
** line on the title bar.  The "my" page was never completed so it is now
** removed.  Use this page as a placeholder in older installations.
*/
void login_page(void){
  const char *zUsername, *zPasswd;
  const char *zNew1, *zNew2;
  const char *zAnonPw = 0;
  int anonFlag;
  char *zErrMsg = "";
Changes to src/main.mk.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#

XTCC = $(TCC) $(CFLAGS) -I. -I$(SRCDIR)


SRC = \
  $(SRCDIR)/add.c \
  $(SRCDIR)/admin.c \
  $(SRCDIR)/allrepo.c \
  $(SRCDIR)/bag.c \
  $(SRCDIR)/blob.c \
  $(SRCDIR)/branch.c \
  $(SRCDIR)/browse.c \
  $(SRCDIR)/captcha.c \
  $(SRCDIR)/cgi.c \







<







10
11
12
13
14
15
16

17
18
19
20
21
22
23
#

XTCC = $(TCC) $(CFLAGS) -I. -I$(SRCDIR)


SRC = \
  $(SRCDIR)/add.c \

  $(SRCDIR)/allrepo.c \
  $(SRCDIR)/bag.c \
  $(SRCDIR)/blob.c \
  $(SRCDIR)/branch.c \
  $(SRCDIR)/browse.c \
  $(SRCDIR)/captcha.c \
  $(SRCDIR)/cgi.c \
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
  $(SRCDIR)/info.c \
  $(SRCDIR)/login.c \
  $(SRCDIR)/main.c \
  $(SRCDIR)/manifest.c \
  $(SRCDIR)/md5.c \
  $(SRCDIR)/merge.c \
  $(SRCDIR)/merge3.c \
  $(SRCDIR)/my_page.c \
  $(SRCDIR)/name.c \
  $(SRCDIR)/pivot.c \
  $(SRCDIR)/pqueue.c \
  $(SRCDIR)/printf.c \
  $(SRCDIR)/rebuild.c \
  $(SRCDIR)/report.c \
  $(SRCDIR)/rss.c \
  $(SRCDIR)/rstats.c \
  $(SRCDIR)/schema.c \
  $(SRCDIR)/setup.c \
  $(SRCDIR)/sha1.c \
  $(SRCDIR)/shun.c \
  $(SRCDIR)/stat.c \
  $(SRCDIR)/style.c \
  $(SRCDIR)/sync.c \
  $(SRCDIR)/tag.c \
  $(SRCDIR)/tagview.c \
  $(SRCDIR)/th_main.c \
  $(SRCDIR)/timeline.c \
  $(SRCDIR)/tkt.c \
  $(SRCDIR)/tktsetup.c \
  $(SRCDIR)/undo.c \
  $(SRCDIR)/update.c \
  $(SRCDIR)/url.c \
  $(SRCDIR)/user.c \
  $(SRCDIR)/verify.c \
  $(SRCDIR)/vfile.c \
  $(SRCDIR)/wiki.c \
  $(SRCDIR)/wikiformat.c \
  $(SRCDIR)/winhttp.c \
  $(SRCDIR)/xfer.c \
  $(SRCDIR)/zip.c

TRANS_SRC = \
  add_.c \
  admin_.c \
  allrepo_.c \
  bag_.c \
  blob_.c \
  branch_.c \
  browse_.c \
  captcha_.c \
  cgi_.c \







<
















<


















<







44
45
46
47
48
49
50

51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66

67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84

85
86
87
88
89
90
91
  $(SRCDIR)/info.c \
  $(SRCDIR)/login.c \
  $(SRCDIR)/main.c \
  $(SRCDIR)/manifest.c \
  $(SRCDIR)/md5.c \
  $(SRCDIR)/merge.c \
  $(SRCDIR)/merge3.c \

  $(SRCDIR)/name.c \
  $(SRCDIR)/pivot.c \
  $(SRCDIR)/pqueue.c \
  $(SRCDIR)/printf.c \
  $(SRCDIR)/rebuild.c \
  $(SRCDIR)/report.c \
  $(SRCDIR)/rss.c \
  $(SRCDIR)/rstats.c \
  $(SRCDIR)/schema.c \
  $(SRCDIR)/setup.c \
  $(SRCDIR)/sha1.c \
  $(SRCDIR)/shun.c \
  $(SRCDIR)/stat.c \
  $(SRCDIR)/style.c \
  $(SRCDIR)/sync.c \
  $(SRCDIR)/tag.c \

  $(SRCDIR)/th_main.c \
  $(SRCDIR)/timeline.c \
  $(SRCDIR)/tkt.c \
  $(SRCDIR)/tktsetup.c \
  $(SRCDIR)/undo.c \
  $(SRCDIR)/update.c \
  $(SRCDIR)/url.c \
  $(SRCDIR)/user.c \
  $(SRCDIR)/verify.c \
  $(SRCDIR)/vfile.c \
  $(SRCDIR)/wiki.c \
  $(SRCDIR)/wikiformat.c \
  $(SRCDIR)/winhttp.c \
  $(SRCDIR)/xfer.c \
  $(SRCDIR)/zip.c

TRANS_SRC = \
  add_.c \

  allrepo_.c \
  bag_.c \
  blob_.c \
  branch_.c \
  browse_.c \
  captcha_.c \
  cgi_.c \
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
  info_.c \
  login_.c \
  main_.c \
  manifest_.c \
  md5_.c \
  merge_.c \
  merge3_.c \
  my_page_.c \
  name_.c \
  pivot_.c \
  pqueue_.c \
  printf_.c \
  rebuild_.c \
  report_.c \
  rss_.c \
  rstats_.c \
  schema_.c \
  setup_.c \
  sha1_.c \
  shun_.c \
  stat_.c \
  style_.c \
  sync_.c \
  tag_.c \
  tagview_.c \
  th_main_.c \
  timeline_.c \
  tkt_.c \
  tktsetup_.c \
  undo_.c \
  update_.c \
  url_.c \
  user_.c \
  verify_.c \
  vfile_.c \
  wiki_.c \
  wikiformat_.c \
  winhttp_.c \
  xfer_.c \
  zip_.c

OBJ = \
  add.o \
  admin.o \
  allrepo.o \
  bag.o \
  blob.o \
  branch.o \
  browse.o \
  captcha.o \
  cgi.o \







<
















<


















<







112
113
114
115
116
117
118

119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134

135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152

153
154
155
156
157
158
159
  info_.c \
  login_.c \
  main_.c \
  manifest_.c \
  md5_.c \
  merge_.c \
  merge3_.c \

  name_.c \
  pivot_.c \
  pqueue_.c \
  printf_.c \
  rebuild_.c \
  report_.c \
  rss_.c \
  rstats_.c \
  schema_.c \
  setup_.c \
  sha1_.c \
  shun_.c \
  stat_.c \
  style_.c \
  sync_.c \
  tag_.c \

  th_main_.c \
  timeline_.c \
  tkt_.c \
  tktsetup_.c \
  undo_.c \
  update_.c \
  url_.c \
  user_.c \
  verify_.c \
  vfile_.c \
  wiki_.c \
  wikiformat_.c \
  winhttp_.c \
  xfer_.c \
  zip_.c

OBJ = \
  add.o \

  allrepo.o \
  bag.o \
  blob.o \
  branch.o \
  browse.o \
  captcha.o \
  cgi.o \
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
  info.o \
  login.o \
  main.o \
  manifest.o \
  md5.o \
  merge.o \
  merge3.o \
  my_page.o \
  name.o \
  pivot.o \
  pqueue.o \
  printf.o \
  rebuild.o \
  report.o \
  rss.o \
  rstats.o \
  schema.o \
  setup.o \
  sha1.o \
  shun.o \
  stat.o \
  style.o \
  sync.o \
  tag.o \
  tagview.o \
  th_main.o \
  timeline.o \
  tkt.o \
  tktsetup.o \
  undo.o \
  update.o \
  url.o \







<
















<







180
181
182
183
184
185
186

187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202

203
204
205
206
207
208
209
  info.o \
  login.o \
  main.o \
  manifest.o \
  md5.o \
  merge.o \
  merge3.o \

  name.o \
  pivot.o \
  pqueue.o \
  printf.o \
  rebuild.o \
  report.o \
  rss.o \
  rstats.o \
  schema.o \
  setup.o \
  sha1.o \
  shun.o \
  stat.o \
  style.o \
  sync.o \
  tag.o \

  th_main.o \
  timeline.o \
  tkt.o \
  tktsetup.o \
  undo.o \
  update.o \
  url.o \
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
#
$(SRCDIR)/../manifest:	
	# noop

clean:	
	rm -f *.o *_.c $(APPNAME) VERSION.h
	rm -f translate makeheaders mkindex page_index.h headers
	rm -f add.h admin.h allrepo.h bag.h blob.h branch.h browse.h captcha.h cgi.h checkin.h checkout.h clearsign.h clone.h comformat.h configure.h construct.h content.h db.h delta.h deltacmd.h descendants.h diff.h diffcmd.h doc.h encode.h file.h http.h http_socket.h http_transport.h info.h login.h main.h manifest.h md5.h merge.h merge3.h my_page.h name.h pivot.h pqueue.h printf.h rebuild.h report.h rss.h rstats.h schema.h setup.h sha1.h shun.h stat.h style.h sync.h tag.h tagview.h th_main.h timeline.h tkt.h tktsetup.h undo.h update.h url.h user.h verify.h vfile.h wiki.h wikiformat.h winhttp.h xfer.h zip.h

page_index.h: $(TRANS_SRC) mkindex
	./mkindex $(TRANS_SRC) >$@
headers:	page_index.h makeheaders VERSION.h
	./makeheaders  add_.c:add.h admin_.c:admin.h allrepo_.c:allrepo.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h file_.c:file.h http_.c:http.h http_socket_.c:http_socket.h http_transport_.c:http_transport.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h my_page_.c:my_page.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h report_.c:report.h rss_.c:rss.h rstats_.c:rstats.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tagview_.c:tagview.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h VERSION.h
	touch headers
headers: Makefile
Makefile:
add_.c:	$(SRCDIR)/add.c translate
	./translate $(SRCDIR)/add.c >add_.c

add.o:	add_.c add.h  $(SRCDIR)/config.h
	$(XTCC) -o add.o -c add_.c

add.h:	headers
admin_.c:	$(SRCDIR)/admin.c translate
	./translate $(SRCDIR)/admin.c >admin_.c

admin.o:	admin_.c admin.h  $(SRCDIR)/config.h
	$(XTCC) -o admin.o -c admin_.c

admin.h:	headers
allrepo_.c:	$(SRCDIR)/allrepo.c translate
	./translate $(SRCDIR)/allrepo.c >allrepo_.c

allrepo.o:	allrepo_.c allrepo.h  $(SRCDIR)/config.h
	$(XTCC) -o allrepo.o -c allrepo_.c

allrepo.h:	headers







|




|










<
<
<
<
<
<
<







253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275







276
277
278
279
280
281
282
#
$(SRCDIR)/../manifest:	
	# noop

clean:	
	rm -f *.o *_.c $(APPNAME) VERSION.h
	rm -f translate makeheaders mkindex page_index.h headers
	rm -f add.h allrepo.h bag.h blob.h branch.h browse.h captcha.h cgi.h checkin.h checkout.h clearsign.h clone.h comformat.h configure.h construct.h content.h db.h delta.h deltacmd.h descendants.h diff.h diffcmd.h doc.h encode.h file.h http.h http_socket.h http_transport.h info.h login.h main.h manifest.h md5.h merge.h merge3.h name.h pivot.h pqueue.h printf.h rebuild.h report.h rss.h rstats.h schema.h setup.h sha1.h shun.h stat.h style.h sync.h tag.h th_main.h timeline.h tkt.h tktsetup.h undo.h update.h url.h user.h verify.h vfile.h wiki.h wikiformat.h winhttp.h xfer.h zip.h

page_index.h: $(TRANS_SRC) mkindex
	./mkindex $(TRANS_SRC) >$@
headers:	page_index.h makeheaders VERSION.h
	./makeheaders  add_.c:add.h allrepo_.c:allrepo.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h file_.c:file.h http_.c:http.h http_socket_.c:http_socket.h http_transport_.c:http_transport.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h report_.c:report.h rss_.c:rss.h rstats_.c:rstats.h schema_.c:schema.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h VERSION.h
	touch headers
headers: Makefile
Makefile:
add_.c:	$(SRCDIR)/add.c translate
	./translate $(SRCDIR)/add.c >add_.c

add.o:	add_.c add.h  $(SRCDIR)/config.h
	$(XTCC) -o add.o -c add_.c

add.h:	headers







allrepo_.c:	$(SRCDIR)/allrepo.c translate
	./translate $(SRCDIR)/allrepo.c >allrepo_.c

allrepo.o:	allrepo_.c allrepo.h  $(SRCDIR)/config.h
	$(XTCC) -o allrepo.o -c allrepo_.c

allrepo.h:	headers
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
merge3_.c:	$(SRCDIR)/merge3.c translate
	./translate $(SRCDIR)/merge3.c >merge3_.c

merge3.o:	merge3_.c merge3.h  $(SRCDIR)/config.h
	$(XTCC) -o merge3.o -c merge3_.c

merge3.h:	headers
my_page_.c:	$(SRCDIR)/my_page.c translate
	./translate $(SRCDIR)/my_page.c >my_page_.c

my_page.o:	my_page_.c my_page.h  $(SRCDIR)/config.h
	$(XTCC) -o my_page.o -c my_page_.c

my_page.h:	headers
name_.c:	$(SRCDIR)/name.c translate
	./translate $(SRCDIR)/name.c >name_.c

name.o:	name_.c name.h  $(SRCDIR)/config.h
	$(XTCC) -o name.o -c name_.c

name.h:	headers







<
<
<
<
<
<
<







507
508
509
510
511
512
513







514
515
516
517
518
519
520
merge3_.c:	$(SRCDIR)/merge3.c translate
	./translate $(SRCDIR)/merge3.c >merge3_.c

merge3.o:	merge3_.c merge3.h  $(SRCDIR)/config.h
	$(XTCC) -o merge3.o -c merge3_.c

merge3.h:	headers







name_.c:	$(SRCDIR)/name.c translate
	./translate $(SRCDIR)/name.c >name_.c

name.o:	name_.c name.h  $(SRCDIR)/config.h
	$(XTCC) -o name.o -c name_.c

name.h:	headers
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
tag_.c:	$(SRCDIR)/tag.c translate
	./translate $(SRCDIR)/tag.c >tag_.c

tag.o:	tag_.c tag.h  $(SRCDIR)/config.h
	$(XTCC) -o tag.o -c tag_.c

tag.h:	headers
tagview_.c:	$(SRCDIR)/tagview.c translate
	./translate $(SRCDIR)/tagview.c >tagview_.c

tagview.o:	tagview_.c tagview.h  $(SRCDIR)/config.h
	$(XTCC) -o tagview.o -c tagview_.c

tagview.h:	headers
th_main_.c:	$(SRCDIR)/th_main.c translate
	./translate $(SRCDIR)/th_main.c >th_main_.c

th_main.o:	th_main_.c th_main.h  $(SRCDIR)/config.h
	$(XTCC) -o th_main.o -c th_main_.c

th_main.h:	headers







<
<
<
<
<
<
<







619
620
621
622
623
624
625







626
627
628
629
630
631
632
tag_.c:	$(SRCDIR)/tag.c translate
	./translate $(SRCDIR)/tag.c >tag_.c

tag.o:	tag_.c tag.h  $(SRCDIR)/config.h
	$(XTCC) -o tag.o -c tag_.c

tag.h:	headers







th_main_.c:	$(SRCDIR)/th_main.c translate
	./translate $(SRCDIR)/th_main.c >th_main_.c

th_main.o:	th_main_.c th_main.h  $(SRCDIR)/config.h
	$(XTCC) -o th_main.o -c th_main_.c

th_main.h:	headers
Changes to src/makemake.tcl.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/usr/bin/tclsh
#
# Run this TCL script to generate the "main.mk" makefile.
#

# Basenames of all source files that get preprocessed using
# "translate" and "makeheaders"
#
set src {
  add
  admin
  allrepo
  bag
  blob
  branch
  browse
  captcha
  cgi










<







1
2
3
4
5
6
7
8
9
10

11
12
13
14
15
16
17
#!/usr/bin/tclsh
#
# Run this TCL script to generate the "main.mk" makefile.
#

# Basenames of all source files that get preprocessed using
# "translate" and "makeheaders"
#
set src {
  add

  allrepo
  bag
  blob
  branch
  browse
  captcha
  cgi
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
  info
  login
  main
  manifest
  md5
  merge
  merge3
  my_page
  name
  pivot
  pqueue
  printf
  rebuild
  report
  rss
  rstats
  schema
  setup
  sha1
  shun
  stat
  style
  sync
  tag
  tagview
  th_main
  timeline
  tkt
  tktsetup
  undo
  update
  url







<
















<







38
39
40
41
42
43
44

45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

61
62
63
64
65
66
67
  info
  login
  main
  manifest
  md5
  merge
  merge3

  name
  pivot
  pqueue
  printf
  rebuild
  report
  rss
  rstats
  schema
  setup
  sha1
  shun
  stat
  style
  sync
  tag

  th_main
  timeline
  tkt
  tktsetup
  undo
  update
  url
Deleted src/my_page.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/*
** Copyright (c) 2007 D. Richard Hipp
** Copyright (c) 2008 Stephan Beal
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public
** License as published by the Free Software Foundation; either
** version 2 of the License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
** General Public License for more details.
**
** You should have received a copy of the GNU General Public
** License along with this library; if not, write to the
** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
** Boston, MA  02111-1307, USA.
**
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*******************************************************************************
**
** Implementation of the Tag View page
*/
#include <assert.h>
#include "config.h"
#include "my_page.h"

/*
** Renders a logout button.
*/
static void mypage_logout_button()
{
  if( g.zLogin ){
    @ <br clear="both"/><hr/>
    @ <strong>Logout (or "log out", if you prefer):</strong><br/>
    @ <form action='login' method='POST'>
    @ <p>To log off the system (and delete your login cookie)
    @  press the following button:<br>
    @ <input type="submit" name="out" value="Logout"/></p>
    @ </form>
  }
}

/*
** Renders a password changer.
*/
static void mypage_password_changer()
{
  if( g.okPassword ){
    @ <br clear="both"/><hr/>
    @ <strong>Change Password:</strong><br/>
    @ <p>To change your password, enter your old password and your
    @ new password twice below then press the "Change Password"
    @ button.</p>
    @ <form action="login" method="POST">
    @ <input type='hidden' name='g' value='my'/>
    @ <table><tbody>
    @ <tr><td align="right">Old Password:</td>
    @ <td><input type="password" name="p" size=30></td></tr>
    @ <tr><td align="right">New Password:</td>
    @ <td><input type="password" name="n1" size=30></td></tr>
    @ <tr><td align="right">Repeat New Password:</td>
    @ <td><input type="password" name="n2" size=30></td></tr>
    @ <tr><td></td>
    @ <td><input type="submit" value="Change Password"></td></tr>
    @ </tbody></table>
    @ </form>
  }

}

/*
** Default page rendered for /my.
*/
static void mypage_page_default()
{
  int uid = g.userUid;
  char * sql = mprintf( "SELECT login,cap,info FROM user WHERE uid=%d",
			uid );
  Stmt st;
  char const *uname;
  char const *ucap;
  char const *uinfo;
  db_prepare( &st, sql );
  free( sql );
  db_step(&st);
  uname = db_column_text( &st, 0 );
  ucap = db_column_text( &st, 1 );
  uinfo = db_column_text( &st, 2 );

  @ <h2>Welcome, %s(uname)!</h2>
  @ Your user ID is: %d(uid)<br/>
  @ Your Fossil permissions are: [%s(ucap)]
  @   [TODO: explain these]<br/>
  if( g.okAdmin ){
    @ You are an <a href='%s(g.zBaseURL)/admin'>admin</a>.<br/>
  }
  @ Your additional info: [%s(uinfo)]
  @   [TODO: make this editable]<br/>

  mypage_logout_button();

  @ <hr/>
  @ <h2>Your artifacts:</h2>
  @ <ul>
  @ <li><a href='%s(g.zBaseURL)/timeline?u=%s(uname)&y=ci'>Your latest commits</a>.</li>
  @ <li><a href='%s(g.zBaseURL)/timeline?u=%s(uname)&y=w'>Your latest wiki changes</a>.</li>
  @ <li><a href='%s(g.zBaseURL)/timeline?u=%s(uname)&y=t'>Your latest ticket changes</a>.</li>
  @ <li>TODO: etc. etc. etc.</li>
  @ </ul>
  mypage_password_changer();

  @ <hr/><h2>TODOs:</h2><ul>
  @ <li>Change "additional info" field.</li>
  @ <li>Search for changes made by you.</li>
  @ <li>Search for files/wiki pages/tickets related to you.</li>
  @ <li>Allow per-user setup of the page (e.g. reports).</li>
  @ <li>... the list goes on ...</li>
  @ </ul>

  db_finalize( &st );

}

/*
** WEBPAGE: /my
*/
void mypage_page(void){
  const char *name;
  login_check_credentials();
  if( !g.okRdWiki ){
    login_needed();
  }
  style_header("Your Home");
  name = P("name");
  if( name )
  {
    if( 0 == strcmp(name,"tickets") )
    {
      @ TODO: Tickets page.
    }
    else
    {
      @ TODO: handle /my/%s(name)
    }
  }
  else
  {
    mypage_page_default();
  }
  style_footer();
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
























































































































































































































































































































Changes to src/style.c.
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
@   <div class="logo">
@     <!-- <img src="logo.gif" alt="logo"><br></br> -->
@     <nobr>$<project_name></nobr>
@   </div>
@   <div class="title">$<title></div>
@   <div class="status"><nobr><th1>
@      if {[info exists login]} {
@        html "Logged in as <a href='$baseurl/my'>$login</a>"
@      } else {
@        puts "Not logged in"
@      }
@   </th1></nobr></div>
@ </div>
@ <div class="mainmenu"><th1>
@ html "<a href='$baseurl$index_page'>Home</a>"







|







195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
@   <div class="logo">
@     <!-- <img src="logo.gif" alt="logo"><br></br> -->
@     <nobr>$<project_name></nobr>
@   </div>
@   <div class="title">$<title></div>
@   <div class="status"><nobr><th1>
@      if {[info exists login]} {
@        puts "Logged in as $login"
@      } else {
@        puts "Not logged in"
@      }
@   </th1></nobr></div>
@ </div>
@ <div class="mainmenu"><th1>
@ html "<a href='$baseurl$index_page'>Home</a>"
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
@   border: 1px solid #ff0000;
@ }
@
@ div.miniform {
@     font-size: smaller;
@     margin: 8px;
@ } 
@
@ table.fossil_db_generic_query_view {
@   border-spacing: 0px;
@   border: 1px solid black;
@ }
@ table.fossil_db_generic_query_view td {
@   padding: 2px 1em 2px 1em;
@ }
@ table.fossil_db_generic_query_view tr {
@ }
@ table.fossil_db_generic_query_view tr.even {
@   background: #ffffff;
@ }
@ table.fossil_db_generic_query_view tr.odd {
@   background: #e5e5e5;
@ }
@ table.fossil_db_generic_query_view tr.header {
@   background: #558195;
@   font-size: 1.5em;
@   color: #ffffff;
@ }
;

/*
** WEBPAGE: style.css
*/
void page_style_css(void){
  char *zCSS = 0;







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







390
391
392
393
394
395
396





















397
398
399
400
401
402
403
@   border: 1px solid #ff0000;
@ }
@
@ div.miniform {
@     font-size: smaller;
@     margin: 8px;
@ } 





















;

/*
** WEBPAGE: style.css
*/
void page_style_css(void){
  char *zCSS = 0;
Deleted src/tagview.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
/*
** Copyright (c) 2007 D. Richard Hipp
** Copyright (c) 2008 Stephan Beal
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public
** License as published by the Free Software Foundation; either
** version 2 of the License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
** General Public License for more details.
**
** You should have received a copy of the GNU General Public
** License along with this library; if not, write to the
** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
** Boston, MA  02111-1307, USA.
**
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*******************************************************************************
**
** Implementation of the Tag View page
*/
#include <assert.h>
#include "config.h"
#include "tagview.h"

#if 0  /* DISABLED */

#if 0
#  define TAGVIEW_DEFAULT_FILTER "AND t.tagname NOT GLOB 'wiki-*' "
#else
#  define TAGVIEW_DEFAULT_FILTER
#endif

/*
** Lists all tags matching the given LIKE clause (which
** may be 0).
*/
static void tagview_page_list_tags(const char *zLike){
  char *zLikeClause = 0;
  const int limit = 10;
  char *zLimit = 0;
  char *zSql;

  if( zLike && zLike[0] ){
    zLikeClause = mprintf( "AND t.tagname LIKE '%%%q%%'", zLike );
    zLimit = "";
    @ <h2>Tags matching [%h(zLikeClause)]:</h2>
  }else{
    zLimit = mprintf( "LIMIT %d", limit );
    zLikeClause = "";
    @ <h2>%d(limit) most recent tags:</h2>
  }
  zSql = mprintf( 
    "SELECT "
    "   linktagid(t.tagid) AS 'Tag ID',"
    "   linktagname(t.tagname) AS 'Name',"
    "   DATETIME(tx.mtime) AS 'Timestamp',"
    "   linkuuid(b.uuid) AS 'Version'"
    "  FROM tag t, tagxref tx, blob b "
    " WHERE t.tagid=tx.tagid AND tx.rid=b.rid"
    " %s "
    TAGVIEW_DEFAULT_FILTER
    " ORDER BY tx.mtime DESC %s",
    zLikeClause, zLimit
  );
  db_generic_query_view(zSql, 1);
  free(zSql);
  if( zLikeClause[0] ) free(zLikeClause);
  if( zLimit[0] ) free(zLimit);
}

/*
** A small search form which forwards to ?like=SEARCH_STRING
*/
static void tagview_page_search_miniform(void){
  char const * like = P("like");
  @ <div class='miniform'>
  @ <form action='tagview' method='post'>
  @ Search for tags: 
  @ <input type='text' name='like' value='%h((like?like:""))' size='10'/>
  @ <input type='submit'/>
  @ <input type='hidden' name='raw' value='y'/>
  @ </form>
  @ </div>
}

/*
** tagview_page_default() renders the default page for tagview_page().
*/
static void tagview_page_default(void){
  tagview_page_list_tags( 0 );
}

/*
** Lists all tags matching the given tagid.
*/
static void tagview_page_tag_by_id( int tagid ){
  char *zSql;
  @ <h2>Tag #%d(tagid):</h2>
  zSql = mprintf( 
    "SELECT DISTINCT"
    "       linktagname(t.tagname) AS 'Tag Name',"
    "       DATETIME(tx.mtime) AS 'Timestamp',"
    "       linkuuid(b.uuid) AS 'Version'"
    "  FROM tag t, tagxref tx, blob b"
    " WHERE t.tagid=%d AND t.tagid=tx.tagid AND tx.rid=b.rid "
    TAGVIEW_DEFAULT_FILTER
    " ORDER BY tx.mtime DESC",
    tagid
  );
  db_generic_query_view(zSql, 1);
  free(zSql);
}

/*
** Lists all tags matching the given tag name.
*/
static void tagview_page_tag_by_name( char const * tagname ){
  char *zSql;
  @ <h2>Tag '%s(tagname)':</h2>
  zSql = mprintf( 
    "SELECT DISTINCT"
    "       linktagid(t.tagid) AS 'Tag ID',"
    "       linktagname(t.tagname) AS 'Name',"
    "       DATETIME(tx.mtime) AS 'Timestamp',"
    "       linkuuid(b.uuid) AS 'Version'"
    "  FROM tag t, tagxref tx, blob b "
    " WHERE ( t.tagname='%q' OR  t.tagname='sym-%q') "
    "   AND t.tagid=tx.tagid AND tx.rid=b.rid "
    TAGVIEW_DEFAULT_FILTER
    " ORDER BY tx.mtime DESC",
    tagname,tagname);
  db_generic_query_view(zSql, 1);
  free(zSql);
}

/*
** Internal view of tags
*/
void raw_tagview_page(void){
  char const * check = 0;
  login_check_credentials();
  /* if( !g.okRdWiki ){ */
  if( !g.okAdmin ){
    login_needed();
  }
  style_header("Raw Tags");
  login_anonymous_available();
  tagview_page_search_miniform();
  @ <hr/>
  if( 0 != (check = P("tagid")) ){
    tagview_page_tag_by_id( atoi(check) );
  }else if( 0 != (check = P("like")) ){
    tagview_page_list_tags( check );
  }else if( 0 != (check = P("name")) ){
    tagview_page_tag_by_name( check );
  }else{
    tagview_page_default();
  }
  style_footer();
}

#undef TAGVIEW_DEFAULT_FILTER

/*
** Generate a timeline for the chosen tag
*/
void tagview_print_timeline(char const *zName, char const *zPrefix){
  char *zSql;
  Stmt q;
  int tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='%q%q'",
                        zPrefix, zName);
  zSql = mprintf("%s AND EXISTS (SELECT 1"
         " FROM tagxref"
         "  WHERE tagxref.rid = event.objid"
         "  AND tagxref.tagtype > 0"
         "  AND tagxref.tagid = %d)"
         " ORDER BY 3 desc",
         timeline_query_for_www(), tagid
  );
  db_prepare(&q, zSql);
  free(zSql);
  www_print_timeline(&q, 0, 0);
  db_finalize(&q);
}

/*
** WEB PAGE: /tagview
*/
void tagview_page(void){
  char const *zName = 0;
  char const *zTitle = 0;
  int nTag = 0;
  login_check_credentials();
  if( !g.okRead ){
    login_needed();
  }
  if ( P("tagid") || P("like") || P("raw") ) {
    raw_tagview_page();
    return;
  }
  login_anonymous_available();
  if( 0 != (zName = P("name")) ){
    Blob uuid;
    if( g.okAdmin ){
      style_submenu_element("RawTags", "Internal Ticket View",
        "%s/tagview?name=%s&raw=y", g.zTop, zName);
    }
    zTitle = "Tagged Artifacts";
    @ <h2>%s(zName):</h2>
    if( sym_tag_to_uuid(zName, &uuid) > 0){
      tagview_print_timeline(zName, "sym-");
    }else if( tag_to_uuid(zName, &uuid, "") > 0){
      tagview_print_timeline(zName, "");
    }else{
      @ There is no artifact with this tag.
    }
  }else{
    Stmt q;
    const char *prefix = "sym-";
    int preflen = strlen(prefix);
    if( g.okAdmin ){
      style_submenu_element("RawTags", "Internal Ticket View",
        "%s/tagview?raw=y", g.zTop);
    }
    zTitle = "Tags";
    db_prepare(&q,
      "SELECT tagname"
      "  FROM tag"
      " WHERE EXISTS(SELECT 1 FROM tagxref"
      "               WHERE tagid=tag.tagid"
      "                 AND tagtype>0)"
      " AND tagid > %d"
      " AND tagname NOT GLOB 'wiki-*'"
      " AND tagname NOT GLOB 'tkt-*'"
      " ORDER BY tagname",
      MAX_INT_TAG
    );
    @ <ul>
    while( db_step(&q)==SQLITE_ROW ){
      const char *name = db_column_text(&q, 0);
      nTag++;
      if( g.okHistory ){
        if( strncmp(name, prefix, preflen)==0 ){
          @ <li><a href=%s(g.zBaseURL)/tagview?name=%s(name+preflen)>
          @ %s(name+preflen)</a>
        }else{
          @ <li><a href=%s(g.zBaseURL)/tagview?name=%s(name)>
          @ %s(name)</a>
        }
      }else{
        if( strncmp(name, prefix, preflen)==0 ){
          @ <li><strong>%s(name+preflen)</strong>
        }else{
          @ <li><strong>%s(name)</strong>
        }
      }
      if( strncmp(name, prefix, preflen)==0 ){
        @ (symbolic label)
      }
      @ </li>
    }
    @ </ul>
    if( nTag == 0) {
      @ There are no relevant tags.
    }
    db_finalize(&q);
  }
  style_header(zTitle);
  /*
   * Put in dummy functions since www_print_timeline has generated calls to
   * them. Some browsers don't seem to care, but better to be safe.
   * Actually, it would be nice to use the functions on this page, but at
   * the moment it looks to be too difficult.
   */
  @ <script>
  @ function xin(id){
  @ }
  @ function xout(id){
  @ }
  @ </script>

  style_footer();
}

#endif /* DISABLED */
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<