dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Copyright (c) 2007 D. Richard Hipp bfb4d414dd 2008-05-15 stephan: ** Copyright (c) 2008 Stephan Beal 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> 5fb1152dab 2008-05-14 stephan: #include <ctype.h> dbda8d6ce9 2007-07-21 drh: #include "config.h" dbda8d6ce9 2007-07-21 drh: #include "wiki.h" dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* 488afb9746 2007-10-06 drh: ** Return true if the input string is a well-formed wiki page name. 488afb9746 2007-10-06 drh: ** 488afb9746 2007-10-06 drh: ** Well-formed wiki page names do not begin or end with whitespace, 488afb9746 2007-10-06 drh: ** and do not contain tabs or other control characters and do not 488afb9746 2007-10-06 drh: ** contain more than a single space character in a row. Well-formed 488afb9746 2007-10-06 drh: ** names must be between 3 and 100 chracters in length, inclusive. 488afb9746 2007-10-06 drh: */ 488afb9746 2007-10-06 drh: int wiki_name_is_wellformed(const char *z){ 488afb9746 2007-10-06 drh: int i; 488afb9746 2007-10-06 drh: if( z[0]<=0x20 ){ 488afb9746 2007-10-06 drh: return 0; 488afb9746 2007-10-06 drh: } 488afb9746 2007-10-06 drh: for(i=1; z[i]; i++){ 488afb9746 2007-10-06 drh: if( z[i]<0x20 ) return 0; 488afb9746 2007-10-06 drh: if( z[i]==0x20 && z[i-1]==0x20 ) return 0; 488afb9746 2007-10-06 drh: } 488afb9746 2007-10-06 drh: if( z[i-1]==' ' ) return 0; 488afb9746 2007-10-06 drh: if( i<3 || i>100 ) return 0; 488afb9746 2007-10-06 drh: return 1; 488afb9746 2007-10-06 drh: } 488afb9746 2007-10-06 drh: 488afb9746 2007-10-06 drh: /* aa57354736 2009-09-15 drh: ** Output rules for well-formed wiki pages aa57354736 2009-09-15 drh: */ aa57354736 2009-09-15 drh: static void well_formed_wiki_name_rules(void){ aa57354736 2009-09-15 drh: @ <ul> aa57354736 2009-09-15 drh: @ <li> Must not begin or end with a space. aa57354736 2009-09-15 drh: @ <li> Must not contain any control characters, including tab or aa57354736 2009-09-15 drh: @ newline. aa57354736 2009-09-15 drh: @ <li> Must not have two or more spaces in a row internally. aa57354736 2009-09-15 drh: @ <li> Must be between 3 and 100 characters in length. aa57354736 2009-09-15 drh: @ </ul> aa57354736 2009-09-15 drh: } aa57354736 2009-09-15 drh: aa57354736 2009-09-15 drh: /* 488afb9746 2007-10-06 drh: ** Check a wiki name. If it is not well-formed, then issue an error 488afb9746 2007-10-06 drh: ** and return true. If it is well-formed, return false. 488afb9746 2007-10-06 drh: */ 488afb9746 2007-10-06 drh: static int check_name(const char *z){ 488afb9746 2007-10-06 drh: if( !wiki_name_is_wellformed(z) ){ 488afb9746 2007-10-06 drh: style_header("Wiki Page Name Error"); 488afb9746 2007-10-06 drh: @ The wiki name "<b>%h(z)</b>" is not well-formed. Rules for 488afb9746 2007-10-06 drh: @ wiki page names: aa57354736 2009-09-15 drh: well_formed_wiki_name_rules(); 488afb9746 2007-10-06 drh: style_footer(); 488afb9746 2007-10-06 drh: return 1; 488afb9746 2007-10-06 drh: } 488afb9746 2007-10-06 drh: return 0; 488afb9746 2007-10-06 drh: } 488afb9746 2007-10-06 drh: 488afb9746 2007-10-06 drh: /* 50a58adb76 2007-10-10 drh: ** WEBPAGE: home 50a58adb76 2007-10-10 drh: ** WEBPAGE: index 50a58adb76 2007-10-10 drh: ** WEBPAGE: not_found 50a58adb76 2007-10-10 drh: */ 50a58adb76 2007-10-10 drh: void home_page(void){ 50a58adb76 2007-10-10 drh: char *zPageName = db_get("project-name",0); 19f5d0b15f 2008-11-20 drh: login_check_credentials(); 19f5d0b15f 2008-11-20 drh: if( !g.okRdWiki ){ 0a523be389 2008-11-20 drh: cgi_redirectf("%s/login?g=%s/home", g.zBaseURL, g.zBaseURL); 19f5d0b15f 2008-11-20 drh: } 50a58adb76 2007-10-10 drh: if( zPageName ){ 50a58adb76 2007-10-10 drh: login_check_credentials(); 50a58adb76 2007-10-10 drh: g.zExtra = zPageName; 677aa71bca 2007-10-12 drh: cgi_set_parameter_nocopy("name", g.zExtra); 426a3ba49e 2008-12-03 drh: g.isHome = 1; 50a58adb76 2007-10-10 drh: wiki_page(); 50a58adb76 2007-10-10 drh: return; 50a58adb76 2007-10-10 drh: } 50a58adb76 2007-10-10 drh: style_header("Home"); 50a58adb76 2007-10-10 drh: @ <p>This is a stub home-page for the project. 50a58adb76 2007-10-10 drh: @ To fill in this page, first go to 50a58adb76 2007-10-10 drh: @ <a href="%s(g.zBaseURL)/setup_config">setup/config</a> 50a58adb76 2007-10-10 drh: @ and establish a "Project Name". Then create a 50a58adb76 2007-10-10 drh: @ wiki page with that name. The content of that wiki page 50a58adb76 2007-10-10 drh: @ will be displayed in place of this message. b2e55c0d4d 2007-09-01 drh: style_footer(); 50a58adb76 2007-10-10 drh: } 50a58adb76 2007-10-10 drh: 50a58adb76 2007-10-10 drh: /* f08adf3d58 2007-10-28 drh: ** Return true if the given pagename is the name of the sandbox f08adf3d58 2007-10-28 drh: */ f08adf3d58 2007-10-28 drh: static int is_sandbox(const char *zPagename){ f08adf3d58 2007-10-28 drh: return strcasecmp(zPagename,"sandbox")==0 || f08adf3d58 2007-10-28 drh: strcasecmp(zPagename,"sand box")==0; b2e55c0d4d 2007-09-01 drh: } b2e55c0d4d 2007-09-01 drh: b2e55c0d4d 2007-09-01 drh: /* dbda8d6ce9 2007-07-21 drh: ** WEBPAGE: wiki 677aa71bca 2007-10-12 drh: ** URL: /wiki?name=PAGENAME dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: void wiki_page(void){ bf428e6854 2007-10-06 drh: char *zTag; e8c4f69c50 2008-10-24 drh: int rid = 0; f08adf3d58 2007-10-28 drh: int isSandbox; bf428e6854 2007-10-06 drh: Blob wiki; bf428e6854 2007-10-06 drh: Manifest m; 677aa71bca 2007-10-12 drh: const char *zPageName; bf428e6854 2007-10-06 drh: char *zBody = mprintf("%s","<i>Empty Page</i>"); bf428e6854 2007-10-06 drh: b2e55c0d4d 2007-09-01 drh: login_check_credentials(); b2e55c0d4d 2007-09-01 drh: if( !g.okRdWiki ){ login_needed(); return; } f40230a7e8 2007-10-28 drh: zPageName = P("name"); f40230a7e8 2007-10-28 drh: if( zPageName==0 ){ f08adf3d58 2007-10-28 drh: style_header("Wiki"); f08adf3d58 2007-10-28 drh: @ <ul> 82136b0a5f 2008-07-17 eric: { char *zHomePageName = db_get("project-name",0); 82136b0a5f 2008-07-17 eric: if( zHomePageName ){ dec4685720 2009-09-15 drh: @ <li> <a href="%s(g.zBaseURL)/wiki?name=%t(zHomePageName)"> dec4685720 2009-09-15 drh: @ %h(zHomePageName)</a> wiki home page.</li> 82136b0a5f 2008-07-17 eric: } 82136b0a5f 2008-07-17 eric: } f08adf3d58 2007-10-28 drh: @ <li> <a href="%s(g.zBaseURL)/timeline?y=w">Recent changes</a> to wiki f08adf3d58 2007-10-28 drh: @ pages. </li> f08adf3d58 2007-10-28 drh: @ <li> <a href="%s(g.zBaseURL)/wiki_rules">Formatting rules</a> for f08adf3d58 2007-10-28 drh: @ wiki.</li> f08adf3d58 2007-10-28 drh: @ <li> Use the <a href="%s(g.zBaseURL)/wiki?name=Sandbox">Sandbox</a> f08adf3d58 2007-10-28 drh: @ to experiment.</li> aa57354736 2009-09-15 drh: if( g.okNewWiki ){ aa57354736 2009-09-15 drh: @ <li> Create a <a href="%s(g.zBaseURL)/wikinew">new wiki page</a>.</li> aa57354736 2009-09-15 drh: } f08adf3d58 2007-10-28 drh: @ <li> <a href="%s(g.zBaseURL)/wcontent">List of All Wiki Pages</a> f08adf3d58 2007-10-28 drh: @ available on this server.</li> f08adf3d58 2007-10-28 drh: @ </ul> f08adf3d58 2007-10-28 drh: style_footer(); f40230a7e8 2007-10-28 drh: return; f40230a7e8 2007-10-28 drh: } 488afb9746 2007-10-06 drh: if( check_name(zPageName) ) return; f08adf3d58 2007-10-28 drh: isSandbox = is_sandbox(zPageName); f08adf3d58 2007-10-28 drh: if( isSandbox ){ f08adf3d58 2007-10-28 drh: zBody = db_get("sandbox",zBody); f08adf3d58 2007-10-28 drh: }else{ f08adf3d58 2007-10-28 drh: zTag = mprintf("wiki-%s", zPageName); f08adf3d58 2007-10-28 drh: rid = db_int(0, f08adf3d58 2007-10-28 drh: "SELECT rid FROM tagxref" f08adf3d58 2007-10-28 drh: " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)" f08adf3d58 2007-10-28 drh: " ORDER BY mtime DESC", zTag f08adf3d58 2007-10-28 drh: ); f08adf3d58 2007-10-28 drh: free(zTag); f08adf3d58 2007-10-28 drh: memset(&m, 0, sizeof(m)); f08adf3d58 2007-10-28 drh: blob_zero(&m.content); f08adf3d58 2007-10-28 drh: if( rid ){ f08adf3d58 2007-10-28 drh: Blob content; f08adf3d58 2007-10-28 drh: content_get(rid, &content); f08adf3d58 2007-10-28 drh: manifest_parse(&m, &content); f08adf3d58 2007-10-28 drh: if( m.type==CFTYPE_WIKI ){ f08adf3d58 2007-10-28 drh: zBody = m.zWiki; f08adf3d58 2007-10-28 drh: } f08adf3d58 2007-10-28 drh: } f08adf3d58 2007-10-28 drh: } 426a3ba49e 2008-12-03 drh: if( !g.isHome ){ b12a031557 2008-12-26 drh: if( (rid && g.okWrWiki) || (!rid && g.okNewWiki) ){ bdde7ddcc8 2008-11-18 drh: style_submenu_element("Edit", "Edit Wiki Page", "%s/wikiedit?name=%T", bdde7ddcc8 2008-11-18 drh: g.zTop, zPageName); bdde7ddcc8 2008-11-18 drh: } b12a031557 2008-12-26 drh: if( rid && g.okApndWiki ){ bdde7ddcc8 2008-11-18 drh: style_submenu_element("Append", "Add A Comment", "%s/wikiappend?name=%T", bdde7ddcc8 2008-11-18 drh: g.zTop, zPageName); bdde7ddcc8 2008-11-18 drh: } b12a031557 2008-12-26 drh: if( g.okHistory ){ bdde7ddcc8 2008-11-18 drh: style_submenu_element("History", "History", "%s/whistory?name=%T", bdde7ddcc8 2008-11-18 drh: g.zTop, zPageName); bdde7ddcc8 2008-11-18 drh: } bdde7ddcc8 2008-11-18 drh: } dec4685720 2009-09-15 drh: style_header(zPageName); bf428e6854 2007-10-06 drh: blob_init(&wiki, zBody, -1); c963a7763d 2007-10-13 drh: wiki_convert(&wiki, 0, 0); bf428e6854 2007-10-06 drh: blob_reset(&wiki); f08adf3d58 2007-10-28 drh: if( !isSandbox ){ f08adf3d58 2007-10-28 drh: manifest_clear(&m); bf428e6854 2007-10-06 drh: } bf428e6854 2007-10-06 drh: style_footer(); bf428e6854 2007-10-06 drh: } bf428e6854 2007-10-06 drh: bf428e6854 2007-10-06 drh: /* bf428e6854 2007-10-06 drh: ** WEBPAGE: wikiedit f40230a7e8 2007-10-28 drh: ** URL: /wikiedit?name=PAGENAME bf428e6854 2007-10-06 drh: */ bf428e6854 2007-10-06 drh: void wikiedit_page(void){ bf428e6854 2007-10-06 drh: char *zTag; 01d3c33874 2008-02-02 stephan: int rid = 0; f08adf3d58 2007-10-28 drh: int isSandbox; bf428e6854 2007-10-06 drh: Blob wiki; bf428e6854 2007-10-06 drh: Manifest m; 677aa71bca 2007-10-12 drh: const char *zPageName; bf428e6854 2007-10-06 drh: char *zHtmlPageName; bf428e6854 2007-10-06 drh: int n; bf428e6854 2007-10-06 drh: const char *z; bf428e6854 2007-10-06 drh: char *zBody = (char*)P("w"); bf428e6854 2007-10-06 drh: bf428e6854 2007-10-06 drh: if( zBody ){ bf428e6854 2007-10-06 drh: zBody = mprintf("%s", zBody); bf428e6854 2007-10-06 drh: } bf428e6854 2007-10-06 drh: login_check_credentials(); 677aa71bca 2007-10-12 drh: zPageName = PD("name",""); 488afb9746 2007-10-06 drh: if( check_name(zPageName) ) return; f08adf3d58 2007-10-28 drh: isSandbox = is_sandbox(zPageName); f08adf3d58 2007-10-28 drh: if( isSandbox ){ 2a3e85f2d5 2008-12-26 drh: if( !g.okWrWiki ){ 2a3e85f2d5 2008-12-26 drh: login_needed(); 2a3e85f2d5 2008-12-26 drh: return; 2a3e85f2d5 2008-12-26 drh: } f08adf3d58 2007-10-28 drh: if( zBody==0 ){ f08adf3d58 2007-10-28 drh: zBody = db_get("sandbox",""); f08adf3d58 2007-10-28 drh: } f08adf3d58 2007-10-28 drh: }else{ f08adf3d58 2007-10-28 drh: zTag = mprintf("wiki-%s", zPageName); f08adf3d58 2007-10-28 drh: rid = db_int(0, f08adf3d58 2007-10-28 drh: "SELECT rid FROM tagxref" f08adf3d58 2007-10-28 drh: " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)" f08adf3d58 2007-10-28 drh: " ORDER BY mtime DESC", zTag f08adf3d58 2007-10-28 drh: ); f08adf3d58 2007-10-28 drh: free(zTag); f08adf3d58 2007-10-28 drh: if( (rid && !g.okWrWiki) || (!rid && !g.okNewWiki) ){ f08adf3d58 2007-10-28 drh: login_needed(); f08adf3d58 2007-10-28 drh: return; f08adf3d58 2007-10-28 drh: } f08adf3d58 2007-10-28 drh: memset(&m, 0, sizeof(m)); f08adf3d58 2007-10-28 drh: blob_zero(&m.content); f08adf3d58 2007-10-28 drh: if( rid && zBody==0 ){ f08adf3d58 2007-10-28 drh: Blob content; f08adf3d58 2007-10-28 drh: content_get(rid, &content); f08adf3d58 2007-10-28 drh: manifest_parse(&m, &content); f08adf3d58 2007-10-28 drh: if( m.type==CFTYPE_WIKI ){ f08adf3d58 2007-10-28 drh: zBody = m.zWiki; f08adf3d58 2007-10-28 drh: } bf428e6854 2007-10-06 drh: } bf428e6854 2007-10-06 drh: } bf428e6854 2007-10-06 drh: if( P("submit")!=0 && zBody!=0 ){ bf428e6854 2007-10-06 drh: char *zDate; bf428e6854 2007-10-06 drh: Blob cksum; bf428e6854 2007-10-06 drh: int nrid; bf428e6854 2007-10-06 drh: blob_zero(&wiki); bf428e6854 2007-10-06 drh: db_begin_transaction(); f08adf3d58 2007-10-28 drh: if( isSandbox ){ f08adf3d58 2007-10-28 drh: db_set("sandbox",zBody,0); f08adf3d58 2007-10-28 drh: }else{ 0be54823ba 2008-10-18 drh: login_verify_csrf_secret(); f08adf3d58 2007-10-28 drh: zDate = db_text(0, "SELECT datetime('now')"); f08adf3d58 2007-10-28 drh: zDate[10] = 'T'; f08adf3d58 2007-10-28 drh: blob_appendf(&wiki, "D %s\n", zDate); f08adf3d58 2007-10-28 drh: free(zDate); f08adf3d58 2007-10-28 drh: blob_appendf(&wiki, "L %F\n", zPageName); f08adf3d58 2007-10-28 drh: if( rid ){ f08adf3d58 2007-10-28 drh: char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); f08adf3d58 2007-10-28 drh: blob_appendf(&wiki, "P %s\n", zUuid); f08adf3d58 2007-10-28 drh: free(zUuid); f08adf3d58 2007-10-28 drh: } f08adf3d58 2007-10-28 drh: if( g.zLogin ){ f08adf3d58 2007-10-28 drh: blob_appendf(&wiki, "U %F\n", g.zLogin); f08adf3d58 2007-10-28 drh: } f08adf3d58 2007-10-28 drh: blob_appendf(&wiki, "W %d\n%s\n", strlen(zBody), zBody); f08adf3d58 2007-10-28 drh: md5sum_blob(&wiki, &cksum); f08adf3d58 2007-10-28 drh: blob_appendf(&wiki, "Z %b\n", &cksum); f08adf3d58 2007-10-28 drh: blob_reset(&cksum); f08adf3d58 2007-10-28 drh: nrid = content_put(&wiki, 0, 0); f08adf3d58 2007-10-28 drh: db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid); f08adf3d58 2007-10-28 drh: manifest_crosslink(nrid, &wiki); f08adf3d58 2007-10-28 drh: blob_reset(&wiki); f08adf3d58 2007-10-28 drh: content_deltify(rid, nrid, 0); f08adf3d58 2007-10-28 drh: } bf428e6854 2007-10-06 drh: db_end_transaction(0); df646a7f4c 2007-10-12 drh: cgi_redirectf("wiki?name=%T", zPageName); bf428e6854 2007-10-06 drh: } bf428e6854 2007-10-06 drh: if( P("cancel")!=0 ){ df646a7f4c 2007-10-12 drh: cgi_redirectf("wiki?name=%T", zPageName); bf428e6854 2007-10-06 drh: return; bf428e6854 2007-10-06 drh: } bf428e6854 2007-10-06 drh: if( zBody==0 ){ bf428e6854 2007-10-06 drh: zBody = mprintf("<i>Empty Page</i>"); bf428e6854 2007-10-06 drh: } dec4685720 2009-09-15 drh: zHtmlPageName = mprintf("Edit: %s", zPageName); bf428e6854 2007-10-06 drh: style_header(zHtmlPageName); bf428e6854 2007-10-06 drh: if( P("preview")!=0 ){ bf428e6854 2007-10-06 drh: blob_zero(&wiki); bf428e6854 2007-10-06 drh: blob_append(&wiki, zBody, -1); bf428e6854 2007-10-06 drh: @ Preview:<hr> c963a7763d 2007-10-13 drh: wiki_convert(&wiki, 0, 0); bf428e6854 2007-10-06 drh: @ <hr> bf428e6854 2007-10-06 drh: blob_reset(&wiki); bf428e6854 2007-10-06 drh: } bf428e6854 2007-10-06 drh: for(n=2, z=zBody; z[0]; z++){ bf428e6854 2007-10-06 drh: if( z[0]=='\n' ) n++; bf428e6854 2007-10-06 drh: } bf428e6854 2007-10-06 drh: if( n<20 ) n = 20; e01aa8cb4b 2008-07-17 drh: if( n>40 ) n = 40; 677aa71bca 2007-10-12 drh: @ <form method="POST" action="%s(g.zBaseURL)/wikiedit"> 0be54823ba 2008-10-18 drh: login_insert_csrf_secret(); df646a7f4c 2007-10-12 drh: @ <input type="hidden" name="name" value="%h(zPageName)"> bf428e6854 2007-10-06 drh: @ <textarea name="w" class="wikiedit" cols="80" bf428e6854 2007-10-06 drh: @ rows="%d(n)" wrap="virtual">%h(zBody)</textarea> bf428e6854 2007-10-06 drh: @ <br> bf428e6854 2007-10-06 drh: @ <input type="submit" name="preview" value="Preview Your Changes"> bf428e6854 2007-10-06 drh: @ <input type="submit" name="submit" value="Apply These Changes"> bf428e6854 2007-10-06 drh: @ <input type="submit" name="cancel" value="Cancel"> bf428e6854 2007-10-06 drh: @ </form> f08adf3d58 2007-10-28 drh: if( !isSandbox ){ f08adf3d58 2007-10-28 drh: manifest_clear(&m); f08adf3d58 2007-10-28 drh: } f08adf3d58 2007-10-28 drh: style_footer(); f08adf3d58 2007-10-28 drh: } f08adf3d58 2007-10-28 drh: f08adf3d58 2007-10-28 drh: /* aa57354736 2009-09-15 drh: ** WEBPAGE: wikinew aa57354736 2009-09-15 drh: ** URL /wikinew aa57354736 2009-09-15 drh: ** aa57354736 2009-09-15 drh: ** Prompt the user to enter the name of a new wiki page. Then redirect aa57354736 2009-09-15 drh: ** to the wikiedit screen for that new page. aa57354736 2009-09-15 drh: */ aa57354736 2009-09-15 drh: void wikinew_page(void){ aa57354736 2009-09-15 drh: const char *zName; aa57354736 2009-09-15 drh: login_check_credentials(); aa57354736 2009-09-15 drh: if( !g.okNewWiki ){ aa57354736 2009-09-15 drh: login_needed(); aa57354736 2009-09-15 drh: return; aa57354736 2009-09-15 drh: } aa57354736 2009-09-15 drh: zName = PD("name",""); aa57354736 2009-09-15 drh: if( zName[0] && wiki_name_is_wellformed(zName) ){ aa57354736 2009-09-15 drh: cgi_redirectf("wikiedit?name=%T", zName); aa57354736 2009-09-15 drh: } aa57354736 2009-09-15 drh: style_header("Create A New Wiki Page"); aa57354736 2009-09-15 drh: @ <p>Rules for wiki page names: aa57354736 2009-09-15 drh: well_formed_wiki_name_rules(); aa57354736 2009-09-15 drh: @ </p> aa57354736 2009-09-15 drh: @ <form method="POST" action="%s(g.zBaseURL)/wikinew"> aa57354736 2009-09-15 drh: @ <p>Name of new wiki page: aa57354736 2009-09-15 drh: @ <input type="text" width="35" name="name" value="%h(zName)"> aa57354736 2009-09-15 drh: @ <input type="submit" value="Create"> aa57354736 2009-09-15 drh: @ </p></form> aa57354736 2009-09-15 drh: if( zName[0] ){ aa57354736 2009-09-15 drh: @ <p><b><font color="red"> aa57354736 2009-09-15 drh: @ "%h(zName)" is not a valid wiki page name!</font></b></p> aa57354736 2009-09-15 drh: } 61ce5e3685 2007-10-10 drh: style_footer(); 61ce5e3685 2007-10-10 drh: } aa57354736 2009-09-15 drh: 61ce5e3685 2007-10-10 drh: 61ce5e3685 2007-10-10 drh: /* 61ce5e3685 2007-10-10 drh: ** Append the wiki text for an remark to the end of the given BLOB. 61ce5e3685 2007-10-10 drh: */ 61ce5e3685 2007-10-10 drh: static void appendRemark(Blob *p){ 61ce5e3685 2007-10-10 drh: char *zDate; 61ce5e3685 2007-10-10 drh: const char *zUser; 61ce5e3685 2007-10-10 drh: const char *zRemark; e01aa8cb4b 2008-07-17 drh: char *zId; 61ce5e3685 2007-10-10 drh: 61ce5e3685 2007-10-10 drh: zDate = db_text(0, "SELECT datetime('now')"); e01aa8cb4b 2008-07-17 drh: zId = db_text(0, "SELECT lower(hex(randomblob(8)))"); e01aa8cb4b 2008-07-17 drh: blob_appendf(p, "\n\n<hr><div id=\"%s\"><i>On %s UTC %h", e01aa8cb4b 2008-07-17 drh: zId, zDate, g.zLogin); 61ce5e3685 2007-10-10 drh: free(zDate); 61ce5e3685 2007-10-10 drh: zUser = PD("u",g.zLogin); 61ce5e3685 2007-10-10 drh: if( zUser[0] && strcmp(zUser,g.zLogin) ){ 61ce5e3685 2007-10-10 drh: blob_appendf(p, " (claiming to be %h)", zUser); 61ce5e3685 2007-10-10 drh: } 61ce5e3685 2007-10-10 drh: zRemark = PD("r",""); e01aa8cb4b 2008-07-17 drh: blob_appendf(p, " added:</i><br />\n%s</div id=\"%s\">", zRemark, zId); 61ce5e3685 2007-10-10 drh: } 61ce5e3685 2007-10-10 drh: 61ce5e3685 2007-10-10 drh: /* 61ce5e3685 2007-10-10 drh: ** WEBPAGE: wikiappend 677aa71bca 2007-10-12 drh: ** URL: /wikiappend?name=PAGENAME 61ce5e3685 2007-10-10 drh: */ 61ce5e3685 2007-10-10 drh: void wikiappend_page(void){ 61ce5e3685 2007-10-10 drh: char *zTag; 01d3c33874 2008-02-02 stephan: int rid = 0; f08adf3d58 2007-10-28 drh: int isSandbox; 677aa71bca 2007-10-12 drh: const char *zPageName; 61ce5e3685 2007-10-10 drh: char *zHtmlPageName; 61ce5e3685 2007-10-10 drh: const char *zUser; 61ce5e3685 2007-10-10 drh: 61ce5e3685 2007-10-10 drh: login_check_credentials(); 677aa71bca 2007-10-12 drh: zPageName = PD("name",""); 61ce5e3685 2007-10-10 drh: if( check_name(zPageName) ) return; f08adf3d58 2007-10-28 drh: isSandbox = is_sandbox(zPageName); f08adf3d58 2007-10-28 drh: if( !isSandbox ){ f08adf3d58 2007-10-28 drh: zTag = mprintf("wiki-%s", zPageName); f08adf3d58 2007-10-28 drh: rid = db_int(0, f08adf3d58 2007-10-28 drh: "SELECT rid FROM tagxref" f08adf3d58 2007-10-28 drh: " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)" f08adf3d58 2007-10-28 drh: " ORDER BY mtime DESC", zTag b2e55c0d4d 2007-09-01 drh: ); f08adf3d58 2007-10-28 drh: free(zTag); f08adf3d58 2007-10-28 drh: if( !rid ){ e01aa8cb4b 2008-07-17 drh: fossil_redirect_home(); f08adf3d58 2007-10-28 drh: return; f08adf3d58 2007-10-28 drh: } 61ce5e3685 2007-10-10 drh: } 61ce5e3685 2007-10-10 drh: if( !g.okApndWiki ){ 61ce5e3685 2007-10-10 drh: login_needed(); 61ce5e3685 2007-10-10 drh: return; 61ce5e3685 2007-10-10 drh: } 61ce5e3685 2007-10-10 drh: if( P("submit")!=0 && P("r")!=0 && P("u")!=0 ){ 61ce5e3685 2007-10-10 drh: char *zDate; 61ce5e3685 2007-10-10 drh: Blob cksum; 61ce5e3685 2007-10-10 drh: int nrid; 61ce5e3685 2007-10-10 drh: Blob body; 61ce5e3685 2007-10-10 drh: Blob content; 61ce5e3685 2007-10-10 drh: Blob wiki; 61ce5e3685 2007-10-10 drh: Manifest m; 61ce5e3685 2007-10-10 drh: 61ce5e3685 2007-10-10 drh: blob_zero(&body); f08adf3d58 2007-10-28 drh: if( isSandbox ){ f08adf3d58 2007-10-28 drh: blob_appendf(&body, db_get("sandbox","")); f08adf3d58 2007-10-28 drh: appendRemark(&body); f08adf3d58 2007-10-28 drh: db_set("sandbox", blob_str(&body), 0); f08adf3d58 2007-10-28 drh: }else{ 0be54823ba 2008-10-18 drh: login_verify_csrf_secret(); f08adf3d58 2007-10-28 drh: content_get(rid, &content); f08adf3d58 2007-10-28 drh: manifest_parse(&m, &content); f08adf3d58 2007-10-28 drh: if( m.type==CFTYPE_WIKI ){ e01aa8cb4b 2008-07-17 drh: blob_append(&body, m.zWiki, -1); f08adf3d58 2007-10-28 drh: } f08adf3d58 2007-10-28 drh: manifest_clear(&m); f08adf3d58 2007-10-28 drh: blob_zero(&wiki); f08adf3d58 2007-10-28 drh: db_begin_transaction(); f08adf3d58 2007-10-28 drh: zDate = db_text(0, "SELECT datetime('now')"); f08adf3d58 2007-10-28 drh: zDate[10] = 'T'; f08adf3d58 2007-10-28 drh: blob_appendf(&wiki, "D %s\n", zDate); f08adf3d58 2007-10-28 drh: blob_appendf(&wiki, "L %F\n", zPageName); f08adf3d58 2007-10-28 drh: if( rid ){ f08adf3d58 2007-10-28 drh: char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); f08adf3d58 2007-10-28 drh: blob_appendf(&wiki, "P %s\n", zUuid); f08adf3d58 2007-10-28 drh: free(zUuid); f08adf3d58 2007-10-28 drh: } f08adf3d58 2007-10-28 drh: if( g.zLogin ){ f08adf3d58 2007-10-28 drh: blob_appendf(&wiki, "U %F\n", g.zLogin); f08adf3d58 2007-10-28 drh: } f08adf3d58 2007-10-28 drh: appendRemark(&body); f08adf3d58 2007-10-28 drh: blob_appendf(&wiki, "W %d\n%s\n", blob_size(&body), blob_str(&body)); f08adf3d58 2007-10-28 drh: md5sum_blob(&wiki, &cksum); f08adf3d58 2007-10-28 drh: blob_appendf(&wiki, "Z %b\n", &cksum); f08adf3d58 2007-10-28 drh: blob_reset(&cksum); f08adf3d58 2007-10-28 drh: nrid = content_put(&wiki, 0, 0); f08adf3d58 2007-10-28 drh: db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid); f08adf3d58 2007-10-28 drh: manifest_crosslink(nrid, &wiki); f08adf3d58 2007-10-28 drh: blob_reset(&wiki); f08adf3d58 2007-10-28 drh: content_deltify(rid, nrid, 0); f08adf3d58 2007-10-28 drh: db_end_transaction(0); 61ce5e3685 2007-10-10 drh: } df646a7f4c 2007-10-12 drh: cgi_redirectf("wiki?name=%T", zPageName); 61ce5e3685 2007-10-10 drh: } 61ce5e3685 2007-10-10 drh: if( P("cancel")!=0 ){ df646a7f4c 2007-10-12 drh: cgi_redirectf("wiki?name=%T", zPageName); 61ce5e3685 2007-10-10 drh: return; 61ce5e3685 2007-10-10 drh: } aa57354736 2009-09-15 drh: zHtmlPageName = mprintf("Append Comment To: %s", zPageName); 61ce5e3685 2007-10-10 drh: style_header(zHtmlPageName); 61ce5e3685 2007-10-10 drh: if( P("preview")!=0 ){ 61ce5e3685 2007-10-10 drh: Blob preview; 61ce5e3685 2007-10-10 drh: blob_zero(&preview); 61ce5e3685 2007-10-10 drh: appendRemark(&preview); 61ce5e3685 2007-10-10 drh: @ Preview:<hr> c963a7763d 2007-10-13 drh: wiki_convert(&preview, 0, 0); 61ce5e3685 2007-10-10 drh: @ <hr> 61ce5e3685 2007-10-10 drh: blob_reset(&preview); b2e55c0d4d 2007-09-01 drh: } 61ce5e3685 2007-10-10 drh: zUser = PD("u", g.zLogin); 677aa71bca 2007-10-12 drh: @ <form method="POST" action="%s(g.zBaseURL)/wikiappend"> 0be54823ba 2008-10-18 drh: login_insert_csrf_secret(); df646a7f4c 2007-10-12 drh: @ <input type="hidden" name="name" value="%h(zPageName)"> 61ce5e3685 2007-10-10 drh: @ Your Name: 61ce5e3685 2007-10-10 drh: @ <input type="text" name="u" size="20" value="%h(zUser)"><br> 61ce5e3685 2007-10-10 drh: @ Comment to append:<br> 61ce5e3685 2007-10-10 drh: @ <textarea name="r" class="wikiedit" cols="80" 61ce5e3685 2007-10-10 drh: @ rows="10" wrap="virtual">%h(PD("r",""))</textarea> 61ce5e3685 2007-10-10 drh: @ <br> 61ce5e3685 2007-10-10 drh: @ <input type="submit" name="preview" value="Preview Your Comment"> 61ce5e3685 2007-10-10 drh: @ <input type="submit" name="submit" value="Append Your Changes"> 61ce5e3685 2007-10-10 drh: @ <input type="submit" name="cancel" value="Cancel"> 61ce5e3685 2007-10-10 drh: @ </form> 50a58adb76 2007-10-10 drh: style_footer(); 61ce5e3685 2007-10-10 drh: } 61ce5e3685 2007-10-10 drh: 61ce5e3685 2007-10-10 drh: /* 8e3b7fab9f 2009-08-27 drh: ** Name of the wiki history page being generated 8e3b7fab9f 2009-08-27 drh: */ 8e3b7fab9f 2009-08-27 drh: static const char *zWikiPageName; 8e3b7fab9f 2009-08-27 drh: 8e3b7fab9f 2009-08-27 drh: /* 8e3b7fab9f 2009-08-27 drh: ** Function called to output extra text at the end of each line in 8e3b7fab9f 2009-08-27 drh: ** a wiki history listing. 8e3b7fab9f 2009-08-27 drh: */ 8e3b7fab9f 2009-08-27 drh: static void wiki_history_extra(int rid){ aa57354736 2009-09-15 drh: @ <a href="%s(g.zTop)/wdiff?name=%t(zWikiPageName)&a=%d(rid)">[diff]</a> 50a58adb76 2007-10-10 drh: } 50a58adb76 2007-10-10 drh: 50a58adb76 2007-10-10 drh: /* 50a58adb76 2007-10-10 drh: ** WEBPAGE: whistory 677aa71bca 2007-10-12 drh: ** URL: /whistory?name=PAGENAME 677aa71bca 2007-10-12 drh: ** 677aa71bca 2007-10-12 drh: ** Show the complete change history for a single wiki page. 50a58adb76 2007-10-10 drh: */ 50a58adb76 2007-10-10 drh: void whistory_page(void){ 50a58adb76 2007-10-10 drh: Stmt q; 50a58adb76 2007-10-10 drh: char *zTitle; 50a58adb76 2007-10-10 drh: char *zSQL; 677aa71bca 2007-10-12 drh: const char *zPageName; 50a58adb76 2007-10-10 drh: login_check_credentials(); 50a58adb76 2007-10-10 drh: if( !g.okHistory ){ login_needed(); return; } 677aa71bca 2007-10-12 drh: zPageName = PD("name",""); dec4685720 2009-09-15 drh: zTitle = mprintf("History Of %s", zPageName); 50a58adb76 2007-10-10 drh: style_header(zTitle); 50a58adb76 2007-10-10 drh: free(zTitle); 50a58adb76 2007-10-10 drh: 50a58adb76 2007-10-10 drh: zSQL = mprintf("%s AND event.objid IN " 50a58adb76 2007-10-10 drh: " (SELECT rid FROM tagxref WHERE tagid=" 50a58adb76 2007-10-10 drh: "(SELECT tagid FROM tag WHERE tagname='wiki-%q'))" 50a58adb76 2007-10-10 drh: "ORDER BY mtime DESC", 677aa71bca 2007-10-12 drh: timeline_query_for_www(), zPageName); 50a58adb76 2007-10-10 drh: db_prepare(&q, zSQL); 50a58adb76 2007-10-10 drh: free(zSQL); 8e3b7fab9f 2009-08-27 drh: zWikiPageName = zPageName; 8e3b7fab9f 2009-08-27 drh: www_print_timeline(&q, TIMELINE_ARTID, wiki_history_extra); 50a58adb76 2007-10-10 drh: db_finalize(&q); bf428e6854 2007-10-06 drh: style_footer(); b2e55c0d4d 2007-09-01 drh: } b2e55c0d4d 2007-09-01 drh: b2e55c0d4d 2007-09-01 drh: /* 8e3b7fab9f 2009-08-27 drh: ** WEBPAGE: wdiff 8e3b7fab9f 2009-08-27 drh: ** URL: /whistory?name=PAGENAME&a=RID1&b=RID2 8e3b7fab9f 2009-08-27 drh: ** 8e3b7fab9f 2009-08-27 drh: ** Show the difference between two wiki pages. b2e55c0d4d 2007-09-01 drh: */ 8e3b7fab9f 2009-08-27 drh: void wdiff_page(void){ 8e3b7fab9f 2009-08-27 drh: char *zTitle; 8e3b7fab9f 2009-08-27 drh: int rid1, rid2; 8e3b7fab9f 2009-08-27 drh: const char *zPageName; 8e3b7fab9f 2009-08-27 drh: Blob content1, content2; 8e3b7fab9f 2009-08-27 drh: Manifest m1, m2; 8e3b7fab9f 2009-08-27 drh: Blob w1, w2, d; 8e3b7fab9f 2009-08-27 drh: b2e55c0d4d 2007-09-01 drh: login_check_credentials(); 8e3b7fab9f 2009-08-27 drh: rid1 = atoi(PD("a","0")); 8e3b7fab9f 2009-08-27 drh: if( !g.okHistory ){ login_needed(); return; } 8e3b7fab9f 2009-08-27 drh: if( rid1==0 ) fossil_redirect_home(); 8e3b7fab9f 2009-08-27 drh: rid2 = atoi(PD("b","0")); 8e3b7fab9f 2009-08-27 drh: zPageName = PD("name",""); dec4685720 2009-09-15 drh: zTitle = mprintf("Changes To %s", zPageName); 8e3b7fab9f 2009-08-27 drh: style_header(zTitle); 8e3b7fab9f 2009-08-27 drh: free(zTitle); bf428e6854 2007-10-06 drh: 8e3b7fab9f 2009-08-27 drh: if( rid2==0 ){ 8e3b7fab9f 2009-08-27 drh: rid2 = db_int(0, dec4685720 2009-09-15 drh: "SELECT objid FROM event JOIN tagxref ON objid=rid AND tagxref.tagid=" 8e3b7fab9f 2009-08-27 drh: "(SELECT tagid FROM tag WHERE tagname='wiki-%q')" 8e3b7fab9f 2009-08-27 drh: " WHERE event.mtime<(SELECT mtime FROM event WHERE objid=%d)" 8e3b7fab9f 2009-08-27 drh: " ORDER BY event.mtime DESC LIMIT 1", 8e3b7fab9f 2009-08-27 drh: zPageName, rid1 8e3b7fab9f 2009-08-27 drh: ); 8e3b7fab9f 2009-08-27 drh: } 8e3b7fab9f 2009-08-27 drh: content_get(rid1, &content1); 8e3b7fab9f 2009-08-27 drh: manifest_parse(&m1, &content1); 8e3b7fab9f 2009-08-27 drh: if( m1.type!=CFTYPE_WIKI ) fossil_redirect_home(); 8e3b7fab9f 2009-08-27 drh: blob_init(&w1, m1.zWiki, -1); 8e3b7fab9f 2009-08-27 drh: blob_zero(&w2); 8e3b7fab9f 2009-08-27 drh: if( rid2 ){ 8e3b7fab9f 2009-08-27 drh: content_get(rid2, &content2); 8e3b7fab9f 2009-08-27 drh: manifest_parse(&m2, &content2); 8e3b7fab9f 2009-08-27 drh: if( m2.type==CFTYPE_WIKI ){ 8e3b7fab9f 2009-08-27 drh: blob_init(&w2, m2.zWiki, -1); 8e3b7fab9f 2009-08-27 drh: } b2e55c0d4d 2007-09-01 drh: } 8e3b7fab9f 2009-08-27 drh: blob_zero(&d); 8e3b7fab9f 2009-08-27 drh: text_diff(&w2, &w1, &d, 5); 8e3b7fab9f 2009-08-27 drh: @ <pre> 8e3b7fab9f 2009-08-27 drh: @ %h(blob_str(&d)) 8e3b7fab9f 2009-08-27 drh: @ </pre> 22c1ac41d4 2007-08-23 drh: style_footer(); 22c1ac41d4 2007-08-23 drh: } 22c1ac41d4 2007-08-23 drh: 22c1ac41d4 2007-08-23 drh: /* 50a58adb76 2007-10-10 drh: ** WEBPAGE: wcontent 50a58adb76 2007-10-10 drh: ** 50a58adb76 2007-10-10 drh: ** List all available wiki pages with date created and last modified. 22c1ac41d4 2007-08-23 drh: */ 50a58adb76 2007-10-10 drh: void wcontent_page(void){ 22c1ac41d4 2007-08-23 drh: Stmt q; 50a58adb76 2007-10-10 drh: login_check_credentials(); 50a58adb76 2007-10-10 drh: if( !g.okRdWiki ){ login_needed(); return; } 50a58adb76 2007-10-10 drh: style_header("Available Wiki Pages"); 22c1ac41d4 2007-08-23 drh: @ <ul> 50a58adb76 2007-10-10 drh: db_prepare(&q, 50a58adb76 2007-10-10 drh: "SELECT substr(tagname, 6, 1000) FROM tag WHERE tagname GLOB 'wiki-*'" 50a58adb76 2007-10-10 drh: " ORDER BY lower(tagname)" 50a58adb76 2007-10-10 drh: ); 22c1ac41d4 2007-08-23 drh: while( db_step(&q)==SQLITE_ROW ){ 50a58adb76 2007-10-10 drh: const char *zName = db_column_text(&q, 0); f40230a7e8 2007-10-28 drh: @ <li><a href="%s(g.zBaseURL)/wiki?name=%T(zName)">%h(zName)</a></li> 22c1ac41d4 2007-08-23 drh: } 22c1ac41d4 2007-08-23 drh: db_finalize(&q); 22c1ac41d4 2007-08-23 drh: @ </ul> 22c1ac41d4 2007-08-23 drh: style_footer(); f08adf3d58 2007-10-28 drh: } f08adf3d58 2007-10-28 drh: f08adf3d58 2007-10-28 drh: /* f08adf3d58 2007-10-28 drh: ** WEBPAGE: wiki_rules f08adf3d58 2007-10-28 drh: */ f08adf3d58 2007-10-28 drh: void wikirules_page(void){ f08adf3d58 2007-10-28 drh: style_header("Wiki Formatting Rules"); f08adf3d58 2007-10-28 drh: @ <h2>Formatting Rule Summary</h2> f08adf3d58 2007-10-28 drh: @ <ol> f08adf3d58 2007-10-28 drh: @ <li> Blank lines are paragraph breaks 3beb385964 2008-05-24 drh: @ <li> Bullets are "*" surrounded by two spaces at the beginning of the line. 8d8a41d195 2008-07-15 drh: @ <li> Enumeration items are a number surrounded by two space 3beb385964 2008-05-24 drh: @ at the beginning of a line. f08adf3d58 2007-10-28 drh: @ <li> Indented pargraphs begin with a tab or two spaces. f08adf3d58 2007-10-28 drh: @ <li> Hyperlinks are contained with square brackets: "[target]" f08adf3d58 2007-10-28 drh: @ <li> Most ordinary HTML works. f08adf3d58 2007-10-28 drh: @ <li> <verbatim> and <nowiki>. f08adf3d58 2007-10-28 drh: @ </ol> f08adf3d58 2007-10-28 drh: @ <p>We call the first five rules above "wiki" formatting rules. The f08adf3d58 2007-10-28 drh: @ last two rules are the HTML formatting rule.</p> f08adf3d58 2007-10-28 drh: @ <h2>Formatting Rule Details</h2> f08adf3d58 2007-10-28 drh: @ <ol> f08adf3d58 2007-10-28 drh: @ <li> <p><b>Paragraphs</b>. Any sequence of one or more blank lines forms f08adf3d58 2007-10-28 drh: @ a paragraph break. Centered or right-justified paragraphs are not f08adf3d58 2007-10-28 drh: @ supported by wiki markup, but you can do these things if you need them f08adf3d58 2007-10-28 drh: @ using HTML.</p> f08adf3d58 2007-10-28 drh: @ <li> <p><b>Bullet Lists</b>. 4ef19b554a 2008-10-11 drh: @ A bullet list item is a line that begins with a single "*" character 3beb385964 2008-05-24 drh: @ surrounded on f08adf3d58 2007-10-28 drh: @ both sides by two or more spaces or by a tab. Only a single level 20a0fbdf64 2008-10-03 drh: @ of bullet list is supported by wiki. For nested lists, use HTML.</p> f08adf3d58 2007-10-28 drh: @ <li> <p><b>Enumeration Lists</b>. 4ef19b554a 2008-10-11 drh: @ An enumeration list item is a line that begins 3beb385964 2008-05-24 drh: @ with one or more digits optionally 4ef19b554a 2008-10-11 drh: @ followed by a "." and is surrounded on both sides by two or more spaces or f08adf3d58 2007-10-28 drh: @ by a tab. The number is significant and becomes the number shown f08adf3d58 2007-10-28 drh: @ in the rendered enumeration item. Only a single level of enumeration f08adf3d58 2007-10-28 drh: @ list is supported by wiki. For nested enumerations or for f08adf3d58 2007-10-28 drh: @ enumerations that count using letters or roman numerials, use HTML.</p> f08adf3d58 2007-10-28 drh: @ <li> <p><b>Indented Paragraphs</b>. f08adf3d58 2007-10-28 drh: @ Any paragraph that begins with two or more spaces or a tab and f08adf3d58 2007-10-28 drh: @ which is not a bullet or enumeration list item is rendered c8893c69ac 2008-10-05 drh: @ indented. Only a single level of indentation is supported by wiki; use c8893c69ac 2008-10-05 drh: @ HTML for deeper indentation.</p> f08adf3d58 2007-10-28 drh: @ <li> <p><b>Hyperlinks</b>. f08adf3d58 2007-10-28 drh: @ Text within square brackets ("[...]") becomes a hyperlink. The e8c4f69c50 2008-10-24 drh: @ target can be a wiki page name, the artifact ID of a check-in or ticket, f08adf3d58 2007-10-28 drh: @ the name of an image, or a URL. By default, the target is displayed f08adf3d58 2007-10-28 drh: @ as the text of the hyperlink. But you can specify alternative text f08adf3d58 2007-10-28 drh: @ after the target name separated by a "|" character.</p> f08adf3d58 2007-10-28 drh: @ <li> <p><b>HTML</b>. f08adf3d58 2007-10-28 drh: @ The following standard HTML elements may be used: f08adf3d58 2007-10-28 drh: @ <a> f08adf3d58 2007-10-28 drh: @ <address> f08adf3d58 2007-10-28 drh: @ <b> f08adf3d58 2007-10-28 drh: @ <big> f08adf3d58 2007-10-28 drh: @ <blockquote> f08adf3d58 2007-10-28 drh: @ <br> f08adf3d58 2007-10-28 drh: @ <center> f08adf3d58 2007-10-28 drh: @ <cite> f08adf3d58 2007-10-28 drh: @ <code> f08adf3d58 2007-10-28 drh: @ <dd> f08adf3d58 2007-10-28 drh: @ <dfn> e01aa8cb4b 2008-07-17 drh: @ <div> f08adf3d58 2007-10-28 drh: @ <dl> f08adf3d58 2007-10-28 drh: @ <dt> f08adf3d58 2007-10-28 drh: @ <em> f08adf3d58 2007-10-28 drh: @ <font> f08adf3d58 2007-10-28 drh: @ <h1> f08adf3d58 2007-10-28 drh: @ <h2> f08adf3d58 2007-10-28 drh: @ <h3> f08adf3d58 2007-10-28 drh: @ <h4> f08adf3d58 2007-10-28 drh: @ <h5> f08adf3d58 2007-10-28 drh: @ <h6> f08adf3d58 2007-10-28 drh: @ <hr> f08adf3d58 2007-10-28 drh: @ <img> f08adf3d58 2007-10-28 drh: @ <i> f08adf3d58 2007-10-28 drh: @ <kbd> f08adf3d58 2007-10-28 drh: @ <li> f08adf3d58 2007-10-28 drh: @ <nobr> f08adf3d58 2007-10-28 drh: @ <ol> f08adf3d58 2007-10-28 drh: @ <p> f08adf3d58 2007-10-28 drh: @ <pre> f08adf3d58 2007-10-28 drh: @ <s> f08adf3d58 2007-10-28 drh: @ <samp> f08adf3d58 2007-10-28 drh: @ <small> f08adf3d58 2007-10-28 drh: @ <strike> f08adf3d58 2007-10-28 drh: @ <strong> f08adf3d58 2007-10-28 drh: @ <sub> f08adf3d58 2007-10-28 drh: @ <sup> f08adf3d58 2007-10-28 drh: @ <table> f08adf3d58 2007-10-28 drh: @ <td> f08adf3d58 2007-10-28 drh: @ <th> f08adf3d58 2007-10-28 drh: @ <tr> f08adf3d58 2007-10-28 drh: @ <tt> f08adf3d58 2007-10-28 drh: @ <u> f08adf3d58 2007-10-28 drh: @ <ul> f08adf3d58 2007-10-28 drh: @ <var>. f08adf3d58 2007-10-28 drh: @ In addition, there are two non-standard elements available: f08adf3d58 2007-10-28 drh: @ <verbatim> and <nowiki>. f08adf3d58 2007-10-28 drh: @ No other elements are allowed. All attributes are checked and f08adf3d58 2007-10-28 drh: @ only a few benign attributes are allowed on each element. f08adf3d58 2007-10-28 drh: @ In particular, any attributes that specify javascript or CSS 3beb385964 2008-05-24 drh: @ are elided.</p></li> 3beb385964 2008-05-24 drh: @ <li><p><b>Special Markup.</b> 2c3ccaa048 2008-07-24 drh: @ The <nowiki> tag disables all wiki formatting rules 2c3ccaa048 2008-07-24 drh: @ through the matching </nowiki> element. 2c3ccaa048 2008-07-24 drh: @ The <verbatim> tag works like <pre> with the addition 2c3ccaa048 2008-07-24 drh: @ that it also disables all wiki and HTML markup 2c3ccaa048 2008-07-24 drh: @ through the matching </verbatim>. f08adf3d58 2007-10-28 drh: @ </ol> dbda8d6ce9 2007-07-21 drh: style_footer(); f08adf3d58 2007-10-28 drh: } f08adf3d58 2007-10-28 drh: decac09b7d 2008-05-14 drh: /* e03d1be55b 2008-05-16 drh: ** Add a new wiki page to the respository. The page name is e03d1be55b 2008-05-16 drh: ** given by the zPageName parameter. isNew must be true to create e03d1be55b 2008-05-16 drh: ** a new page. If no previous page with the name zPageName exists e03d1be55b 2008-05-16 drh: ** and isNew is false, then this routine throws an error. e03d1be55b 2008-05-16 drh: ** e03d1be55b 2008-05-16 drh: ** The content of the new page is given by the blob pContent. cde6e7a303 2008-05-15 stephan: */ e03d1be55b 2008-05-16 drh: int wiki_cmd_commit(char const * zPageName, int isNew, Blob *pContent){ e03d1be55b 2008-05-16 drh: Blob wiki; /* Wiki page content */ cde6e7a303 2008-05-15 stephan: Blob cksum; /* wiki checksum */ e03d1be55b 2008-05-16 drh: int rid; /* artifact ID of parent page */ e03d1be55b 2008-05-16 drh: int nrid; /* artifact ID of new wiki page */ e03d1be55b 2008-05-16 drh: char *zDate; /* timestamp */ e03d1be55b 2008-05-16 drh: char *zUuid; /* uuid for rid */ bfb4d414dd 2008-05-15 stephan: e03d1be55b 2008-05-16 drh: rid = db_int(0, e03d1be55b 2008-05-16 drh: "SELECT x.rid FROM tag t, tagxref x" e03d1be55b 2008-05-16 drh: " WHERE x.tagid=t.tagid AND t.tagname='wiki-%q'" e03d1be55b 2008-05-16 drh: " ORDER BY x.mtime DESC LIMIT 1", e03d1be55b 2008-05-16 drh: zPageName e03d1be55b 2008-05-16 drh: ); e03d1be55b 2008-05-16 drh: if( rid==0 && !isNew ){ e03d1be55b 2008-05-16 drh: fossil_fatal("no such wiki page: %s", zPageName); e03d1be55b 2008-05-16 drh: } e03d1be55b 2008-05-16 drh: if( rid!=0 && isNew ){ e03d1be55b 2008-05-16 drh: fossil_fatal("wiki page %s already exists", zPageName); bfb4d414dd 2008-05-15 stephan: } bfb4d414dd 2008-05-15 stephan: cde6e7a303 2008-05-15 stephan: blob_zero(&wiki); cde6e7a303 2008-05-15 stephan: zDate = db_text(0, "SELECT datetime('now')"); cde6e7a303 2008-05-15 stephan: zDate[10] = 'T'; cde6e7a303 2008-05-15 stephan: blob_appendf(&wiki, "D %s\n", zDate); cde6e7a303 2008-05-15 stephan: free(zDate); cde6e7a303 2008-05-15 stephan: blob_appendf(&wiki, "L %F\n", zPageName ); e03d1be55b 2008-05-16 drh: if( rid ){ e03d1be55b 2008-05-16 drh: zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); e03d1be55b 2008-05-16 drh: blob_appendf(&wiki, "P %s\n", zUuid); e03d1be55b 2008-05-16 drh: free(zUuid); e03d1be55b 2008-05-16 drh: } cde6e7a303 2008-05-15 stephan: user_select(); cde6e7a303 2008-05-15 stephan: if( g.zLogin ){ cde6e7a303 2008-05-15 stephan: blob_appendf(&wiki, "U %F\n", g.zLogin); cde6e7a303 2008-05-15 stephan: } e03d1be55b 2008-05-16 drh: blob_appendf( &wiki, "W %d\n%s\n", blob_size(pContent), e03d1be55b 2008-05-16 drh: blob_str(pContent) ); cde6e7a303 2008-05-15 stephan: md5sum_blob(&wiki, &cksum); cde6e7a303 2008-05-15 stephan: blob_appendf(&wiki, "Z %b\n", &cksum); cde6e7a303 2008-05-15 stephan: blob_reset(&cksum); cde6e7a303 2008-05-15 stephan: db_begin_transaction(); cde6e7a303 2008-05-15 stephan: nrid = content_put( &wiki, 0, 0 ); cde6e7a303 2008-05-15 stephan: db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid); cde6e7a303 2008-05-15 stephan: manifest_crosslink(nrid,&wiki); cde6e7a303 2008-05-15 stephan: blob_reset(&wiki); cde6e7a303 2008-05-15 stephan: content_deltify(rid,nrid,0); cde6e7a303 2008-05-15 stephan: db_end_transaction(0); d58ed02bed 2008-05-24 stephan: autosync(AUTOSYNC_PUSH); cde6e7a303 2008-05-15 stephan: return 1; 5fb1152dab 2008-05-14 stephan: } 5fb1152dab 2008-05-14 stephan: 5fb1152dab 2008-05-14 stephan: /* 5fb1152dab 2008-05-14 stephan: ** COMMAND: wiki 5fb1152dab 2008-05-14 stephan: ** 92df4748bd 2008-05-23 stephan: ** Usage: %fossil wiki (export|create|commit|list) WikiName 92df4748bd 2008-05-23 stephan: ** 5e8fb35db1 2009-06-01 stephan: ** Run various subcommands to work with wiki entries. 7adbf773c2 2008-05-16 stephan: ** 7adbf773c2 2008-05-16 stephan: ** %fossil wiki export PAGENAME ?FILE? e03d1be55b 2008-05-16 drh: ** e03d1be55b 2008-05-16 drh: ** Sends the latest version of the PAGENAME wiki 7adbf773c2 2008-05-16 stephan: ** entry to the given file or standard output. e03d1be55b 2008-05-16 drh: ** e03d1be55b 2008-05-16 drh: ** %fossil wiki commit PAGENAME ?FILE? e03d1be55b 2008-05-16 drh: ** 5e8fb35db1 2009-06-01 stephan: ** Commit changes to a wiki page from FILE or from standard 5e8fb35db1 2009-06-01 stephan: ** input. e03d1be55b 2008-05-16 drh: ** e03d1be55b 2008-05-16 drh: ** %fossil wiki create PAGENAME ?FILE? 87a1a31d1d 2008-05-14 stephan: ** e03d1be55b 2008-05-16 drh: ** Create a new wiki page with initial content taken from e03d1be55b 2008-05-16 drh: ** FILE or from standard input. 87a1a31d1d 2008-05-14 stephan: ** 87a1a31d1d 2008-05-14 stephan: ** %fossil wiki list 87a1a31d1d 2008-05-14 stephan: ** d13b3ff094 2008-05-14 stephan: ** Lists all wiki entries, one per line, ordered d13b3ff094 2008-05-14 stephan: ** case-insentively by name. 87a1a31d1d 2008-05-14 stephan: ** 87a1a31d1d 2008-05-14 stephan: ** TODOs: 87a1a31d1d 2008-05-14 stephan: ** e8c4f69c50 2008-10-24 drh: ** %fossil wiki export ?-u ARTIFACT? WikiName ?FILE? d13b3ff094 2008-05-14 stephan: ** 7adbf773c2 2008-05-16 stephan: ** Outputs the selected version of WikiName. d13b3ff094 2008-05-14 stephan: ** d13b3ff094 2008-05-14 stephan: ** %fossil wiki delete ?-m MESSAGE? WikiName d13b3ff094 2008-05-14 stephan: ** d13b3ff094 2008-05-14 stephan: ** The same as deleting a file entry, but i don't know if fossil d13b3ff094 2008-05-14 stephan: ** supports a commit message for Wiki entries. d13b3ff094 2008-05-14 stephan: ** d13b3ff094 2008-05-14 stephan: ** %fossil wiki ?-u? ?-d? ?-s=[|]? list 5fb1152dab 2008-05-14 stephan: ** e8c4f69c50 2008-10-24 drh: ** Lists the artifact ID and/or Date of last change along with e8c4f69c50 2008-10-24 drh: ** each entry name, delimited by the -s char. 5fb1152dab 2008-05-14 stephan: ** e8c4f69c50 2008-10-24 drh: ** %fossil wiki diff ?ARTIFACT? ?-f infile[=stdin]? EntryName 5fb1152dab 2008-05-14 stephan: ** cde6e7a303 2008-05-15 stephan: ** Diffs the local copy of a page with a given version (defaulting cde6e7a303 2008-05-15 stephan: ** to the head version). 5fb1152dab 2008-05-14 stephan: */ 5fb1152dab 2008-05-14 stephan: void wiki_cmd(void){ 5fb1152dab 2008-05-14 stephan: int n; 5fb1152dab 2008-05-14 stephan: db_find_and_open_repository(1); 5fb1152dab 2008-05-14 stephan: if( g.argc<3 ){ 5fb1152dab 2008-05-14 stephan: goto wiki_cmd_usage; 5fb1152dab 2008-05-14 stephan: } 5fb1152dab 2008-05-14 stephan: n = strlen(g.argv[2]); 5fb1152dab 2008-05-14 stephan: if( n==0 ){ 5fb1152dab 2008-05-14 stephan: goto wiki_cmd_usage; 5fb1152dab 2008-05-14 stephan: } 5fb1152dab 2008-05-14 stephan: 5fb1152dab 2008-05-14 stephan: if( strncmp(g.argv[2],"export",n)==0 ){ 7adbf773c2 2008-05-16 stephan: char const *zPageName; /* Name of the wiki page to export */ 7adbf773c2 2008-05-16 stephan: char const *zFile; /* Name of the output file (0=stdout) */ decac09b7d 2008-05-14 drh: int rid; /* Artifact ID of the wiki page */ decac09b7d 2008-05-14 drh: int i; /* Loop counter */ decac09b7d 2008-05-14 drh: char *zBody = 0; /* Wiki page content */ decac09b7d 2008-05-14 drh: Manifest m; /* Parsed wiki page content */ 7adbf773c2 2008-05-16 stephan: if( (g.argc!=4) && (g.argc!=5) ){ 7adbf773c2 2008-05-16 stephan: usage("export PAGENAME ?FILE?"); feee32d3af 2008-05-14 stephan: } cde6e7a303 2008-05-15 stephan: zPageName = g.argv[3]; decac09b7d 2008-05-14 drh: rid = db_int(0, "SELECT x.rid FROM tag t, tagxref x" feee32d3af 2008-05-14 stephan: " WHERE x.tagid=t.tagid AND t.tagname='wiki-%q'" feee32d3af 2008-05-14 stephan: " ORDER BY x.mtime DESC LIMIT 1", cde6e7a303 2008-05-15 stephan: zPageName decac09b7d 2008-05-14 drh: ); decac09b7d 2008-05-14 drh: if( rid ){ decac09b7d 2008-05-14 drh: Blob content; decac09b7d 2008-05-14 drh: content_get(rid, &content); decac09b7d 2008-05-14 drh: manifest_parse(&m, &content); decac09b7d 2008-05-14 drh: if( m.type==CFTYPE_WIKI ){ decac09b7d 2008-05-14 drh: zBody = m.zWiki; decac09b7d 2008-05-14 drh: } decac09b7d 2008-05-14 drh: } decac09b7d 2008-05-14 drh: if( zBody==0 ){ cde6e7a303 2008-05-15 stephan: fossil_fatal("wiki page [%s] not found",zPageName); decac09b7d 2008-05-14 drh: } decac09b7d 2008-05-14 drh: for(i=strlen(zBody); i>0 && isspace(zBody[i-1]); i--){} 7adbf773c2 2008-05-16 stephan: zFile = (g.argc==4) ? 0 : g.argv[4]; 7adbf773c2 2008-05-16 stephan: if( zFile ){ 7adbf773c2 2008-05-16 stephan: FILE * zF; 7adbf773c2 2008-05-16 stephan: short doClose = 0; 7adbf773c2 2008-05-16 stephan: if( (1 == strlen(zFile)) && ('-'==zFile[0]) ){ 7adbf773c2 2008-05-16 stephan: zF = stdout; 7adbf773c2 2008-05-16 stephan: }else{ 7adbf773c2 2008-05-16 stephan: zF = fopen( zFile, "w" ); 7adbf773c2 2008-05-16 stephan: doClose = zF ? 1 : 0; 7adbf773c2 2008-05-16 stephan: } 7adbf773c2 2008-05-16 stephan: if( ! zF ){ 7adbf773c2 2008-05-16 stephan: fossil_fatal("wiki export could not open output file for writing."); 7adbf773c2 2008-05-16 stephan: } 7adbf773c2 2008-05-16 stephan: fprintf(zF,"%.*s\n", i, zBody); 7adbf773c2 2008-05-16 stephan: if( doClose ) fclose(zF); 7adbf773c2 2008-05-16 stephan: }else{ 7adbf773c2 2008-05-16 stephan: printf("%.*s\n", i, zBody); 5fb1152dab 2008-05-14 stephan: } decac09b7d 2008-05-14 drh: return; decac09b7d 2008-05-14 drh: }else e03d1be55b 2008-05-16 drh: if( strncmp(g.argv[2],"commit",n)==0 e03d1be55b 2008-05-16 drh: || strncmp(g.argv[2],"create",n)==0 ){ cde6e7a303 2008-05-15 stephan: char *zPageName; e03d1be55b 2008-05-16 drh: Blob content; e03d1be55b 2008-05-16 drh: if( g.argc!=4 && g.argc!=5 ){ e03d1be55b 2008-05-16 drh: usage("commit PAGENAME ?FILE?"); 5fb1152dab 2008-05-14 stephan: } cde6e7a303 2008-05-15 stephan: zPageName = g.argv[3]; e03d1be55b 2008-05-16 drh: if( g.argc==4 ){ e03d1be55b 2008-05-16 drh: blob_read_from_channel(&content, stdin, -1); e03d1be55b 2008-05-16 drh: }else{ e03d1be55b 2008-05-16 drh: blob_read_from_file(&content, g.argv[4]); 5fb1152dab 2008-05-14 stephan: } e03d1be55b 2008-05-16 drh: if( g.argv[2][1]=='r' ){ e03d1be55b 2008-05-16 drh: wiki_cmd_commit(zPageName, 1, &content); e03d1be55b 2008-05-16 drh: printf("Created new wiki page %s.\n", zPageName); e03d1be55b 2008-05-16 drh: }else{ e03d1be55b 2008-05-16 drh: wiki_cmd_commit(zPageName, 0, &content); e03d1be55b 2008-05-16 drh: printf("Updated wiki page %s.\n", zPageName); 5fb1152dab 2008-05-14 stephan: } e03d1be55b 2008-05-16 drh: blob_reset(&content); 5fb1152dab 2008-05-14 stephan: }else 5fb1152dab 2008-05-14 stephan: if( strncmp(g.argv[2],"delete",n)==0 ){ 5fb1152dab 2008-05-14 stephan: if( g.argc!=5 ){ decac09b7d 2008-05-14 drh: usage("delete PAGENAME"); 5fb1152dab 2008-05-14 stephan: } decac09b7d 2008-05-14 drh: fossil_fatal("delete not yet implemented."); 5fb1152dab 2008-05-14 stephan: }else 5fb1152dab 2008-05-14 stephan: if( strncmp(g.argv[2],"list",n)==0 ){ 5fb1152dab 2008-05-14 stephan: Stmt q; 5fb1152dab 2008-05-14 stephan: db_prepare(&q, decac09b7d 2008-05-14 drh: "SELECT substr(tagname, 6) FROM tag WHERE tagname GLOB 'wiki-*'" decac09b7d 2008-05-14 drh: " ORDER BY lower(tagname)" decac09b7d 2008-05-14 drh: ); 5fb1152dab 2008-05-14 stephan: while( db_step(&q)==SQLITE_ROW ){ decac09b7d 2008-05-14 drh: const char *zName = db_column_text(&q, 0); decac09b7d 2008-05-14 drh: printf( "%s\n",zName); 5fb1152dab 2008-05-14 stephan: } 5fb1152dab 2008-05-14 stephan: db_finalize(&q); 5fb1152dab 2008-05-14 stephan: }else 5fb1152dab 2008-05-14 stephan: { 5fb1152dab 2008-05-14 stephan: goto wiki_cmd_usage; 5fb1152dab 2008-05-14 stephan: } 5fb1152dab 2008-05-14 stephan: return; 5fb1152dab 2008-05-14 stephan: 5fb1152dab 2008-05-14 stephan: wiki_cmd_usage: 92df4748bd 2008-05-23 stephan: usage("export|create|commit|list ..."); dbda8d6ce9 2007-07-21 drh: }