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: 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: ** e487b77b1a 2008-02-04 drh: ** d=PATH Directory to display. Required. e487b77b1a 2008-02-04 drh: */ e487b77b1a 2008-02-04 drh: void page_dir(void){ e487b77b1a 2008-02-04 drh: const char *zD = P("d"); 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; 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: e487b77b1a 2008-02-04 drh: /* If the d= parameter is an empty string, make it a NULL pointer */ e487b77b1a 2008-02-04 drh: if( zD && strlen(zD)==0 ){ zD = 0; } 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: int i, j; e487b77b1a 2008-02-04 drh: char *zCopy; e487b77b1a 2008-02-04 drh: Blob title; e487b77b1a 2008-02-04 drh: e487b77b1a 2008-02-04 drh: blob_zero(&title); e487b77b1a 2008-02-04 drh: zCopy = sqlite3_mprintf("%s/", zD); e487b77b1a 2008-02-04 drh: blob_appendf(&title, e487b77b1a 2008-02-04 drh: "Files in directory <a href=\"%s/dir\"><i>root</i></a>", e487b77b1a 2008-02-04 drh: g.zBaseURL e487b77b1a 2008-02-04 drh: ); e487b77b1a 2008-02-04 drh: for(i=0; zD[i]; i=j){ e487b77b1a 2008-02-04 drh: for(j=i; zD[j] && zD[j]!='/'; j++){} e487b77b1a 2008-02-04 drh: if( zD[j] ){ e487b77b1a 2008-02-04 drh: zCopy[j] = 0; e487b77b1a 2008-02-04 drh: blob_appendf(&title, "/<a href=\"%s/dir?d=%T\">%h</a>", e487b77b1a 2008-02-04 drh: g.zBaseURL, zCopy, &zCopy[i]); e487b77b1a 2008-02-04 drh: zCopy[j] = '/'; e487b77b1a 2008-02-04 drh: }else{ e487b77b1a 2008-02-04 drh: blob_appendf(&title, "/%h", &zCopy[i]); e487b77b1a 2008-02-04 drh: } e487b77b1a 2008-02-04 drh: while( zD[j]=='/' ){ j++; } e487b77b1a 2008-02-04 drh: } e487b77b1a 2008-02-04 drh: @ <h2>%s(blob_str(&title))</h2> e487b77b1a 2008-02-04 drh: blob_reset(&title); e487b77b1a 2008-02-04 drh: zPrefix = zCopy; e487b77b1a 2008-02-04 drh: }else{ e487b77b1a 2008-02-04 drh: @ <h2>Files in the top-level directory</h2> e487b77b1a 2008-02-04 drh: 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: */ e487b77b1a 2008-02-04 drh: if( zD ){ e487b77b1a 2008-02-04 drh: db_multi_exec( e487b77b1a 2008-02-04 drh: "CREATE TEMP TABLE localfiles(x UNIQUE NOT NULL);" e487b77b1a 2008-02-04 drh: "INSERT OR IGNORE INTO localfiles " e487b77b1a 2008-02-04 drh: " SELECT pathelement(name,%d) FROM filename" e487b77b1a 2008-02-04 drh: " WHERE +name 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: "CREATE TEMP TABLE localfiles(x UNIQUE NOT NULL);" e487b77b1a 2008-02-04 drh: "INSERT OR IGNORE INTO localfiles " e487b77b1a 2008-02-04 drh: " SELECT pathelement(name,0) FROM filename" 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; e487b77b1a 2008-02-04 drh: db_prepare(&q, "SELECT x 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 ){ e487b77b1a 2008-02-04 drh: const char *zFName; 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++; e487b77b1a 2008-02-04 drh: zFName = db_column_text(&q, 0); e487b77b1a 2008-02-04 drh: if( zFName[0]=='/' ){ e487b77b1a 2008-02-04 drh: zFName++; e487b77b1a 2008-02-04 drh: @ <li><a href="%s(g.zBaseURL)/dir?d=%T(zPrefix)%T(zFName)"> e487b77b1a 2008-02-04 drh: @ %h(zFName)/</a></li> e487b77b1a 2008-02-04 drh: }else{ e487b77b1a 2008-02-04 drh: @ <li><a href="%s(g.zBaseURL)/finfo?name=%T(zPrefix)%T(zFName)"> e487b77b1a 2008-02-04 drh: @ %h(zFName)</a></li> 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: }