File Annotation
Not logged in
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: /*
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:
488afb9746 2007-10-06       drh:     @ <ul>
488afb9746 2007-10-06       drh:     @ <li> Must not begin or end with a space.
488afb9746 2007-10-06       drh:     @ <li> Must not contain any control characters, including tab or
488afb9746 2007-10-06       drh:     @      newline.
488afb9746 2007-10-06       drh:     @ <li> Must not have two or more spaces in a row internally.
488afb9746 2007-10-06       drh:     @ <li> Must be between 3 and 100 characters in length.
488afb9746 2007-10-06       drh:     @ </ul>
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>
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:   }
61ce5e3685 2007-10-10       drh:   style_footer();
61ce5e3685 2007-10-10       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;
b2e55c0d4d 2007-09-01       drh:   }
61ce5e3685 2007-10-10       drh:   zHtmlPageName = mprintf("Append Comment To: %h", 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){
8e3b7fab9f 2009-08-27       drh:   @ <a href="%s(g.zTop)/wdiff?name=%h(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> &lt;verbatim&gt; and &lt;nowiki&gt;.
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:   @ &lt;a&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;address&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;b&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;big&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;blockquote&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;br&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;center&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;cite&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;code&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;dd&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;dfn&gt;
e01aa8cb4b 2008-07-17       drh:   @ &lt;div&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;dl&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;dt&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;em&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;font&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;h1&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;h2&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;h3&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;h4&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;h5&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;h6&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;hr&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;img&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;i&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;kbd&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;li&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;nobr&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;ol&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;p&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;pre&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;s&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;samp&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;small&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;strike&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;strong&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;sub&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;sup&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;table&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;td&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;th&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;tr&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;tt&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;u&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;ul&gt;
f08adf3d58 2007-10-28       drh:   @ &lt;var&gt;.
f08adf3d58 2007-10-28       drh:   @ In addition, there are two non-standard elements available:
f08adf3d58 2007-10-28       drh:   @ &lt;verbatim&gt; and &lt;nowiki&gt;.
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 &lt;nowiki&gt; tag disables all wiki formatting rules
2c3ccaa048 2008-07-24       drh:   @ through the matching &lt;/nowiki&gt; element.
2c3ccaa048 2008-07-24       drh:   @ The &lt;verbatim&gt; tag works like &lt;pre&gt; 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 &lt;/verbatim&gt;.
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: }