/* ** Copyright (c) 2008 D. Richard Hipp ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the GNU General Public ** License version 2 as published by the Free Software Foundation. ** ** 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/ ** ******************************************************************************* ** ** This file contains code to implement the file browser web interface. */ #include "config.h" #include "browse.h" #include /* ** This is the implemention of the "pathelement(X,N)" SQL function. ** ** If X is a unix-like pathname (with "/" separators) and N is an ** integer, then skip the initial N characters of X and return the ** name of the path component that begins on the N+1th character ** (numbered from 0). If the path component is a directory (if ** it is followed by other path components) then prepend "/". ** ** Examples: ** ** pathelement('abc/pqr/xyz', 4) -> '/pqr' ** pathelement('abc/pqr', 4) -> 'pqr' ** pathelement('abc/pqr/xyz', 0) -> '/abc' */ static void pathelementFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ const unsigned char *z; int len, n, i; char *zOut; assert( argc==2 ); z = sqlite3_value_text(argv[0]); if( z==0 ) return; len = sqlite3_value_bytes(argv[0]); n = sqlite3_value_int(argv[1]); if( len<=n ) return; if( n>0 && z[n-1]!='/' ) return; for(i=n; i%#h", zSep, g.zBaseURL, j, zPath, j-i, &zPath[i]); }else{ blob_appendf(pOut, "%s%#h", zSep, j-i, &zPath[i]); } zSep = "/"; while( zPath[j]=='/' ){ j++; } } } /* ** WEBPAGE: dir ** ** Query parameters: ** ** name=PATH Directory to display. Required. ** ci=LABEL Show only files in this check-in. Optional. */ void page_dir(void){ const char *zD = P("name"); int mxLen; int nCol, nRow; int cnt, i; char *zPrefix; Stmt q; const char *zCI = P("ci"); int rid = 0; Blob content; Manifest m; const char *zSubdirLink; login_check_credentials(); if( !g.okHistory ){ login_needed(); return; } style_header("File List"); sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0, pathelementFunc, 0, 0); /* If the name= parameter is an empty string, make it a NULL pointer */ if( zD && strlen(zD)==0 ){ zD = 0; } /* If a specific check-in is requested, fetch and parse it. */ if( zCI && (rid = name_to_rid(zCI))!=0 && content_get(rid, &content) ){ if( !manifest_parse(&m, &content) || m.type!=CFTYPE_MANIFEST ){ zCI = 0; } } /* Compute the title of the page */ if( zD ){ Blob title; blob_zero(&title); blob_appendf(&title, "Files in directory "); hyperlinked_path(zD, &title); @

%s(blob_str(&title)) blob_reset(&title); zPrefix = mprintf("%h/", zD); }else{ @

Files in the top-level directory zPrefix = ""; } if( zCI ){ char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); char zShort[20]; memcpy(zShort, zUuid, 10); zShort[10] = 0; @ of check-in [%s(zShort)]

zSubdirLink = mprintf("%s/dir?ci=%s&name=%T", g.zBaseURL, zUuid, zPrefix); if( zD ){ style_submenu_element("Top", "Top", "%s/dir?ci=%s", g.zBaseURL, zUuid); } }else{ @ zSubdirLink = mprintf("%s/dir?name=%T", g.zBaseURL, zPrefix); } /* Compute the temporary table "localfiles" containing the names ** of all files and subdirectories in the zD[] directory. ** ** Subdirectory names begin with "/". This causes them to sort ** first and it also gives us an easy way to distinguish files ** from directories in the loop that follows. */ db_multi_exec( "CREATE TEMP TABLE localfiles(x UNIQUE NOT NULL, u);" "CREATE TEMP TABLE allfiles(x UNIQUE NOT NULL, u);" ); if( zCI ){ Stmt ins; int i; db_prepare(&ins, "INSERT INTO allfiles VALUES(:x, :u)"); for(i=0; i i = 0; while( db_step(&q)==SQLITE_ROW ){ const char *zFName; if( i==nRow ){ @ i = 0; } i++; zFName = db_column_text(&q, 0); if( zFName[0]=='/' ){ zFName++; @
  • @ %h(zFName)/
  • }else if( zCI ){ const char *zUuid = db_column_text(&q, 1); @
  • %h(zFName) }else{ @
  • @ %h(zFName)
  • } } db_finalize(&q); @ style_footer(); }