File Annotation
Not logged in
e487b77b1a 2008-02-04       drh: /*
e487b77b1a 2008-02-04       drh: ** Copyright (c) 2008 D. Richard Hipp
e487b77b1a 2008-02-04       drh: **
e487b77b1a 2008-02-04       drh: ** This program is free software; you can redistribute it and/or
e487b77b1a 2008-02-04       drh: ** modify it under the terms of the GNU General Public
e487b77b1a 2008-02-04       drh: ** License version 2 as published by the Free Software Foundation.
e487b77b1a 2008-02-04       drh: **
e487b77b1a 2008-02-04       drh: ** This program is distributed in the hope that it will be useful,
e487b77b1a 2008-02-04       drh: ** but WITHOUT ANY WARRANTY; without even the implied warranty of
e487b77b1a 2008-02-04       drh: ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
e487b77b1a 2008-02-04       drh: ** General Public License for more details.
e487b77b1a 2008-02-04       drh: **
e487b77b1a 2008-02-04       drh: ** You should have received a copy of the GNU General Public
e487b77b1a 2008-02-04       drh: ** License along with this library; if not, write to the
e487b77b1a 2008-02-04       drh: ** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
e487b77b1a 2008-02-04       drh: ** Boston, MA  02111-1307, USA.
e487b77b1a 2008-02-04       drh: **
e487b77b1a 2008-02-04       drh: ** Author contact information:
e487b77b1a 2008-02-04       drh: **   drh@hwaci.com
e487b77b1a 2008-02-04       drh: **   http://www.hwaci.com/drh/
e487b77b1a 2008-02-04       drh: **
e487b77b1a 2008-02-04       drh: *******************************************************************************
e487b77b1a 2008-02-04       drh: **
e487b77b1a 2008-02-04       drh: ** This file contains code to implement the file browser web interface.
e487b77b1a 2008-02-04       drh: */
e487b77b1a 2008-02-04       drh: #include "config.h"
e487b77b1a 2008-02-04       drh: #include "browse.h"
e487b77b1a 2008-02-04       drh: #include <assert.h>
e487b77b1a 2008-02-04       drh: 
e487b77b1a 2008-02-04       drh: /*
e487b77b1a 2008-02-04       drh: ** This is the implemention of the "pathelement(X,N)" SQL function.
e487b77b1a 2008-02-04       drh: **
e487b77b1a 2008-02-04       drh: ** If X is a unix-like pathname (with "/" separators) and N is an
e487b77b1a 2008-02-04       drh: ** integer, then skip the initial N characters of X and return the
e487b77b1a 2008-02-04       drh: ** name of the path component that begins on the N+1th character
e487b77b1a 2008-02-04       drh: ** (numbered from 0).  If the path component is a directory (if
e487b77b1a 2008-02-04       drh: ** it is followed by other path components) then prepend "/".
e487b77b1a 2008-02-04       drh: **
e487b77b1a 2008-02-04       drh: ** Examples:
e487b77b1a 2008-02-04       drh: **
e487b77b1a 2008-02-04       drh: **      pathelement('abc/pqr/xyz', 4)  ->  '/pqr'
e487b77b1a 2008-02-04       drh: **      pathelement('abc/pqr', 4)      ->  'pqr'
e487b77b1a 2008-02-04       drh: **      pathelement('abc/pqr/xyz', 0)  ->  '/abc'
e487b77b1a 2008-02-04       drh: */
e487b77b1a 2008-02-04       drh: static void pathelementFunc(
e487b77b1a 2008-02-04       drh:   sqlite3_context *context,
e487b77b1a 2008-02-04       drh:   int argc,
e487b77b1a 2008-02-04       drh:   sqlite3_value **argv
e487b77b1a 2008-02-04       drh: ){
e487b77b1a 2008-02-04       drh:   const unsigned char *z;
e487b77b1a 2008-02-04       drh:   int len, n, i;
e487b77b1a 2008-02-04       drh:   char *zOut;
e487b77b1a 2008-02-04       drh: 
e487b77b1a 2008-02-04       drh:   assert( argc==2 );
e487b77b1a 2008-02-04       drh:   z = sqlite3_value_text(argv[0]);
e487b77b1a 2008-02-04       drh:   if( z==0 ) return;
e487b77b1a 2008-02-04       drh:   len = sqlite3_value_bytes(argv[0]);
e487b77b1a 2008-02-04       drh:   n = sqlite3_value_int(argv[1]);
e487b77b1a 2008-02-04       drh:   if( len<=n ) return;
e487b77b1a 2008-02-04       drh:   if( n>0 && z[n-1]!='/' ) return;
e487b77b1a 2008-02-04       drh:   for(i=n; i<len && z[i]!='/'; i++){}
e487b77b1a 2008-02-04       drh:   if( i==len ){
e487b77b1a 2008-02-04       drh:     sqlite3_result_text(context, (char*)&z[n], len-n, SQLITE_TRANSIENT);
e487b77b1a 2008-02-04       drh:   }else{
e487b77b1a 2008-02-04       drh:     zOut = sqlite3_mprintf("/%.*s", i-n, &z[n]);
e487b77b1a 2008-02-04       drh:     sqlite3_result_text(context, zOut, i-n+1, sqlite3_free);
e487b77b1a 2008-02-04       drh:   }
e487b77b1a 2008-02-04       drh: }
e487b77b1a 2008-02-04       drh: 
a20dcb5c26 2008-02-04       drh: /*
a20dcb5c26 2008-02-04       drh: ** Given a pathname which is a relative path from the root of
a20dcb5c26 2008-02-04       drh: ** the repository to a file or directory, compute a string which
a20dcb5c26 2008-02-04       drh: ** is an HTML rendering of that path with hyperlinks on each
a20dcb5c26 2008-02-04       drh: ** directory component of the path where the hyperlink redirects
a20dcb5c26 2008-02-04       drh: ** to the "dir" page for the directory.
a20dcb5c26 2008-02-04       drh: **
a20dcb5c26 2008-02-04       drh: ** There is no hyperlink on the file element of the path.
a20dcb5c26 2008-02-04       drh: **
a20dcb5c26 2008-02-04       drh: ** The computed string is appended to the pOut blob.  pOut should
a20dcb5c26 2008-02-04       drh: ** have already been initialized.
a20dcb5c26 2008-02-04       drh: */
a20dcb5c26 2008-02-04       drh: void hyperlinked_path(const char *zPath, Blob *pOut){
a20dcb5c26 2008-02-04       drh:   int i, j;
a20dcb5c26 2008-02-04       drh:   char *zSep = "";
a20dcb5c26 2008-02-04       drh: 
a20dcb5c26 2008-02-04       drh:   for(i=0; zPath[i]; i=j){
a20dcb5c26 2008-02-04       drh:     for(j=i; zPath[j] && zPath[j]!='/'; j++){}
d57de28756 2008-05-05       drh:     if( zPath[j] && g.okHistory ){
a20dcb5c26 2008-02-04       drh:       blob_appendf(pOut, "%s<a href=\"%s/dir?name=%#T\">%#h</a>",
a20dcb5c26 2008-02-04       drh:                    zSep, g.zBaseURL, j, zPath, j-i, &zPath[i]);
a20dcb5c26 2008-02-04       drh:     }else{
d57de28756 2008-05-05       drh:       blob_appendf(pOut, "%s%#h", zSep, j-i, &zPath[i]);
a20dcb5c26 2008-02-04       drh:     }
a20dcb5c26 2008-02-04       drh:     zSep = "/";
a20dcb5c26 2008-02-04       drh:     while( zPath[j]=='/' ){ j++; }
a20dcb5c26 2008-02-04       drh:   }
a20dcb5c26 2008-02-04       drh: }
a20dcb5c26 2008-02-04       drh: 
e487b77b1a 2008-02-04       drh: 
e487b77b1a 2008-02-04       drh: /*
e487b77b1a 2008-02-04       drh: ** WEBPAGE: dir
e487b77b1a 2008-02-04       drh: **
e487b77b1a 2008-02-04       drh: ** Query parameters:
e487b77b1a 2008-02-04       drh: **
e81cc91aa4 2008-02-04       drh: **    name=PATH        Directory to display.  Required.
923d644b89 2009-01-28       drh: **    ci=LABEL         Show only files in this check-in.  Optional.
e487b77b1a 2008-02-04       drh: */
e487b77b1a 2008-02-04       drh: void page_dir(void){
e81cc91aa4 2008-02-04       drh:   const char *zD = P("name");
e487b77b1a 2008-02-04       drh:   int mxLen;
e487b77b1a 2008-02-04       drh:   int nCol, nRow;
e487b77b1a 2008-02-04       drh:   int cnt, i;
e487b77b1a 2008-02-04       drh:   char *zPrefix;
e487b77b1a 2008-02-04       drh:   Stmt q;
923d644b89 2009-01-28       drh:   const char *zCI = P("ci");
923d644b89 2009-01-28       drh:   int rid = 0;
923d644b89 2009-01-28       drh:   Blob content;
923d644b89 2009-01-28       drh:   Manifest m;
923d644b89 2009-01-28       drh:   const char *zSubdirLink;
e487b77b1a 2008-02-04       drh: 
e487b77b1a 2008-02-04       drh:   login_check_credentials();
e487b77b1a 2008-02-04       drh:   if( !g.okHistory ){ login_needed(); return; }
e487b77b1a 2008-02-04       drh:   style_header("File List");
e487b77b1a 2008-02-04       drh:   sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0,
e487b77b1a 2008-02-04       drh:                           pathelementFunc, 0, 0);
e487b77b1a 2008-02-04       drh: 
e81cc91aa4 2008-02-04       drh:   /* If the name= parameter is an empty string, make it a NULL pointer */
e487b77b1a 2008-02-04       drh:   if( zD && strlen(zD)==0 ){ zD = 0; }
e81cc91aa4 2008-02-04       drh: 
923d644b89 2009-01-28       drh:   /* If a specific check-in is requested, fetch and parse it. */
923d644b89 2009-01-28       drh:   if( zCI && (rid = name_to_rid(zCI))!=0 && content_get(rid, &content) ){
923d644b89 2009-01-28       drh:     if( !manifest_parse(&m, &content) || m.type!=CFTYPE_MANIFEST ){
923d644b89 2009-01-28       drh:       zCI = 0;
923d644b89 2009-01-28       drh:     }
923d644b89 2009-01-28       drh:   }
e487b77b1a 2008-02-04       drh: 
e487b77b1a 2008-02-04       drh:   /* Compute the title of the page */
e487b77b1a 2008-02-04       drh:   if( zD ){
e487b77b1a 2008-02-04       drh:     Blob title;
e487b77b1a 2008-02-04       drh: 
e487b77b1a 2008-02-04       drh:     blob_zero(&title);
a20dcb5c26 2008-02-04       drh:     blob_appendf(&title, "Files in directory ");
a20dcb5c26 2008-02-04       drh:     hyperlinked_path(zD, &title);
923d644b89 2009-01-28       drh:     @ <h2>%s(blob_str(&title))
a20dcb5c26 2008-02-04       drh:     blob_reset(&title);
a20dcb5c26 2008-02-04       drh:     zPrefix = mprintf("%h/", zD);
a20dcb5c26 2008-02-04       drh:   }else{
923d644b89 2009-01-28       drh:     @ <h2>Files in the top-level directory
a20dcb5c26 2008-02-04       drh:     zPrefix = "";
923d644b89 2009-01-28       drh:   }
923d644b89 2009-01-28       drh:   if( zCI ){
923d644b89 2009-01-28       drh:     char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
923d644b89 2009-01-28       drh:     char zShort[20];
923d644b89 2009-01-28       drh:     memcpy(zShort, zUuid, 10);
923d644b89 2009-01-28       drh:     zShort[10] = 0;
923d644b89 2009-01-28       drh:     @ of check-in [<a href="vinfo?name=%T(zUuid)">%s(zShort)</a>]</h2>
923d644b89 2009-01-28       drh:     zSubdirLink = mprintf("%s/dir?ci=%s&name=%T", g.zBaseURL, zUuid, zPrefix);
923d644b89 2009-01-28       drh:     if( zD ){
923d644b89 2009-01-28       drh:       style_submenu_element("Top", "Top", "%s/dir?ci=%s", g.zBaseURL, zUuid);
e487b77b1a 2008-02-04       drh:     }
e487b77b1a 2008-02-04       drh:   }else{
923d644b89 2009-01-28       drh:     @ </h2>
923d644b89 2009-01-28       drh:     zSubdirLink = mprintf("%s/dir?name=%T", g.zBaseURL, zPrefix);
e487b77b1a 2008-02-04       drh:   }
e487b77b1a 2008-02-04       drh: 
e487b77b1a 2008-02-04       drh:   /* Compute the temporary table "localfiles" containing the names
e487b77b1a 2008-02-04       drh:   ** of all files and subdirectories in the zD[] directory.
e487b77b1a 2008-02-04       drh:   **
e487b77b1a 2008-02-04       drh:   ** Subdirectory names begin with "/".  This causes them to sort
e487b77b1a 2008-02-04       drh:   ** first and it also gives us an easy way to distinguish files
e487b77b1a 2008-02-04       drh:   ** from directories in the loop that follows.
e487b77b1a 2008-02-04       drh:   */
923d644b89 2009-01-28       drh:   db_multi_exec(
923d644b89 2009-01-28       drh:      "CREATE TEMP TABLE localfiles(x UNIQUE NOT NULL, u);"
923d644b89 2009-01-28       drh:      "CREATE TEMP TABLE allfiles(x UNIQUE NOT NULL, u);"
923d644b89 2009-01-28       drh:   );
923d644b89 2009-01-28       drh:   if( zCI ){
923d644b89 2009-01-28       drh:     Stmt ins;
923d644b89 2009-01-28       drh:     int i;
923d644b89 2009-01-28       drh:     db_prepare(&ins, "INSERT INTO allfiles VALUES(:x, :u)");
923d644b89 2009-01-28       drh:     for(i=0; i<m.nFile; i++){
923d644b89 2009-01-28       drh:       db_bind_text(&ins, ":x", m.aFile[i].zName);
923d644b89 2009-01-28       drh:       db_bind_text(&ins, ":u", m.aFile[i].zUuid);
923d644b89 2009-01-28       drh:       db_step(&ins);
923d644b89 2009-01-28       drh:       db_reset(&ins);
923d644b89 2009-01-28       drh:     }
923d644b89 2009-01-28       drh:     db_finalize(&ins);
923d644b89 2009-01-28       drh:   }else{
923d644b89 2009-01-28       drh:     db_multi_exec(
923d644b89 2009-01-28       drh:       "INSERT INTO allfiles SELECT name, NULL FROM filename"
923d644b89 2009-01-28       drh:     );
923d644b89 2009-01-28       drh:   }
e487b77b1a 2008-02-04       drh:   if( zD ){
e487b77b1a 2008-02-04       drh:     db_multi_exec(
e487b77b1a 2008-02-04       drh:        "INSERT OR IGNORE INTO localfiles "
923d644b89 2009-01-28       drh:        "  SELECT pathelement(x,%d), u FROM allfiles"
923d644b89 2009-01-28       drh:        "   WHERE x GLOB '%q/*'",
e487b77b1a 2008-02-04       drh:        strlen(zD)+1, zD
e487b77b1a 2008-02-04       drh:     );
e487b77b1a 2008-02-04       drh:   }else{
e487b77b1a 2008-02-04       drh:     db_multi_exec(
e487b77b1a 2008-02-04       drh:        "INSERT OR IGNORE INTO localfiles "
923d644b89 2009-01-28       drh:        "  SELECT pathelement(x,0), u FROM allfiles"
e487b77b1a 2008-02-04       drh:     );
e487b77b1a 2008-02-04       drh:   }
e487b77b1a 2008-02-04       drh: 
e487b77b1a 2008-02-04       drh:   /* Generate a multi-column table listing the contents of zD[]
e487b77b1a 2008-02-04       drh:   ** directory.
e487b77b1a 2008-02-04       drh:   */
e487b77b1a 2008-02-04       drh:   mxLen = db_int(12, "SELECT max(length(x)) FROM localfiles");
e487b77b1a 2008-02-04       drh:   cnt = db_int(0, "SELECT count(*) FROM localfiles");
e487b77b1a 2008-02-04       drh:   nCol = 4;
e487b77b1a 2008-02-04       drh:   nRow = (cnt+nCol-1)/nCol;
923d644b89 2009-01-28       drh:   db_prepare(&q, "SELECT x, u FROM localfiles ORDER BY x");
e487b77b1a 2008-02-04       drh:   @ <table border="0" width="100%%"><tr><td valign="top" width="25%%">
e487b77b1a 2008-02-04       drh:   i = 0;
e487b77b1a 2008-02-04       drh:   while( db_step(&q)==SQLITE_ROW ){
4165033b40 2009-10-31       drh:     const char *zFN;
e487b77b1a 2008-02-04       drh:     if( i==nRow ){
e487b77b1a 2008-02-04       drh:       @ </td><td valign="top" width="25%%">
e487b77b1a 2008-02-04       drh:       i = 0;
e487b77b1a 2008-02-04       drh:     }
e487b77b1a 2008-02-04       drh:     i++;
4165033b40 2009-10-31       drh:     zFN = db_column_text(&q, 0);
4165033b40 2009-10-31       drh:     if( zFN[0]=='/' ){
4165033b40 2009-10-31       drh:       zFN++;
4165033b40 2009-10-31       drh:       @ <li><a href="%s(zSubdirLink)%T(zFN)">%h(zFN)/</a></li>
923d644b89 2009-01-28       drh:     }else if( zCI ){
923d644b89 2009-01-28       drh:       const char *zUuid = db_column_text(&q, 1);
4165033b40 2009-10-31       drh:       @ <li><a href="%s(g.zBaseURL)/artifact?name=%s(zUuid)">%h(zFN)</a>
e487b77b1a 2008-02-04       drh:     }else{
4165033b40 2009-10-31       drh:       @ <li><a href="%s(g.zBaseURL)/finfo?name=%T(zPrefix)%T(zFN)">%h(zFN)</a>
e487b77b1a 2008-02-04       drh:     }
e487b77b1a 2008-02-04       drh:   }
e487b77b1a 2008-02-04       drh:   db_finalize(&q);
e487b77b1a 2008-02-04       drh:   @ </td></tr></table>
e487b77b1a 2008-02-04       drh:   style_footer();
e487b77b1a 2008-02-04       drh: }