File Annotation
Not logged in
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Copyright (c) 2007 D. Richard Hipp
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** This program is free software; you can redistribute it and/or
dbda8d6ce9 2007-07-21       drh: ** modify it under the terms of the GNU General Public
dbda8d6ce9 2007-07-21       drh: ** License version 2 as published by the Free Software Foundation.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** This program is distributed in the hope that it will be useful,
dbda8d6ce9 2007-07-21       drh: ** but WITHOUT ANY WARRANTY; without even the implied warranty of
dbda8d6ce9 2007-07-21       drh: ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
dbda8d6ce9 2007-07-21       drh: ** General Public License for more details.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** You should have received a copy of the GNU General Public
dbda8d6ce9 2007-07-21       drh: ** License along with this library; if not, write to the
dbda8d6ce9 2007-07-21       drh: ** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
dbda8d6ce9 2007-07-21       drh: ** Boston, MA  02111-1307, USA.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** Author contact information:
dbda8d6ce9 2007-07-21       drh: **   drh@hwaci.com
dbda8d6ce9 2007-07-21       drh: **   http://www.hwaci.com/drh/
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: *******************************************************************************
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** This file contains code to do formatting of wiki text.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: #include <assert.h>
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.
dbda8d6ce9 2007-07-21       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);
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
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: /*
b2e55c0d4d 2007-09-01       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
50a58adb76 2007-10-10       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
22c1ac41d4 2007-08-23       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();
22c1ac41d4 2007-08-23       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
f08adf3d58 2007-10-28       drh:   @ <li> Bullet list items are a "*" at the beginning of the line.
f08adf3d58 2007-10-28       drh:   @ <li> Enumeration list items are a number 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>.
f08adf3d58 2007-10-28       drh:   @ A bullet list item begins with a single "*" character 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>.
f08adf3d58 2007-10-28       drh:   @ An enumeration list item begins with one or more digits optionally
f08adf3d58 2007-10-28       drh:   @ followed by a "." 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
f08adf3d58 2007-10-28       drh:   @ are elided.</p>
f08adf3d58 2007-10-28       drh:   @ <p>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();
dbda8d6ce9 2007-07-21       drh: }
5fb1152dab 2008-05-14   stephan: 
5fb1152dab 2008-05-14   stephan: void dump_blob_to_FILE( Blob * b, FILE * f )
5fb1152dab 2008-05-14   stephan: {
5fb1152dab 2008-05-14   stephan: 	fwrite(blob_buffer(b), 1, blob_size(b), stdout);
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: **
feee32d3af 2008-05-14   stephan: ** Usage: %fossil wiki (export|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: **
87a1a31d1d 2008-05-14   stephan: **     %fossil wiki export WikiName
87a1a31d1d 2008-05-14   stephan: **
87a1a31d1d 2008-05-14   stephan: **         Sends the latest version of the WikiName wiki
87a1a31d1d 2008-05-14   stephan: **         entry to stdout.
87a1a31d1d 2008-05-14   stephan: **
87a1a31d1d 2008-05-14   stephan: **     %fossil wiki list
87a1a31d1d 2008-05-14   stephan: **
87a1a31d1d 2008-05-14   stephan: **         Lists all wiki entries, one per line.
5fb1152dab 2008-05-14   stephan: **
5fb1152dab 2008-05-14   stephan: **
87a1a31d1d 2008-05-14   stephan: ** TODOs:
5fb1152dab 2008-05-14   stephan: **
87a1a31d1d 2008-05-14   stephan: **     %fossil export WikiName ?UUID? ?-f outfile?
feee32d3af 2008-05-14   stephan: **     %fossil commit WikiName ?-f infile?
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 ){
5fb1152dab 2008-05-14   stephan:     Stmt q;
5fb1152dab 2008-05-14   stephan:     char *wname;
5fb1152dab 2008-05-14   stephan:     Blob buf;
5fb1152dab 2008-05-14   stephan:     int rid;
5fb1152dab 2008-05-14   stephan:     char * sql;
5fb1152dab 2008-05-14   stephan:     if( g.argc!=4 ){
5fb1152dab 2008-05-14   stephan:       usage("export EntryName");
5fb1152dab 2008-05-14   stephan:     }
5fb1152dab 2008-05-14   stephan:     wname = g.argv[3];
5fb1152dab 2008-05-14   stephan:     rid = -1;
feee32d3af 2008-05-14   stephan:     sql = mprintf("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",
5fb1152dab 2008-05-14   stephan:       wname );
5fb1152dab 2008-05-14   stephan:     db_prepare(&q, "%z", sql );
feee32d3af 2008-05-14   stephan:     if( db_step(&q) == SQLITE_ROW ){
feee32d3af 2008-05-14   stephan:       rid = db_column_int(&q,0);
5fb1152dab 2008-05-14   stephan:     }
5fb1152dab 2008-05-14   stephan:     db_finalize(&q);
5fb1152dab 2008-05-14   stephan:     if( -1 == rid ){
5fb1152dab 2008-05-14   stephan:       fprintf(stderr,"export error: wiki entry [%s] not found.\n",wname);
5fb1152dab 2008-05-14   stephan:       exit(1);
5fb1152dab 2008-05-14   stephan:     }
5fb1152dab 2008-05-14   stephan:     if( ! content_get(rid,&buf) ){
5fb1152dab 2008-05-14   stephan:       fprintf(stderr,"export error: content_get(%d) returned 0\n", rid );
5fb1152dab 2008-05-14   stephan:       exit(1);
5fb1152dab 2008-05-14   stephan:     }else
5fb1152dab 2008-05-14   stephan:     {
5fb1152dab 2008-05-14   stephan:       /* Unfortunately, the content_get() routine does ALMOST what i want,
5fb1152dab 2008-05-14   stephan: 	 but not quite. It is quite complex, so i don't want to fork a
5fb1152dab 2008-05-14   stephan: 	 modified copy here. That's what all the skipping-over bits are for...
5fb1152dab 2008-05-14   stephan: 
5fb1152dab 2008-05-14   stephan: 	 We look for the first line starting with 'W', then expect '
5fb1152dab 2008-05-14   stephan: 	 NUMBER\n' immediately after that, followed by NUMBER bytes
5fb1152dab 2008-05-14   stephan: 	 of plain blob content.
5fb1152dab 2008-05-14   stephan:       */
5fb1152dab 2008-05-14   stephan:       int len;
5fb1152dab 2008-05-14   stephan:       char * it;
5fb1152dab 2008-05-14   stephan:       Blob numbuf;
5fb1152dab 2008-05-14   stephan:       blob_zero(&numbuf);
5fb1152dab 2008-05-14   stephan:       it = blob_buffer(&buf);
5fb1152dab 2008-05-14   stephan:       while(*it){
5fb1152dab 2008-05-14   stephan:         if( *it != 'W' ){
5fb1152dab 2008-05-14   stephan:           ++it;
5fb1152dab 2008-05-14   stephan:           while( *it ){
5fb1152dab 2008-05-14   stephan:             if( *it == '\n') { ++it; break; }
5fb1152dab 2008-05-14   stephan:             ++it;
5fb1152dab 2008-05-14   stephan:           }
5fb1152dab 2008-05-14   stephan:           continue;
5fb1152dab 2008-05-14   stephan:         }
feee32d3af 2008-05-14   stephan:         if( ! *it )
feee32d3af 2008-05-14   stephan:         {
feee32d3af 2008-05-14   stephan:             fprintf(stderr,
feee32d3af 2008-05-14   stephan:               "export reached end of input before finding a 'W' card.\n");
feee32d3af 2008-05-14   stephan:             exit(1);
feee32d3af 2008-05-14   stephan:         }
5fb1152dab 2008-05-14   stephan:         ++it;
5fb1152dab 2008-05-14   stephan:         while( (*it) && (*it != '\n') ){
5fb1152dab 2008-05-14   stephan:           if( isspace(*it) ) { ++it; continue; }
5fb1152dab 2008-05-14   stephan:           blob_append(&numbuf,it,1);
5fb1152dab 2008-05-14   stephan:           ++it;
5fb1152dab 2008-05-14   stephan:         }
5fb1152dab 2008-05-14   stephan:         if( '\n' == *it ) ++it;
5fb1152dab 2008-05-14   stephan:         if( 0 == blob_size(&numbuf) ){
5fb1152dab 2008-05-14   stephan:           fprintf(stderr,
5fb1152dab 2008-05-14   stephan:           "export error: didn't find \"W NUMBER\" line in input!\n");
feee32d3af 2008-05-14   stephan:           blob_reset(&buf);
feee32d3af 2008-05-14   stephan:           blob_reset(&numbuf);
5fb1152dab 2008-05-14   stephan:           exit(1);
5fb1152dab 2008-05-14   stephan:         }
5fb1152dab 2008-05-14   stephan:         len = atoi(blob_buffer(&numbuf));
feee32d3af 2008-05-14   stephan:         //fprintf(stderr,"Writing %s (%d) bytes...\n",blob_buffer(&numbuf),len);
feee32d3af 2008-05-14   stephan:         blob_reset(&numbuf);
feee32d3af 2008-05-14   stephan:         if( ( (it - blob_buffer(&buf)) + len) > blob_size(&buf) ){
feee32d3af 2008-05-14   stephan:           fprintf(stderr,
feee32d3af 2008-05-14   stephan:             "export error: manifest data doesn't match actual data size!"
feee32d3af 2008-05-14   stephan:             " Manifest says [%s (%d)] bytes.\n",
feee32d3af 2008-05-14   stephan:             blob_buffer(&numbuf), len );
feee32d3af 2008-05-14   stephan:           blob_reset(&buf);
feee32d3af 2008-05-14   stephan:           blob_reset(&numbuf);
feee32d3af 2008-05-14   stephan:           exit(1);
feee32d3af 2008-05-14   stephan:         }
5fb1152dab 2008-05-14   stephan:         fwrite(it,sizeof(char),len,stdout);
feee32d3af 2008-05-14   stephan:         blob_reset(&buf);
5fb1152dab 2008-05-14   stephan:         return;
5fb1152dab 2008-05-14   stephan:       }
5fb1152dab 2008-05-14   stephan:     }
feee32d3af 2008-05-14   stephan:     blob_reset(&buf);
5fb1152dab 2008-05-14   stephan:     return;
5fb1152dab 2008-05-14   stephan:   }else
feee32d3af 2008-05-14   stephan:   if( strncmp(g.argv[2],"commit",n)==0 ){
5fb1152dab 2008-05-14   stephan:     char *wname;
5fb1152dab 2008-05-14   stephan:     if( g.argc!=4 ){
feee32d3af 2008-05-14   stephan:       usage("commit EntryName");
5fb1152dab 2008-05-14   stephan:     }
5fb1152dab 2008-05-14   stephan:     wname = g.argv[3];
feee32d3af 2008-05-14   stephan:     fprintf(stderr,"commit not yet implemented.\n");
5fb1152dab 2008-05-14   stephan:     exit(1);
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 ){
5fb1152dab 2008-05-14   stephan:       usage("delete WikiName");
5fb1152dab 2008-05-14   stephan:     }
5fb1152dab 2008-05-14   stephan:     fprintf(stderr,"delete not yet implemented.\n");
5fb1152dab 2008-05-14   stephan:     exit(1);
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,
5fb1152dab 2008-05-14   stephan:                "SELECT substr(tagname, 6, 1000) FROM tag WHERE tagname GLOB 'wiki-*'"
5fb1152dab 2008-05-14   stephan:                " ORDER BY lower(tagname)"
5fb1152dab 2008-05-14   stephan:                );
5fb1152dab 2008-05-14   stephan:     while( db_step(&q)==SQLITE_ROW ){
5fb1152dab 2008-05-14   stephan:         const char *zName = db_column_text(&q, 0);
5fb1152dab 2008-05-14   stephan:         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:
feee32d3af 2008-05-14   stephan:   usage("delete|export|commit|list [EntryName]");
f08adf3d58 2007-10-28       drh: }
f08adf3d58 2007-10-28       drh: