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: }
b2e55c0d4d 2007-09-01       drh: 
b2e55c0d4d 2007-09-01       drh: /*
50a58adb76 2007-10-10       drh: ** WEBPAGE: home
50a58adb76 2007-10-10       drh: ** WEBPAGE: index
50a58adb76 2007-10-10       drh: ** WEBPAGE: not_found
b2e55c0d4d 2007-09-01       drh: */
50a58adb76 2007-10-10       drh: void home_page(void){
50a58adb76 2007-10-10       drh:   char *zPageName = db_get("project-name",0);
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);
50a58adb76 2007-10-10       drh:     g.okRdWiki = 1;
50a58adb76 2007-10-10       drh:     g.okApndWiki = 0;
50a58adb76 2007-10-10       drh:     g.okWrWiki = 0;
50a58adb76 2007-10-10       drh:     g.okHistory = 0;
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.
50a58adb76 2007-10-10       drh:   style_footer();
b2e55c0d4d 2007-09-01       drh: }
b2e55c0d4d 2007-09-01       drh: 
b2e55c0d4d 2007-09-01       drh: /*
f08adf3d58 2007-10-28       drh: ** Return true if the given pagename is the name of the sandbox
b2e55c0d4d 2007-09-01       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;
bf428e6854 2007-10-06       drh:   int rid;
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:   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>
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:   }
f08adf3d58 2007-10-28       drh:   if( isSandbox || (rid && g.okWrWiki) || (!rid && g.okNewWiki) ){
5f3ddcc1b8 2007-11-25       drh:     style_submenu_element("Edit", "Edit Wiki Page", "%s/wikiedit?name=%T",
5f3ddcc1b8 2007-11-25       drh:          g.zTop, zPageName);
f08adf3d58 2007-10-28       drh:   }
f08adf3d58 2007-10-28       drh:   if( isSandbox || (rid && g.okApndWiki) ){
5f3ddcc1b8 2007-11-25       drh:     style_submenu_element("Append", "Add A Comment", "%s/wikiappend?name=%T",
5f3ddcc1b8 2007-11-25       drh:          g.zTop, zPageName);
f08adf3d58 2007-10-28       drh:   }
f08adf3d58 2007-10-28       drh:   if( !isSandbox && g.okHistory ){
5f3ddcc1b8 2007-11-25       drh:     style_submenu_element("History", "History", "%s/whistory?name=%T",
5f3ddcc1b8 2007-11-25       drh:          g.zTop, zPageName);
bf428e6854 2007-10-06       drh:   }
bf428e6854 2007-10-06       drh:   zHtmlPageName = mprintf("%h", zPageName);
bf428e6854 2007-10-06       drh:   style_header(zHtmlPageName);
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 ){
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{
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);
bf428e6854 2007-10-06       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:   }
bf428e6854 2007-10-06       drh:   zHtmlPageName = mprintf("Edit: %h", 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;
bf428e6854 2007-10-06       drh:   if( n>200 ) n = 200;
677aa71bca 2007-10-12       drh:   @ <form method="POST" action="%s(g.zBaseURL)/wikiedit">
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:   }
50a58adb76 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;
61ce5e3685 2007-10-10       drh: 
61ce5e3685 2007-10-10       drh:   zDate = db_text(0, "SELECT datetime('now')");
f08adf3d58 2007-10-28       drh:   blob_appendf(p, "\n\n<hr><i>On %s UTC %h", 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","");
f08adf3d58 2007-10-28       drh:   blob_appendf(p, " added:</i><br />\n%s", zRemark);
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 ){
f08adf3d58 2007-10-28       drh:       cgi_redirect("index");
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;
b2e55c0d4d 2007-09-01       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;
b2e55c0d4d 2007-09-01       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{
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:         blob_appendf(&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:       blob_appendf(&body, "\n<hr>\n");
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:   }
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">
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>
bf428e6854 2007-10-06       drh:   style_footer();
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","");
677aa71bca 2007-10-12       drh:   zTitle = mprintf("History Of %h", zPageName);
50a58adb76 2007-10-10       drh:   style_header(zTitle);
50a58adb76 2007-10-10       drh:   free(zTitle);
bf428e6854 2007-10-06       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);
82fc5abb60 2008-02-26       drh:   www_print_timeline(&q);
50a58adb76 2007-10-10       drh:   db_finalize(&q);
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.
3beb385964 2008-05-24       drh:   @ <li> Enumeration items 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>.
3beb385964 2008-05-24       drh:   @ A bullet list item are lines that begin 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
f08adf3d58 2007-10-28       drh:   @ of bullet list is supported by wiki.  For tested lists, use HTML.</p>
f08adf3d58 2007-10-28       drh:   @ <li> <p><b>Enumeration Lists</b>.
3beb385964 2008-05-24       drh:   @ An enumeration list items are lines that begin
3beb385964 2008-05-24       drh:   @ with one or more digits optionally
3beb385964 2008-05-24       drh:   @ followed by a "." and 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
f08adf3d58 2007-10-28       drh:   @ indented.  Only a single level of indentation is supported by</p>
f08adf3d58 2007-10-28       drh:   @ <li> <p><b>Hyperlinks</b>.
f08adf3d58 2007-10-28       drh:   @ Text within square brackets ("[...]") becomes a hyperlink.  The
f08adf3d58 2007-10-28       drh:   @ target can be a wiki page name, the UUID 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;
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>
3beb385964 2008-05-24       drh:   @ The &lt;verbatim&gt; tag disables all wiki and HTML markup
f08adf3d58 2007-10-28       drh:   @ up through the next &lt;/verbatim&gt;.  The &lt;nowiki&gt; tag
f08adf3d58 2007-10-28       drh:   @ disables all wiki formatting rules through the matching
f08adf3d58 2007-10-28       drh:   @ &lt;/nowiki&gt; element.
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);
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
87a1a31d1d 2008-05-14   stephan: **
87a1a31d1d 2008-05-14   stephan: ** Run various subcommands to fetch wiki entries.
87a1a31d1d 2008-05-14   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: **
e03d1be55b 2008-05-16       drh: **        Commit changes to a wiki page from FILE or from standard.
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: **
7adbf773c2 2008-05-16   stephan: **     %fossil wiki export ?-u UUID? 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: **
7adbf773c2 2008-05-16   stephan: **        Lists the UUID and/or Date of last change along with each entry
7adbf773c2 2008-05-16   stephan: **        name, delimited by the -s char.
5fb1152dab 2008-05-14   stephan: **
cde6e7a303 2008-05-15   stephan: **     %fossil wiki diff ?UUID? ?-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: }