dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Copyright (c) 2007 D. Richard Hipp dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This program is free software; you can redistribute it and/or dbda8d6ce9 2007-07-21 drh: ** modify it under the terms of the GNU General Public dbda8d6ce9 2007-07-21 drh: ** License version 2 as published by the Free Software Foundation. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This program is distributed in the hope that it will be useful, dbda8d6ce9 2007-07-21 drh: ** but WITHOUT ANY WARRANTY; without even the implied warranty of dbda8d6ce9 2007-07-21 drh: ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU dbda8d6ce9 2007-07-21 drh: ** General Public License for more details. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** You should have received a copy of the GNU General Public dbda8d6ce9 2007-07-21 drh: ** License along with this library; if not, write to the dbda8d6ce9 2007-07-21 drh: ** Free Software Foundation, Inc., 59 Temple Place - Suite 330, dbda8d6ce9 2007-07-21 drh: ** Boston, MA 02111-1307, USA. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Author contact information: dbda8d6ce9 2007-07-21 drh: ** drh@hwaci.com dbda8d6ce9 2007-07-21 drh: ** http://www.hwaci.com/drh/ dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ******************************************************************************* dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This file contains code to do formatting of wiki text. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #include <assert.h> dbda8d6ce9 2007-07-21 drh: #include "config.h" dbda8d6ce9 2007-07-21 drh: #include "wiki.h" dbda8d6ce9 2007-07-21 drh: b2e55c0d4d 2007-09-01 drh: b2e55c0d4d 2007-09-01 drh: /* b2e55c0d4d 2007-09-01 drh: ** Create a fake replicate of the "vfile" table as a TEMP table b2e55c0d4d 2007-09-01 drh: ** using the manifest identified by manid. b2e55c0d4d 2007-09-01 drh: */ b2e55c0d4d 2007-09-01 drh: static void create_fake_vfile(int manid){ b2e55c0d4d 2007-09-01 drh: static const char zVfileDef[] = b2e55c0d4d 2007-09-01 drh: @ CREATE TEMP TABLE vfile( b2e55c0d4d 2007-09-01 drh: @ id INTEGER PRIMARY KEY, -- ID of the checked out file b2e55c0d4d 2007-09-01 drh: @ vid INTEGER REFERENCES blob, -- The version this file is part of. b2e55c0d4d 2007-09-01 drh: @ chnged INT DEFAULT 0, -- 0:unchnged 1:edited 2:m-chng 3:m-add b2e55c0d4d 2007-09-01 drh: @ deleted BOOLEAN DEFAULT 0, -- True if deleted b2e55c0d4d 2007-09-01 drh: @ rid INTEGER, -- Originally from this repository record b2e55c0d4d 2007-09-01 drh: @ mrid INTEGER, -- Based on this record due to a merge b2e55c0d4d 2007-09-01 drh: @ pathname TEXT, -- Full pathname b2e55c0d4d 2007-09-01 drh: @ UNIQUE(pathname,vid) b2e55c0d4d 2007-09-01 drh: @ ); b2e55c0d4d 2007-09-01 drh: ; b2e55c0d4d 2007-09-01 drh: db_multi_exec(zVfileDef); b2e55c0d4d 2007-09-01 drh: load_vfile_from_rid(manid); b2e55c0d4d 2007-09-01 drh: } b2e55c0d4d 2007-09-01 drh: b2e55c0d4d 2007-09-01 drh: /* b2e55c0d4d 2007-09-01 drh: ** Locate the wiki page with the name zPageName and render it. b2e55c0d4d 2007-09-01 drh: */ b2e55c0d4d 2007-09-01 drh: static void locate_and_render_wikipage(const char *zPageName){ b2e55c0d4d 2007-09-01 drh: Stmt q; b2e55c0d4d 2007-09-01 drh: int id = 0; b2e55c0d4d 2007-09-01 drh: int rid = 0; b2e55c0d4d 2007-09-01 drh: int chnged = 0; b2e55c0d4d 2007-09-01 drh: char *zPathname = 0; b2e55c0d4d 2007-09-01 drh: db_prepare(&q, b2e55c0d4d 2007-09-01 drh: "SELECT id, rid, chnged, pathname FROM vfile" b2e55c0d4d 2007-09-01 drh: " WHERE (pathname='%q.wiki' OR pathname LIKE '%%/%q.wiki')" b2e55c0d4d 2007-09-01 drh: " AND NOT deleted", zPageName, zPageName b2e55c0d4d 2007-09-01 drh: ); b2e55c0d4d 2007-09-01 drh: if( db_step(&q)==SQLITE_ROW ){ b2e55c0d4d 2007-09-01 drh: id = db_column_int(&q, 0); b2e55c0d4d 2007-09-01 drh: rid = db_column_int(&q, 1); b2e55c0d4d 2007-09-01 drh: chnged = db_column_int(&q, 2); b2e55c0d4d 2007-09-01 drh: if( chnged || rid==0 ){ b2e55c0d4d 2007-09-01 drh: zPathname = db_column_malloc(&q, 3); b2e55c0d4d 2007-09-01 drh: } b2e55c0d4d 2007-09-01 drh: } b2e55c0d4d 2007-09-01 drh: db_finalize(&q); b2e55c0d4d 2007-09-01 drh: if( id ){ b2e55c0d4d 2007-09-01 drh: Blob page, src; b2e55c0d4d 2007-09-01 drh: char *zTitle = "wiki"; b2e55c0d4d 2007-09-01 drh: char *z; b2e55c0d4d 2007-09-01 drh: blob_zero(&src); b2e55c0d4d 2007-09-01 drh: if( zPathname ){ b2e55c0d4d 2007-09-01 drh: zPathname = mprintf("%s/%z", g.zLocalRoot, zPathname); b2e55c0d4d 2007-09-01 drh: blob_read_from_file(&src, zPathname); b2e55c0d4d 2007-09-01 drh: free(zPathname); b2e55c0d4d 2007-09-01 drh: }else{ b2e55c0d4d 2007-09-01 drh: content_get(rid, &src); b2e55c0d4d 2007-09-01 drh: } b2e55c0d4d 2007-09-01 drh: b2e55c0d4d 2007-09-01 drh: /* The wiki page content is now in src. Check to see if b2e55c0d4d 2007-09-01 drh: ** there is a <readonly/> or <appendonly/> element at the b2e55c0d4d 2007-09-01 drh: ** beginning of the content. b2e55c0d4d 2007-09-01 drh: */ b2e55c0d4d 2007-09-01 drh: z = blob_str(&src); b2e55c0d4d 2007-09-01 drh: while( isspace(*z) ) z++; b2e55c0d4d 2007-09-01 drh: if( strncmp(z, "<readonly/>", 11)==0 ){ b2e55c0d4d 2007-09-01 drh: z += 11; b2e55c0d4d 2007-09-01 drh: }else if( strncmp(z, "<appendonly/>", 13)==0 ){ b2e55c0d4d 2007-09-01 drh: z += 13; b2e55c0d4d 2007-09-01 drh: } b2e55c0d4d 2007-09-01 drh: b2e55c0d4d 2007-09-01 drh: /* Check for <title>...</title> markup and remove it if present. */ b2e55c0d4d 2007-09-01 drh: while( isspace(*z) ) z++; b2e55c0d4d 2007-09-01 drh: if( strncmp(z, "<title>", 7)==0 ){ b2e55c0d4d 2007-09-01 drh: int i; b2e55c0d4d 2007-09-01 drh: for(i=7; z[i] && z[i]!='<'; i++){} b2e55c0d4d 2007-09-01 drh: if( z[i]=='<' && strncmp(&z[i], "</title>", 8)==0 ){ b2e55c0d4d 2007-09-01 drh: zTitle = htmlize(&z[7], i-7); b2e55c0d4d 2007-09-01 drh: z = &z[i+8]; b2e55c0d4d 2007-09-01 drh: } b2e55c0d4d 2007-09-01 drh: } b2e55c0d4d 2007-09-01 drh: b2e55c0d4d 2007-09-01 drh: /* Render the page */ b2e55c0d4d 2007-09-01 drh: style_header(zTitle); b2e55c0d4d 2007-09-01 drh: blob_init(&page, z, -1); ab637af752 2007-09-28 drh: wiki_convert(&page, 0); b2e55c0d4d 2007-09-01 drh: blob_reset(&src); b2e55c0d4d 2007-09-01 drh: }else{ b2e55c0d4d 2007-09-01 drh: style_header("Unknown Wiki Page"); b2e55c0d4d 2007-09-01 drh: @ The wiki page "%h(zPageName)" does not exist. b2e55c0d4d 2007-09-01 drh: } b2e55c0d4d 2007-09-01 drh: style_footer(); b2e55c0d4d 2007-09-01 drh: } b2e55c0d4d 2007-09-01 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** WEBPAGE: wiki b2e55c0d4d 2007-09-01 drh: ** URL: /wiki/PAGENAME dbda8d6ce9 2007-07-21 drh: ** b2e55c0d4d 2007-09-01 drh: ** If the local database is available (which only happens if run b2e55c0d4d 2007-09-01 drh: ** as "server" instead of "cgi" or "http") then the file is taken b2e55c0d4d 2007-09-01 drh: ** from the local checkout. If there is no local checkout, then b2e55c0d4d 2007-09-01 drh: ** the content is taken from the "head" baseline. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: void wiki_page(void){ b2e55c0d4d 2007-09-01 drh: login_check_credentials(); b2e55c0d4d 2007-09-01 drh: if( !g.okRdWiki ){ login_needed(); return; } b2e55c0d4d 2007-09-01 drh: if( !g.localOpen ){ b2e55c0d4d 2007-09-01 drh: int headid = db_int(0, b2e55c0d4d 2007-09-01 drh: "SELECT cid FROM plink ORDER BY mtime DESC LIMIT 1" b2e55c0d4d 2007-09-01 drh: ); b2e55c0d4d 2007-09-01 drh: create_fake_vfile(headid); b2e55c0d4d 2007-09-01 drh: } b2e55c0d4d 2007-09-01 drh: locate_and_render_wikipage(g.zExtra); b2e55c0d4d 2007-09-01 drh: } b2e55c0d4d 2007-09-01 drh: b2e55c0d4d 2007-09-01 drh: /* b2e55c0d4d 2007-09-01 drh: ** The g.zExtra value is of the form UUID/otherstuff. b2e55c0d4d 2007-09-01 drh: ** Extract the UUID and convert it to a record id. Leave b2e55c0d4d 2007-09-01 drh: ** g.zExtra holding just otherstuff. If UUID does not exist b2e55c0d4d 2007-09-01 drh: ** or is malformed, return 0 and leave g.zExtra unchanged. b2e55c0d4d 2007-09-01 drh: */ b2e55c0d4d 2007-09-01 drh: int extract_uuid_from_url(void){ b2e55c0d4d 2007-09-01 drh: int i, rid; b2e55c0d4d 2007-09-01 drh: Blob uuid; b2e55c0d4d 2007-09-01 drh: for(i=0; g.zExtra[i] && g.zExtra[i]!='/'; i++){} b2e55c0d4d 2007-09-01 drh: blob_zero(&uuid); b2e55c0d4d 2007-09-01 drh: blob_append(&uuid, g.zExtra, i); b2e55c0d4d 2007-09-01 drh: rid = name_to_uuid(&uuid, 0); b2e55c0d4d 2007-09-01 drh: blob_reset(&uuid); b2e55c0d4d 2007-09-01 drh: if( rid ){ b2e55c0d4d 2007-09-01 drh: while( g.zExtra[i]=='/' ){ i++; } b2e55c0d4d 2007-09-01 drh: g.zExtra = &g.zExtra[i]; b2e55c0d4d 2007-09-01 drh: } b2e55c0d4d 2007-09-01 drh: return rid; b2e55c0d4d 2007-09-01 drh: } b2e55c0d4d 2007-09-01 drh: b2e55c0d4d 2007-09-01 drh: /* b2e55c0d4d 2007-09-01 drh: ** WEBPAGE: bwiki b2e55c0d4d 2007-09-01 drh: ** URL: /bwiki/UUID/PAGENAME b2e55c0d4d 2007-09-01 drh: ** b2e55c0d4d 2007-09-01 drh: ** UUID specifies a baseline. Render the wiki page PAGENAME as b2e55c0d4d 2007-09-01 drh: ** it appears in that baseline. b2e55c0d4d 2007-09-01 drh: */ b2e55c0d4d 2007-09-01 drh: void bwiki_page(void){ b2e55c0d4d 2007-09-01 drh: int headid; b2e55c0d4d 2007-09-01 drh: login_check_credentials(); b2e55c0d4d 2007-09-01 drh: if( !g.okRdWiki || !g.okHistory ){ login_needed(); return; } b2e55c0d4d 2007-09-01 drh: headid = extract_uuid_from_url(); b2e55c0d4d 2007-09-01 drh: if( headid ){ b2e55c0d4d 2007-09-01 drh: create_fake_vfile(headid); b2e55c0d4d 2007-09-01 drh: } b2e55c0d4d 2007-09-01 drh: locate_and_render_wikipage(g.zExtra); 22c1ac41d4 2007-08-23 drh: } 22c1ac41d4 2007-08-23 drh: 22c1ac41d4 2007-08-23 drh: /* 22c1ac41d4 2007-08-23 drh: ** WEBPAGE: ambiguous 22c1ac41d4 2007-08-23 drh: ** 22c1ac41d4 2007-08-23 drh: ** This is the destination for UUID hyperlinks that are ambiguous. 22c1ac41d4 2007-08-23 drh: ** Show all possible choices for the destination with links to each. 22c1ac41d4 2007-08-23 drh: ** 22c1ac41d4 2007-08-23 drh: ** The ambiguous UUID prefix is in g.zExtra 22c1ac41d4 2007-08-23 drh: */ 22c1ac41d4 2007-08-23 drh: void ambiguous_page(void){ 22c1ac41d4 2007-08-23 drh: Stmt q; 22c1ac41d4 2007-08-23 drh: style_header("Ambiguous UUID"); 22c1ac41d4 2007-08-23 drh: @ <p>The link <a href="%s(g.zBaseURL)/ambiguous/%T(g.zExtra)"> 22c1ac41d4 2007-08-23 drh: @ [%h(g.zExtra)]</a> is ambiguous. It might mean any of the following:</p> 22c1ac41d4 2007-08-23 drh: @ <ul> 22c1ac41d4 2007-08-23 drh: db_prepare(&q, "SELECT uuid, rid FROM blob WHERE uuid>=%Q AND uuid<'%qz'" 22c1ac41d4 2007-08-23 drh: " ORDER BY uuid", g.zExtra, g.zExtra); 22c1ac41d4 2007-08-23 drh: while( db_step(&q)==SQLITE_ROW ){ 22c1ac41d4 2007-08-23 drh: const char *zUuid = db_column_text(&q, 0); 22c1ac41d4 2007-08-23 drh: int rid = db_column_int(&q, 1); 22c1ac41d4 2007-08-23 drh: @ <li> %s(zUuid) - %d(rid) 22c1ac41d4 2007-08-23 drh: } 22c1ac41d4 2007-08-23 drh: db_finalize(&q); 22c1ac41d4 2007-08-23 drh: @ </ul> dbda8d6ce9 2007-07-21 drh: style_footer(); dbda8d6ce9 2007-07-21 drh: }