/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=2 et sw=2 tw=80: */ /* Copyright (c) 2013 D. Richard Hipp This program is free software; you can redistribute it and/or modify it under the terms of the Simplified BSD License (also known as the "2-Clause License" or "FreeBSD License".) This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. Author contact information: drh@hwaci.com http://www.hwaci.com/drh/ ***************************************************************************** This file implements iki-related parts of the library. */ #include "fossil-scm/fossil-internal.h" #include /* Only for debugging */ #include #define MARKER(pfexp) \ do{ printf("MARKER: %s:%d:%s():\t",__FILE__,__LINE__,__func__); \ printf pfexp; \ } while(0) int fsl_wiki_names_get( fsl_cx * f, fsl_list * tgt ){ fsl_db * db = fsl_needs_repo(f); if(!f || !tgt) return FSL_RC_MISUSE; else if(!db) return FSL_RC_NOT_A_REPO; else { int rc = fsl_db_select_slist( db, tgt, "SELECT substr(tagname,6) AS name " "FROM tag " "WHERE tagname GLOB 'wiki-*' " "ORDER BY lower(name)"); if(rc && db->error.code && !f->error.code){ fsl_cx_uplift_db_error(f, db); } return rc; } } int fsl_wiki_latest_rid( fsl_cx * f, char const * pageName, fsl_id_t * rid ){ fsl_db * db = f ? fsl_needs_repo(f) : NULL; if(!f || !pageName) return FSL_RC_MISUSE; else if(!*pageName) return FSL_RC_RANGE; else if(!db) return FSL_RC_NOT_A_REPO; else return fsl_db_get_id(db, rid, "SELECT x.rid FROM tag t, tagxref x " "WHERE x.tagid=t.tagid " "AND t.tagname='wiki-%q' " "ORDER BY mtime DESC LIMIT 1", pageName); } char fsl_wiki_page_exists(fsl_cx * f, char const * pageName){ fsl_id_t rid = 0; return (0==fsl_wiki_latest_rid(f, pageName, &rid)) && (rid>0); } int fsl_wiki_load_latest( fsl_cx * f, char const * pageName, fsl_deck * d ){ fsl_db * db = f ? fsl_needs_repo(f) : NULL; if(!f || !pageName || !d) return FSL_RC_MISUSE; else if(!*pageName) return FSL_RC_RANGE; else if(!db) return FSL_RC_NOT_A_REPO; else{ fsl_id_t rid = 0; int rc = fsl_wiki_latest_rid(f, pageName, &rid); if(rc) return rc; else if(0==rid) return FSL_RC_NOT_FOUND; return fsl_deck_load_rid( f, d, rid, FSL_CATYPE_WIKI); } } int fsl_wiki_foreach_page( fsl_cx * f, fsl_deck_visitor_f cb, void * state ){ fsl_db * db = f ? fsl_needs_repo(f) : NULL; if(!f || !cb) return FSL_RC_MISUSE; else if(!db) return FSL_RC_NOT_A_REPO; else{ fsl_stmt st = fsl_stmt_empty; fsl_stmt names = fsl_stmt_empty; int rc; char doBreak = 0; rc = fsl_db_prepare(db, &names, "SELECT substr(tagname,6) AS name " "FROM tag " "WHERE tagname GLOB 'wiki-*' " "ORDER BY lower(name)"); if(rc) return rc; while( !doBreak && !rc && (FSL_RC_STEP_ROW==fsl_stmt_step(&names))){ fsl_size_t nameLen = 0; char const * pageName = fsl_stmt_g_text(&names, 0, &nameLen); if(!st.stmt){ rc = fsl_db_prepare(db, &st, "SELECT x.rid AS mrid FROM tag t, tagxref x " "WHERE x.tagid=t.tagid " "AND t.tagname='wiki-'||? " "ORDER BY mtime DESC LIMIT 1"); if(rc) goto end; } rc = fsl_stmt_bind_text(&st, 1, pageName, (fsl_int_t)nameLen, 0); if(rc) break; rc = fsl_stmt_step(&st); assert(FSL_RC_STEP_ROW==rc); if(FSL_RC_STEP_ROW==rc){ fsl_deck d = fsl_deck_empty; fsl_id_t rid = fsl_stmt_g_id(&st, 0); rc = fsl_deck_load_rid( f, &d, rid, FSL_CATYPE_WIKI); if(!rc){ rc = cb(f, &d, state); if(FSL_RC_BREAK==rc){ rc = 0; doBreak = 1; } } fsl_deck_finalize(&d); } fsl_stmt_reset(&st); } end: fsl_stmt_finalize(&st); fsl_stmt_finalize(&names); return rc; } } int fsl_wiki_save(fsl_cx * f, char const * pageName, fsl_buffer const * b, char const * userName, char const * mimeType, fsl_wiki_save_mode_t createPolicy ){ fsl_db * db = f ? fsl_needs_repo(f) : NULL; if(!f || !pageName || !b) return FSL_RC_MISUSE; else if(!*pageName) return FSL_RC_RANGE; else if(!db) return FSL_RC_NOT_A_REPO; else{ fsl_deck d = fsl_deck_empty; fsl_id_t parentRid = 0; int rc = fsl_wiki_latest_rid(f, pageName, &parentRid); fsl_double_t mtime; if(rc) return rc; else if((FSL_WIKI_SAVE_MODE_UPDATE==createPolicy) && !parentRid){ return fsl_cx_err_set(f, FSL_RC_NOT_FOUND, "No such wiki page: %s", pageName); } else if((FSL_WIKI_SAVE_MODE_CREATE==createPolicy) && (parentRid>0)){ return fsl_cx_err_set(f, FSL_RC_ALREADY_EXISTS, "Wiki page already exists: %s", pageName); } mtime = fsl_db_julian_now(db); fsl_deck_init(f, &d, FSL_CATYPE_WIKI); rc = fsl_deck_D_set(&d, mtime); assert(!rc); rc = fsl_deck_L_set(&d, pageName, -1); if(!rc && mimeType && *mimeType){ rc = fsl_deck_N_set(&d, mimeType, -1); } if( !rc && parentRid ){ char * zUuid = fsl_rid_to_uuid(f, parentRid); if(!zUuid){ rc = FSL_RC_OOM; }else{ rc = fsl_deck_P_add(&d,zUuid); fsl_free(zUuid); } } if(rc) goto end; { char * u = NULL; if(!userName) userName = fsl_cx_user_get(f); if(!userName){ u = fsl_guess_user_name(); if(!u) rc = FSL_RC_OOM; } if(!rc) rc = fsl_deck_U_set(&d, u ? u : userName, -1); if(u) fsl_free(u); if(rc) goto end; } rc = fsl_deck_W_set(&d, fsl_buffer_cstr(b), (fsl_int_t)b->used); #if 0 fsl_deck_output(f, &d, fsl_output_f_FILE, stdout); #endif if(!rc) rc = fsl_deck_save(&d, 0); end: fsl_deck_finalize(&d); return rc; } } #undef MARKER