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: **
3b5514ed82 2007-09-22       drh: ** This file contains code used to cross link control files and
09c4adeb6f 2007-09-22       drh: ** manifests.  The file is named "manifest.c" because it was
09c4adeb6f 2007-09-22       drh: ** original only used to parse manifests.  Then later clusters
2ab2db0bd3 2007-10-05       drh: ** and control files and wiki pages and tickets were added.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: #include "config.h"
dbda8d6ce9 2007-07-21       drh: #include "manifest.h"
dbda8d6ce9 2007-07-21       drh: #include <assert.h>
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: #if INTERFACE
dbda8d6ce9 2007-07-21       drh: /*
3b5514ed82 2007-09-22       drh: ** Types of control files
3b5514ed82 2007-09-22       drh: */
3b5514ed82 2007-09-22       drh: #define CFTYPE_MANIFEST   1
3b5514ed82 2007-09-22       drh: #define CFTYPE_CLUSTER    2
3b5514ed82 2007-09-22       drh: #define CFTYPE_CONTROL    3
2ab2db0bd3 2007-10-05       drh: #define CFTYPE_WIKI       4
2ab2db0bd3 2007-10-05       drh: #define CFTYPE_TICKET     5
2ab2db0bd3 2007-10-05       drh: 
2ab2db0bd3 2007-10-05       drh: /*
2ab2db0bd3 2007-10-05       drh: ** Mode parameter values
2ab2db0bd3 2007-10-05       drh: */
2ab2db0bd3 2007-10-05       drh: #define CFMODE_READ       1
2ab2db0bd3 2007-10-05       drh: #define CFMODE_APPEND     2
2ab2db0bd3 2007-10-05       drh: #define CFMODE_WRITE      3
3b5514ed82 2007-09-22       drh: 
3b5514ed82 2007-09-22       drh: /*
ba486fec5a 2007-09-03       drh: ** A parsed manifest or cluster.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: struct Manifest {
dbda8d6ce9 2007-07-21       drh:   Blob content;         /* The original content blob */
3b5514ed82 2007-09-22       drh:   int type;             /* Type of file */
2ab2db0bd3 2007-10-05       drh:   int mode;             /* Access mode */
dbda8d6ce9 2007-07-21       drh:   char *zComment;       /* Decoded comment */
dbda8d6ce9 2007-07-21       drh:   double rDate;         /* Time in the "D" line */
dbda8d6ce9 2007-07-21       drh:   char *zUser;          /* Name of the user */
dbda8d6ce9 2007-07-21       drh:   char *zRepoCksum;     /* MD5 checksum of the baseline content */
2ab2db0bd3 2007-10-05       drh:   char *zWiki;          /* Text of the wiki page */
2ab2db0bd3 2007-10-05       drh:   char *zWikiTitle;     /* Name of the wiki page */
2ab2db0bd3 2007-10-05       drh:   char *zTicketUuid;    /* UUID for a ticket */
dbda8d6ce9 2007-07-21       drh:   int nFile;            /* Number of F lines */
dbda8d6ce9 2007-07-21       drh:   int nFileAlloc;       /* Slots allocated in aFile[] */
dbda8d6ce9 2007-07-21       drh:   struct {
dbda8d6ce9 2007-07-21       drh:     char *zName;           /* Name of a file */
dbda8d6ce9 2007-07-21       drh:     char *zUuid;           /* UUID of the file */
33c31f73cd 2008-02-21       drh:     char *zPerm;           /* File permissions */
dbda8d6ce9 2007-07-21       drh:   } *aFile;
dbda8d6ce9 2007-07-21       drh:   int nParent;          /* Number of parents */
dbda8d6ce9 2007-07-21       drh:   int nParentAlloc;     /* Slots allocated in azParent[] */
dbda8d6ce9 2007-07-21       drh:   char **azParent;      /* UUIDs of parents */
ba486fec5a 2007-09-03       drh:   int nCChild;          /* Number of cluster children */
ba486fec5a 2007-09-03       drh:   int nCChildAlloc;     /* Number of closts allocated in azCChild[] */
ba486fec5a 2007-09-03       drh:   char **azCChild;      /* UUIDs of referenced objects in a cluster */
3dc92fdb7f 2007-09-21       drh:   int nTag;             /* Number of T lines */
3dc92fdb7f 2007-09-21       drh:   int nTagAlloc;        /* Slots allocated in aTag[] */
3dc92fdb7f 2007-09-21       drh:   struct {
3dc92fdb7f 2007-09-21       drh:     char *zName;           /* Name of the tag */
3dc92fdb7f 2007-09-21       drh:     char *zUuid;           /* UUID that the tag is applied to */
f73c0e792b 2007-09-22       drh:     char *zValue;          /* Value if the tag is really a property */
3dc92fdb7f 2007-09-21       drh:   } *aTag;
2ab2db0bd3 2007-10-05       drh:   int nField;           /* Number of J lines */
2ab2db0bd3 2007-10-05       drh:   int nFieldAlloc;      /* Slots allocated in aField[] */
2ab2db0bd3 2007-10-05       drh:   struct {
2ab2db0bd3 2007-10-05       drh:     char *zName;           /* Key or field name */
2ab2db0bd3 2007-10-05       drh:     char *zValue;          /* Value of the field */
2ab2db0bd3 2007-10-05       drh:   } *aField;
2ab2db0bd3 2007-10-05       drh:   int nAttach;          /* Number of A lines */
2ab2db0bd3 2007-10-05       drh:   int nAttachAlloc;     /* Slots allocated in aAttach[] */
2ab2db0bd3 2007-10-05       drh:   struct {
2ab2db0bd3 2007-10-05       drh:     char *zUuid;           /* UUID of the attachment */
2ab2db0bd3 2007-10-05       drh:     char *zName;           /* Name of the attachment */
2ab2db0bd3 2007-10-05       drh:     char *zDesc;           /* Description of the attachment */
2ab2db0bd3 2007-10-05       drh:   } *aAttach;
dbda8d6ce9 2007-07-21       drh: };
dbda8d6ce9 2007-07-21       drh: #endif
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Clear the memory allocated in a manifest object
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: void manifest_clear(Manifest *p){
dbda8d6ce9 2007-07-21       drh:   blob_reset(&p->content);
dbda8d6ce9 2007-07-21       drh:   free(p->aFile);
dbda8d6ce9 2007-07-21       drh:   free(p->azParent);
ba486fec5a 2007-09-03       drh:   free(p->azCChild);
2ab2db0bd3 2007-10-05       drh:   free(p->aTag);
2ab2db0bd3 2007-10-05       drh:   free(p->aField);
2ab2db0bd3 2007-10-05       drh:   free(p->aAttach);
dbda8d6ce9 2007-07-21       drh:   memset(p, 0, sizeof(*p));
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
2ab2db0bd3 2007-10-05       drh: ** Parse a blob into a Manifest object.  The Manifest object
2ab2db0bd3 2007-10-05       drh: ** takes over the input blob and will free it when the
dbda8d6ce9 2007-07-21       drh: ** Manifest object is freed.  Zeros are inserted into the blob
dbda8d6ce9 2007-07-21       drh: ** as string terminators so that blob should not be used again.
dbda8d6ce9 2007-07-21       drh: **
2ab2db0bd3 2007-10-05       drh: ** Return TRUE if the content really is a control file of some
2ab2db0bd3 2007-10-05       drh: ** kind.  Return FALSE if there are syntax errors.
2ab2db0bd3 2007-10-05       drh: **
2ab2db0bd3 2007-10-05       drh: ** This routine is strict about the format of a control file.
2ab2db0bd3 2007-10-05       drh: ** The format must match exactly or else it is rejected.  This
2ab2db0bd3 2007-10-05       drh: ** rule minimizes the risk that a content file will be mistaken
2ab2db0bd3 2007-10-05       drh: ** for a control file simply because they look the same.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** The pContent is reset.  If TRUE is returned, then pContent will
dbda8d6ce9 2007-07-21       drh: ** be reset when the Manifest object is cleared.  If FALSE is
dbda8d6ce9 2007-07-21       drh: ** returned then the Manifest object is cleared automatically
dbda8d6ce9 2007-07-21       drh: ** and pContent is reset before the return.
2ab2db0bd3 2007-10-05       drh: **
2ab2db0bd3 2007-10-05       drh: ** The entire file can be PGP clear-signed.  The signature is ignored.
2ab2db0bd3 2007-10-05       drh: ** The file consists of zero or more cards, one card per line.
2ab2db0bd3 2007-10-05       drh: ** (Except: the content of the W card can extend of multiple lines.)
2ab2db0bd3 2007-10-05       drh: ** Each card is divided into tokens by a single space character.
2ab2db0bd3 2007-10-05       drh: ** The first token is a single upper-case letter which is the card type.
2ab2db0bd3 2007-10-05       drh: ** The card type determines the other parameters to the card.
2ab2db0bd3 2007-10-05       drh: ** Cards must occur in lexicographical order.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: int manifest_parse(Manifest *p, Blob *pContent){
dbda8d6ce9 2007-07-21       drh:   int seenHeader = 0;
2ab2db0bd3 2007-10-05       drh:   int seenZ = 0;
2ad378d065 2007-09-23       jnc:   int i, lineNo=0;
dbda8d6ce9 2007-07-21       drh:   Blob line, token, a1, a2, a3;
dea1ae50d3 2007-09-23       drh:   char cPrevType = 0;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   memset(p, 0, sizeof(*p));
dbda8d6ce9 2007-07-21       drh:   memcpy(&p->content, pContent, sizeof(p->content));
dbda8d6ce9 2007-07-21       drh:   blob_zero(pContent);
dbda8d6ce9 2007-07-21       drh:   pContent = &p->content;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   blob_zero(&a1);
dbda8d6ce9 2007-07-21       drh:   blob_zero(&a2);
33c31f73cd 2008-02-21       drh:   blob_zero(&a3);
dbda8d6ce9 2007-07-21       drh:   md5sum_init();
dbda8d6ce9 2007-07-21       drh:   while( blob_line(pContent, &line) ){
dbda8d6ce9 2007-07-21       drh:     char *z = blob_buffer(&line);
2ad378d065 2007-09-23       jnc:     lineNo++;
dbda8d6ce9 2007-07-21       drh:     if( z[0]=='-' ){
dbda8d6ce9 2007-07-21       drh:       if( strncmp(z, "-----BEGIN PGP ", 15)!=0 ){
dbda8d6ce9 2007-07-21       drh:         goto manifest_syntax_error;
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:       if( seenHeader ){
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh:       }
f030c0aea7 2007-08-30       drh:       while( blob_line(pContent, &line)>2 ){}
dbda8d6ce9 2007-07-21       drh:       if( blob_line(pContent, &line)==0 ) break;
e37451d9c2 2007-08-01       drh:       z = blob_buffer(&line);
e37451d9c2 2007-08-01       drh:     }
dea1ae50d3 2007-09-23       drh:     if( z[0]<cPrevType ){
3dc92fdb7f 2007-09-21       drh:       /* Lines of a manifest must occur in lexicographical order */
3dc92fdb7f 2007-09-21       drh:       goto manifest_syntax_error;
dbda8d6ce9 2007-07-21       drh:     }
dea1ae50d3 2007-09-23       drh:     cPrevType = z[0];
dbda8d6ce9 2007-07-21       drh:     seenHeader = 1;
dbda8d6ce9 2007-07-21       drh:     if( blob_token(&line, &token)!=1 ) goto manifest_syntax_error;
3dc92fdb7f 2007-09-21       drh:     switch( z[0] ){
2ab2db0bd3 2007-10-05       drh:       /*
2ab2db0bd3 2007-10-05       drh:       **     A <uuid> <filename> <description>
2ab2db0bd3 2007-10-05       drh:       **
2ab2db0bd3 2007-10-05       drh:       ** Identifies an attachment to either a wiki page or a ticket.
2ab2db0bd3 2007-10-05       drh:       ** <uuid> is the artifact that is the attachment.
2ab2db0bd3 2007-10-05       drh:       */
2ab2db0bd3 2007-10-05       drh:       case 'A': {
2ab2db0bd3 2007-10-05       drh:         char *zName, *zUuid, *zDesc;
2ab2db0bd3 2007-10-05       drh:         md5sum_step_text(blob_buffer(&line), blob_size(&line));
2ab2db0bd3 2007-10-05       drh:         if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:         if( blob_token(&line, &a2)==0 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:         if( blob_token(&line, &a3)==0 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:         zUuid = blob_terminate(&a1);
2ab2db0bd3 2007-10-05       drh:         zName = blob_terminate(&a2);
2ab2db0bd3 2007-10-05       drh:         zDesc = blob_terminate(&a3);
2ab2db0bd3 2007-10-05       drh:         if( blob_size(&a1)!=UUID_SIZE ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:         if( !validate16(zUuid, UUID_SIZE) ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:         defossilize(zName);
2ab2db0bd3 2007-10-05       drh:         if( !file_is_simple_pathname(zName) ){
2ab2db0bd3 2007-10-05       drh:           goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:         }
2ab2db0bd3 2007-10-05       drh:         defossilize(zDesc);
2ab2db0bd3 2007-10-05       drh:         if( p->nAttach>=p->nAttachAlloc ){
2ab2db0bd3 2007-10-05       drh:           p->nAttachAlloc = p->nAttachAlloc*2 + 10;
2ab2db0bd3 2007-10-05       drh:           p->aAttach = realloc(p->aAttach,
2ab2db0bd3 2007-10-05       drh:                                p->nAttachAlloc*sizeof(p->aAttach[0]) );
2ab2db0bd3 2007-10-05       drh:           if( p->aAttach==0 ) fossil_panic("out of memory");
2ab2db0bd3 2007-10-05       drh:         }
2ab2db0bd3 2007-10-05       drh:         i = p->nAttach++;
2ab2db0bd3 2007-10-05       drh:         p->aAttach[i].zUuid = zUuid;
2ab2db0bd3 2007-10-05       drh:         p->aAttach[i].zName = zName;
2ab2db0bd3 2007-10-05       drh:         p->aAttach[i].zDesc = zDesc;
2ab2db0bd3 2007-10-05       drh:         if( i>0 && strcmp(p->aAttach[i-1].zUuid, zUuid)>=0 ){
2ab2db0bd3 2007-10-05       drh:           goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:         }
2ab2db0bd3 2007-10-05       drh:         break;
2ab2db0bd3 2007-10-05       drh:       }
2ab2db0bd3 2007-10-05       drh: 
3dc92fdb7f 2007-09-21       drh:       /*
3dc92fdb7f 2007-09-21       drh:       **     C <comment>
3dc92fdb7f 2007-09-21       drh:       **
3dc92fdb7f 2007-09-21       drh:       ** Comment text is fossil-encoded.  There may be no more than
3dc92fdb7f 2007-09-21       drh:       ** one C line.  C lines are required for manifests and are
3dc92fdb7f 2007-09-21       drh:       ** disallowed on all other control files.
3dc92fdb7f 2007-09-21       drh:       */
3dc92fdb7f 2007-09-21       drh:       case 'C': {
3dc92fdb7f 2007-09-21       drh:         md5sum_step_text(blob_buffer(&line), blob_size(&line));
3dc92fdb7f 2007-09-21       drh:         if( p->zComment!=0 ) goto manifest_syntax_error;
3dc92fdb7f 2007-09-21       drh:         if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error;
3dc92fdb7f 2007-09-21       drh:         if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error;
3dc92fdb7f 2007-09-21       drh:         p->zComment = blob_terminate(&a1);
3dc92fdb7f 2007-09-21       drh:         defossilize(p->zComment);
3dc92fdb7f 2007-09-21       drh:         break;
3dc92fdb7f 2007-09-21       drh:       }
3dc92fdb7f 2007-09-21       drh: 
3dc92fdb7f 2007-09-21       drh:       /*
3dc92fdb7f 2007-09-21       drh:       **     D <timestamp>
3dc92fdb7f 2007-09-21       drh:       **
3dc92fdb7f 2007-09-21       drh:       ** The timestamp should be ISO 8601.   YYYY-MM-DDtHH:MM:SS
3dc92fdb7f 2007-09-21       drh:       ** There can be no more than 1 D line.  D lines are required
3dc92fdb7f 2007-09-21       drh:       ** for all control files except for clusters.
3dc92fdb7f 2007-09-21       drh:       */
3dc92fdb7f 2007-09-21       drh:       case 'D': {
3dc92fdb7f 2007-09-21       drh:         char *zDate;
3dc92fdb7f 2007-09-21       drh:         md5sum_step_text(blob_buffer(&line), blob_size(&line));
3dc92fdb7f 2007-09-21       drh:         if( p->rDate!=0.0 ) goto manifest_syntax_error;
3dc92fdb7f 2007-09-21       drh:         if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error;
3dc92fdb7f 2007-09-21       drh:         if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error;
3dc92fdb7f 2007-09-21       drh:         zDate = blob_terminate(&a1);
3dc92fdb7f 2007-09-21       drh:         p->rDate = db_double(0.0, "SELECT julianday(%Q)", zDate);
3dc92fdb7f 2007-09-21       drh:         break;
3dc92fdb7f 2007-09-21       drh:       }
3dc92fdb7f 2007-09-21       drh: 
3dc92fdb7f 2007-09-21       drh:       /*
2ab2db0bd3 2007-10-05       drh:       **     E <mode>
2ab2db0bd3 2007-10-05       drh:       **
2ab2db0bd3 2007-10-05       drh:       ** Access mode.  <mode> can be one of "read", "append",
2ab2db0bd3 2007-10-05       drh:       ** or "write".
2ab2db0bd3 2007-10-05       drh:       */
2ab2db0bd3 2007-10-05       drh:       case 'E': {
2ab2db0bd3 2007-10-05       drh:         md5sum_step_text(blob_buffer(&line), blob_size(&line));
2ab2db0bd3 2007-10-05       drh:         if( p->mode!=0 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:         if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:         if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:         if( blob_eq(&a1, "write") ){
2ab2db0bd3 2007-10-05       drh:           p->mode = CFMODE_WRITE;
2ab2db0bd3 2007-10-05       drh:         }else if( blob_eq(&a1, "append") ){
2ab2db0bd3 2007-10-05       drh:           p->mode = CFMODE_APPEND;
2ab2db0bd3 2007-10-05       drh:         }else if( blob_eq(&a1, "read") ){
2ab2db0bd3 2007-10-05       drh:           p->mode = CFMODE_READ;
2ab2db0bd3 2007-10-05       drh:         }else{
2ab2db0bd3 2007-10-05       drh:           goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:         }
2ab2db0bd3 2007-10-05       drh:         break;
2ab2db0bd3 2007-10-05       drh:       }
2ab2db0bd3 2007-10-05       drh: 
2ab2db0bd3 2007-10-05       drh:       /*
33c31f73cd 2008-02-21       drh:       **     F <filename> <uuid> ?<permissions>?
3dc92fdb7f 2007-09-21       drh:       **
3dc92fdb7f 2007-09-21       drh:       ** Identifies a file in a manifest.  Multiple F lines are
3dc92fdb7f 2007-09-21       drh:       ** allowed in a manifest.  F lines are not allowed in any
3dc92fdb7f 2007-09-21       drh:       ** other control file.  The filename is fossil-encoded.
3dc92fdb7f 2007-09-21       drh:       */
3dc92fdb7f 2007-09-21       drh:       case 'F': {
33c31f73cd 2008-02-21       drh:         char *zName, *zUuid, *zPerm;
3dc92fdb7f 2007-09-21       drh:         md5sum_step_text(blob_buffer(&line), blob_size(&line));
3dc92fdb7f 2007-09-21       drh:         if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error;
3dc92fdb7f 2007-09-21       drh:         if( blob_token(&line, &a2)==0 ) goto manifest_syntax_error;
3dc92fdb7f 2007-09-21       drh:         zName = blob_terminate(&a1);
3dc92fdb7f 2007-09-21       drh:         zUuid = blob_terminate(&a2);
33c31f73cd 2008-02-21       drh:         blob_token(&line, &a3);
33c31f73cd 2008-02-21       drh:         zPerm = blob_terminate(&a3);
3dc92fdb7f 2007-09-21       drh:         if( blob_size(&a2)!=UUID_SIZE ) goto manifest_syntax_error;
3dc92fdb7f 2007-09-21       drh:         if( !validate16(zUuid, UUID_SIZE) ) goto manifest_syntax_error;
3dc92fdb7f 2007-09-21       drh:         defossilize(zName);
3dc92fdb7f 2007-09-21       drh:         if( !file_is_simple_pathname(zName) ){
3dc92fdb7f 2007-09-21       drh:           goto manifest_syntax_error;
3dc92fdb7f 2007-09-21       drh:         }
3dc92fdb7f 2007-09-21       drh:         if( p->nFile>=p->nFileAlloc ){
3dc92fdb7f 2007-09-21       drh:           p->nFileAlloc = p->nFileAlloc*2 + 10;
3dc92fdb7f 2007-09-21       drh:           p->aFile = realloc(p->aFile, p->nFileAlloc*sizeof(p->aFile[0]) );
3dc92fdb7f 2007-09-21       drh:           if( p->aFile==0 ) fossil_panic("out of memory");
3dc92fdb7f 2007-09-21       drh:         }
3dc92fdb7f 2007-09-21       drh:         i = p->nFile++;
3dc92fdb7f 2007-09-21       drh:         p->aFile[i].zName = zName;
3dc92fdb7f 2007-09-21       drh:         p->aFile[i].zUuid = zUuid;
33c31f73cd 2008-02-21       drh:         p->aFile[i].zPerm = zPerm;
3dc92fdb7f 2007-09-21       drh:         if( i>0 && strcmp(p->aFile[i-1].zName, zName)>=0 ){
2ab2db0bd3 2007-10-05       drh:           goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:         }
2ab2db0bd3 2007-10-05       drh:         break;
2ab2db0bd3 2007-10-05       drh:       }
2ab2db0bd3 2007-10-05       drh: 
2ab2db0bd3 2007-10-05       drh:       /*
d5e7891b07 2007-11-18       drh:       **     J '+'?<name> <value>
d5e7891b07 2007-11-18       drh:       **
d5e7891b07 2007-11-18       drh:       ** Specifies a name value pair for ticket.  If the first character
d5e7891b07 2007-11-18       drh:       ** of <name> is "+" then the value is appended to any preexisting
d5e7891b07 2007-11-18       drh:       ** value.
2ab2db0bd3 2007-10-05       drh:       */
2ab2db0bd3 2007-10-05       drh:       case 'J': {
2ab2db0bd3 2007-10-05       drh:         char *zName, *zValue;
2ab2db0bd3 2007-10-05       drh:         md5sum_step_text(blob_buffer(&line), blob_size(&line));
2ab2db0bd3 2007-10-05       drh:         if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:         if( blob_token(&line, &a2)==0 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:         if( blob_token(&line, &a3)!=0 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:         zName = blob_terminate(&a1);
2ab2db0bd3 2007-10-05       drh:         zValue = blob_terminate(&a2);
2ab2db0bd3 2007-10-05       drh:         defossilize(zValue);
2ab2db0bd3 2007-10-05       drh:         if( p->nField>=p->nFieldAlloc ){
2ab2db0bd3 2007-10-05       drh:           p->nFieldAlloc = p->nFieldAlloc*2 + 10;
2ab2db0bd3 2007-10-05       drh:           p->aField = realloc(p->aField,
2ab2db0bd3 2007-10-05       drh:                                p->nFieldAlloc*sizeof(p->aField[0]) );
2ab2db0bd3 2007-10-05       drh:           if( p->aField==0 ) fossil_panic("out of memory");
2ab2db0bd3 2007-10-05       drh:         }
2ab2db0bd3 2007-10-05       drh:         i = p->nField++;
2ab2db0bd3 2007-10-05       drh:         p->aField[i].zName = zName;
2ab2db0bd3 2007-10-05       drh:         p->aField[i].zValue = zValue;
2ab2db0bd3 2007-10-05       drh:         if( i>0 && strcmp(p->aField[i-1].zName, zName)>=0 ){
2ab2db0bd3 2007-10-05       drh:           goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:         }
2ab2db0bd3 2007-10-05       drh:         break;
2ab2db0bd3 2007-10-05       drh:       }
2ab2db0bd3 2007-10-05       drh: 
2ab2db0bd3 2007-10-05       drh: 
2ab2db0bd3 2007-10-05       drh:       /*
2ab2db0bd3 2007-10-05       drh:       **    K <uuid>
2ab2db0bd3 2007-10-05       drh:       **
2ab2db0bd3 2007-10-05       drh:       ** A K-line gives the UUID for the ticket which this control file
2ab2db0bd3 2007-10-05       drh:       ** is amending.
2ab2db0bd3 2007-10-05       drh:       */
2ab2db0bd3 2007-10-05       drh:       case 'K': {
2ab2db0bd3 2007-10-05       drh:         char *zUuid;
2ab2db0bd3 2007-10-05       drh:         md5sum_step_text(blob_buffer(&line), blob_size(&line));
2ab2db0bd3 2007-10-05       drh:         if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:         zUuid = blob_terminate(&a1);
2ab2db0bd3 2007-10-05       drh:         if( blob_size(&a1)!=UUID_SIZE ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:         if( !validate16(zUuid, UUID_SIZE) ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:         if( p->zTicketUuid!=0 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:         p->zTicketUuid = zUuid;
2ab2db0bd3 2007-10-05       drh:         break;
2ab2db0bd3 2007-10-05       drh:       }
2ab2db0bd3 2007-10-05       drh: 
2ab2db0bd3 2007-10-05       drh:       /*
d5e7891b07 2007-11-18       drh:       **     L <wikititle>
2ab2db0bd3 2007-10-05       drh:       **
2ab2db0bd3 2007-10-05       drh:       ** The wiki page title is fossil-encoded.  There may be no more than
2ab2db0bd3 2007-10-05       drh:       ** one L line.
2ab2db0bd3 2007-10-05       drh:       */
2ab2db0bd3 2007-10-05       drh:       case 'L': {
2ab2db0bd3 2007-10-05       drh:         md5sum_step_text(blob_buffer(&line), blob_size(&line));
2ab2db0bd3 2007-10-05       drh:         if( p->zWikiTitle!=0 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:         if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:         if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:         p->zWikiTitle = blob_terminate(&a1);
2ab2db0bd3 2007-10-05       drh:         defossilize(p->zWikiTitle);
488afb9746 2007-10-06       drh:         if( !wiki_name_is_wellformed(p->zWikiTitle) ){
3dc92fdb7f 2007-09-21       drh:           goto manifest_syntax_error;
3dc92fdb7f 2007-09-21       drh:         }
3dc92fdb7f 2007-09-21       drh:         break;
3dc92fdb7f 2007-09-21       drh:       }
3dc92fdb7f 2007-09-21       drh: 
3dc92fdb7f 2007-09-21       drh:       /*
3dc92fdb7f 2007-09-21       drh:       **    M <uuid>
3dc92fdb7f 2007-09-21       drh:       **
3dc92fdb7f 2007-09-21       drh:       ** An M-line identifies another artifact by its UUID.  M-lines
3dc92fdb7f 2007-09-21       drh:       ** occur in clusters only.
3dc92fdb7f 2007-09-21       drh:       */
3dc92fdb7f 2007-09-21       drh:       case 'M': {
dbda8d6ce9 2007-07-21       drh:         char *zUuid;
3dc92fdb7f 2007-09-21       drh:         md5sum_step_text(blob_buffer(&line), blob_size(&line));
3dc92fdb7f 2007-09-21       drh:         if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error;
dbda8d6ce9 2007-07-21       drh:         zUuid = blob_terminate(&a1);
3dc92fdb7f 2007-09-21       drh:         if( blob_size(&a1)!=UUID_SIZE ) goto manifest_syntax_error;
dbda8d6ce9 2007-07-21       drh:         if( !validate16(zUuid, UUID_SIZE) ) goto manifest_syntax_error;
3dc92fdb7f 2007-09-21       drh:         if( p->nCChild>=p->nCChildAlloc ){
3dc92fdb7f 2007-09-21       drh:           p->nCChildAlloc = p->nCChildAlloc*2 + 10;
3dc92fdb7f 2007-09-21       drh:           p->azCChild =
3dc92fdb7f 2007-09-21       drh:              realloc(p->azCChild, p->nCChildAlloc*sizeof(p->azCChild[0]) );
3dc92fdb7f 2007-09-21       drh:           if( p->azCChild==0 ) fossil_panic("out of memory");
3dc92fdb7f 2007-09-21       drh:         }
3dc92fdb7f 2007-09-21       drh:         i = p->nCChild++;
3dc92fdb7f 2007-09-21       drh:         p->azCChild[i] = zUuid;
3dc92fdb7f 2007-09-21       drh:         if( i>0 && strcmp(p->azCChild[i-1], zUuid)>=0 ){
3dc92fdb7f 2007-09-21       drh:           goto manifest_syntax_error;
3dc92fdb7f 2007-09-21       drh:         }
3dc92fdb7f 2007-09-21       drh:         break;
3dc92fdb7f 2007-09-21       drh:       }
3dc92fdb7f 2007-09-21       drh: 
3dc92fdb7f 2007-09-21       drh:       /*
3dc92fdb7f 2007-09-21       drh:       **     P <uuid> ...
3dc92fdb7f 2007-09-21       drh:       **
3dc92fdb7f 2007-09-21       drh:       ** Specify one or more other artifacts where are the parents of
3dc92fdb7f 2007-09-21       drh:       ** this artifact.  The first parent is the primary parent.  All
3dc92fdb7f 2007-09-21       drh:       ** others are parents by merge.
3dc92fdb7f 2007-09-21       drh:       */
3dc92fdb7f 2007-09-21       drh:       case 'P': {
3dc92fdb7f 2007-09-21       drh:         md5sum_step_text(blob_buffer(&line), blob_size(&line));
3dc92fdb7f 2007-09-21       drh:         while( blob_token(&line, &a1) ){
3dc92fdb7f 2007-09-21       drh:           char *zUuid;
3dc92fdb7f 2007-09-21       drh:           if( blob_size(&a1)!=UUID_SIZE ) goto manifest_syntax_error;
3dc92fdb7f 2007-09-21       drh:           zUuid = blob_terminate(&a1);
3dc92fdb7f 2007-09-21       drh:           if( !validate16(zUuid, UUID_SIZE) ) goto manifest_syntax_error;
3dc92fdb7f 2007-09-21       drh:           if( p->nParent>=p->nParentAlloc ){
3dc92fdb7f 2007-09-21       drh:             p->nParentAlloc = p->nParentAlloc*2 + 5;
3dc92fdb7f 2007-09-21       drh:             p->azParent = realloc(p->azParent, p->nParentAlloc*sizeof(char*));
3dc92fdb7f 2007-09-21       drh:             if( p->azParent==0 ) fossil_panic("out of memory");
3dc92fdb7f 2007-09-21       drh:           }
3dc92fdb7f 2007-09-21       drh:           i = p->nParent++;
3dc92fdb7f 2007-09-21       drh:           p->azParent[i] = zUuid;
3dc92fdb7f 2007-09-21       drh:         }
3dc92fdb7f 2007-09-21       drh:         break;
3dc92fdb7f 2007-09-21       drh:       }
3dc92fdb7f 2007-09-21       drh: 
3dc92fdb7f 2007-09-21       drh:       /*
2ab2db0bd3 2007-10-05       drh:       **     R <md5sum>
2ab2db0bd3 2007-10-05       drh:       **
2ab2db0bd3 2007-10-05       drh:       ** Specify the MD5 checksum of the entire baseline in a
2ab2db0bd3 2007-10-05       drh:       ** manifest.
2ab2db0bd3 2007-10-05       drh:       */
2ab2db0bd3 2007-10-05       drh:       case 'R': {
2ab2db0bd3 2007-10-05       drh:         md5sum_step_text(blob_buffer(&line), blob_size(&line));
2ab2db0bd3 2007-10-05       drh:         if( p->zRepoCksum!=0 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:         if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:         if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:         if( blob_size(&a1)!=32 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:         p->zRepoCksum = blob_terminate(&a1);
2ab2db0bd3 2007-10-05       drh:         if( !validate16(p->zRepoCksum, 32) ) goto manifest_syntax_error;
2ad378d065 2007-09-23       jnc:         break;
2ad378d065 2007-09-23       jnc:       }
2ad378d065 2007-09-23       jnc: 
2ad378d065 2007-09-23       jnc:       /*
09c4adeb6f 2007-09-22       drh:       **    T (+|*|-)<tagname> <uuid> ?<value>?
f73c0e792b 2007-09-22       drh:       **
f73c0e792b 2007-09-22       drh:       ** Create or cancel a tag or property.  The tagname is fossil-encoded.
09c4adeb6f 2007-09-22       drh:       ** The first character of the name must be either "+" to create a
09c4adeb6f 2007-09-22       drh:       ** singleton tag, "*" to create a propagating tag, or "-" to create
09c4adeb6f 2007-09-22       drh:       ** anti-tag that undoes a prior "+" or blocks propagation of of
09c4adeb6f 2007-09-22       drh:       ** a "*".
09c4adeb6f 2007-09-22       drh:       **
09c4adeb6f 2007-09-22       drh:       ** The tag is applied to <uuid>.  If <uuid> is "*" then the tag is
09c4adeb6f 2007-09-22       drh:       ** applied to the current manifest.  If <value> is provided then
09c4adeb6f 2007-09-22       drh:       ** the tag is really a property with the given value.
09c4adeb6f 2007-09-22       drh:       **
f73c0e792b 2007-09-22       drh:       ** Tags are not allowed in clusters.  Multiple T lines are allowed.
f73c0e792b 2007-09-22       drh:       */
f73c0e792b 2007-09-22       drh:       case 'T': {
f73c0e792b 2007-09-22       drh:         char *zName, *zUuid, *zValue;
f73c0e792b 2007-09-22       drh:         md5sum_step_text(blob_buffer(&line), blob_size(&line));
2ad378d065 2007-09-23       jnc:         if( blob_token(&line, &a1)==0 ){
2ad378d065 2007-09-23       jnc:           goto manifest_syntax_error;
2ad378d065 2007-09-23       jnc:         }
2ad378d065 2007-09-23       jnc:         if( blob_token(&line, &a2)==0 ){
2ad378d065 2007-09-23       jnc:           goto manifest_syntax_error;
2ad378d065 2007-09-23       jnc:         }
f73c0e792b 2007-09-22       drh:         zName = blob_terminate(&a1);
f73c0e792b 2007-09-22       drh:         zUuid = blob_terminate(&a2);
f73c0e792b 2007-09-22       drh:         if( blob_token(&line, &a3)==0 ){
f73c0e792b 2007-09-22       drh:           zValue = 0;
f73c0e792b 2007-09-22       drh:         }else{
f73c0e792b 2007-09-22       drh:           zValue = blob_terminate(&a3);
f73c0e792b 2007-09-22       drh:           defossilize(zValue);
f73c0e792b 2007-09-22       drh:         }
09c4adeb6f 2007-09-22       drh:         if( blob_size(&a2)==UUID_SIZE && validate16(zUuid, UUID_SIZE) ){
09c4adeb6f 2007-09-22       drh:           /* A valid uuid */
09c4adeb6f 2007-09-22       drh:         }else if( blob_size(&a2)==1 && zUuid[0]=='*' ){
0afb5e8e39 2008-03-08       drh:           zUuid = 0;
09c4adeb6f 2007-09-22       drh:         }else{
09c4adeb6f 2007-09-22       drh:           goto manifest_syntax_error;
09c4adeb6f 2007-09-22       drh:         }
f73c0e792b 2007-09-22       drh:         defossilize(zName);
09c4adeb6f 2007-09-22       drh:         if( zName[0]!='-' && zName[0]!='+' && zName[0]!='*' ){
3b5514ed82 2007-09-22       drh:           goto manifest_syntax_error;
3b5514ed82 2007-09-22       drh:         }
3b5514ed82 2007-09-22       drh:         if( validate16(&zName[1], strlen(&zName[1])) ){
3b5514ed82 2007-09-22       drh:           /* Do not allow tags whose names look like UUIDs */
f73c0e792b 2007-09-22       drh:           goto manifest_syntax_error;
f73c0e792b 2007-09-22       drh:         }
f73c0e792b 2007-09-22       drh:         if( p->nTag>=p->nTagAlloc ){
f73c0e792b 2007-09-22       drh:           p->nTagAlloc = p->nTagAlloc*2 + 10;
f73c0e792b 2007-09-22       drh:           p->aTag = realloc(p->aTag, p->nTagAlloc*sizeof(p->aTag[0]) );
f73c0e792b 2007-09-22       drh:           if( p->aTag==0 ) fossil_panic("out of memory");
f73c0e792b 2007-09-22       drh:         }
f73c0e792b 2007-09-22       drh:         i = p->nTag++;
f73c0e792b 2007-09-22       drh:         p->aTag[i].zName = zName;
f73c0e792b 2007-09-22       drh:         p->aTag[i].zUuid = zUuid;
f73c0e792b 2007-09-22       drh:         p->aTag[i].zValue = zValue;
f73c0e792b 2007-09-22       drh:         if( i>0 && strcmp(p->aTag[i-1].zName, zName)>=0 ){
f73c0e792b 2007-09-22       drh:           goto manifest_syntax_error;
f73c0e792b 2007-09-22       drh:         }
f73c0e792b 2007-09-22       drh:         break;
f73c0e792b 2007-09-22       drh:       }
f73c0e792b 2007-09-22       drh: 
f73c0e792b 2007-09-22       drh:       /*
f73c0e792b 2007-09-22       drh:       **     U <login>
f73c0e792b 2007-09-22       drh:       **
f73c0e792b 2007-09-22       drh:       ** Identify the user who created this control file by their
f73c0e792b 2007-09-22       drh:       ** login.  Only one U line is allowed.  Prohibited in clusters.
f73c0e792b 2007-09-22       drh:       */
f73c0e792b 2007-09-22       drh:       case 'U': {
f73c0e792b 2007-09-22       drh:         md5sum_step_text(blob_buffer(&line), blob_size(&line));
f73c0e792b 2007-09-22       drh:         if( p->zUser!=0 ) goto manifest_syntax_error;
f73c0e792b 2007-09-22       drh:         if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error;
f73c0e792b 2007-09-22       drh:         if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error;
f73c0e792b 2007-09-22       drh:         p->zUser = blob_terminate(&a1);
f73c0e792b 2007-09-22       drh:         defossilize(p->zUser);
f73c0e792b 2007-09-22       drh:         break;
f73c0e792b 2007-09-22       drh:       }
f73c0e792b 2007-09-22       drh: 
f73c0e792b 2007-09-22       drh:       /*
2ab2db0bd3 2007-10-05       drh:       **     W <size>
f73c0e792b 2007-09-22       drh:       **
2ab2db0bd3 2007-10-05       drh:       ** The next <size> bytes of the file contain the text of the wiki
2ab2db0bd3 2007-10-05       drh:       ** page.  There is always an extra \n before the start of the next
2ab2db0bd3 2007-10-05       drh:       ** record.
f73c0e792b 2007-09-22       drh:       */
2ab2db0bd3 2007-10-05       drh:       case 'W': {
2ab2db0bd3 2007-10-05       drh:         int size;
2ab2db0bd3 2007-10-05       drh:         Blob wiki;
2ab2db0bd3 2007-10-05       drh:         md5sum_step_text(blob_buffer(&line), blob_size(&line));
f73c0e792b 2007-09-22       drh:         if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error;
f73c0e792b 2007-09-22       drh:         if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:         if( !blob_is_int(&a1, &size) ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:         if( size<0 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:         if( p->zWiki!=0 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:         blob_zero(&wiki);
2ab2db0bd3 2007-10-05       drh:         if( blob_extract(pContent, size+1, &wiki)!=size+1 ){
2ab2db0bd3 2007-10-05       drh:           goto manifest_syntax_error;
dbda8d6ce9 2007-07-21       drh:         }
2ab2db0bd3 2007-10-05       drh:         p->zWiki = blob_buffer(&wiki);
bf428e6854 2007-10-06       drh:         md5sum_step_text(p->zWiki, size+1);
2ab2db0bd3 2007-10-05       drh:         if( p->zWiki[size]!='\n' ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:         p->zWiki[size] = 0;
f73c0e792b 2007-09-22       drh:         break;
f73c0e792b 2007-09-22       drh:       }
f73c0e792b 2007-09-22       drh: 
f73c0e792b 2007-09-22       drh: 
f73c0e792b 2007-09-22       drh:       /*
3dc92fdb7f 2007-09-21       drh:       **     Z <md5sum>
3dc92fdb7f 2007-09-21       drh:       **
3dc92fdb7f 2007-09-21       drh:       ** MD5 checksum on this control file.  The checksum is over all
3dc92fdb7f 2007-09-21       drh:       ** lines (other than PGP-signature lines) prior to the current
3dc92fdb7f 2007-09-21       drh:       ** line.  This must be the last record.
2ab2db0bd3 2007-10-05       drh:       **
2ab2db0bd3 2007-10-05       drh:       ** This card is required for all control file types except for
2ab2db0bd3 2007-10-05       drh:       ** Manifest.  It is not required for manifest only for historical
2ab2db0bd3 2007-10-05       drh:       ** compatibility reasons.
3dc92fdb7f 2007-09-21       drh:       */
3dc92fdb7f 2007-09-21       drh:       case 'Z': {
3dc92fdb7f 2007-09-21       drh:         int rc;
3dc92fdb7f 2007-09-21       drh:         Blob hash;
3dc92fdb7f 2007-09-21       drh:         if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error;
3dc92fdb7f 2007-09-21       drh:         if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error;
3dc92fdb7f 2007-09-21       drh:         if( blob_size(&a1)!=32 ) goto manifest_syntax_error;
3dc92fdb7f 2007-09-21       drh:         if( !validate16(blob_buffer(&a1), 32) ) goto manifest_syntax_error;
3dc92fdb7f 2007-09-21       drh:         md5sum_finish(&hash);
3dc92fdb7f 2007-09-21       drh:         rc = blob_compare(&hash, &a1);
3dc92fdb7f 2007-09-21       drh:         blob_reset(&hash);
3dc92fdb7f 2007-09-21       drh:         if( rc!=0 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:         seenZ = 1;
3dc92fdb7f 2007-09-21       drh:         break;
3dc92fdb7f 2007-09-21       drh:       }
3dc92fdb7f 2007-09-21       drh:       default: {
3dc92fdb7f 2007-09-21       drh:         goto manifest_syntax_error;
3dc92fdb7f 2007-09-21       drh:       }
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   if( !seenHeader ) goto manifest_syntax_error;
3dc92fdb7f 2007-09-21       drh: 
3dc92fdb7f 2007-09-21       drh:   if( p->nFile>0 ){
3dc92fdb7f 2007-09-21       drh:     if( p->nCChild>0 ) goto manifest_syntax_error;
3dc92fdb7f 2007-09-21       drh:     if( p->rDate==0.0 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:     if( p->nField>0 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:     if( p->zTicketUuid ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:     if( p->nAttach>0 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:     if( p->zWiki ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:     if( p->zWikiTitle ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:     if( p->zTicketUuid ) goto manifest_syntax_error;
3b5514ed82 2007-09-22       drh:     p->type = CFTYPE_MANIFEST;
3dc92fdb7f 2007-09-21       drh:   }else if( p->nCChild>0 ){
3dc92fdb7f 2007-09-21       drh:     if( p->rDate>0.0 ) goto manifest_syntax_error;
3dc92fdb7f 2007-09-21       drh:     if( p->zComment!=0 ) goto manifest_syntax_error;
3dc92fdb7f 2007-09-21       drh:     if( p->zUser!=0 ) goto manifest_syntax_error;
3dc92fdb7f 2007-09-21       drh:     if( p->nTag>0 ) goto manifest_syntax_error;
3dc92fdb7f 2007-09-21       drh:     if( p->nParent>0 ) goto manifest_syntax_error;
3dc92fdb7f 2007-09-21       drh:     if( p->zRepoCksum!=0 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:     if( p->nField>0 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:     if( p->zTicketUuid ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:     if( p->nAttach>0 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:     if( p->zWiki ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:     if( p->zWikiTitle ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:     if( !seenZ ) goto manifest_syntax_error;
3b5514ed82 2007-09-22       drh:     p->type = CFTYPE_CLUSTER;
2ab2db0bd3 2007-10-05       drh:   }else if( p->nField>0 ){
2ab2db0bd3 2007-10-05       drh:     if( p->rDate==0.0 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:     if( p->zRepoCksum!=0 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:     if( p->zWiki ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:     if( p->zWikiTitle ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:     if( p->nCChild>0 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:     if( p->nTag>0 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:     if( p->zTicketUuid==0 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:     if( p->zUser==0 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:     if( !seenZ ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:     p->type = CFTYPE_TICKET;
2ab2db0bd3 2007-10-05       drh:   }else if( p->zWiki!=0 ){
2ab2db0bd3 2007-10-05       drh:     if( p->rDate==0.0 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:     if( p->zRepoCksum!=0 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:     if( p->nCChild>0 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:     if( p->nTag>0 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:     if( p->zTicketUuid!=0 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:     if( p->zWikiTitle==0 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:     if( !seenZ ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:     p->type = CFTYPE_WIKI;
3dc92fdb7f 2007-09-21       drh:   }else if( p->nTag>0 ){
3dc92fdb7f 2007-09-21       drh:     if( p->rDate<=0.0 ) goto manifest_syntax_error;
3dc92fdb7f 2007-09-21       drh:     if( p->zRepoCksum!=0 ) goto manifest_syntax_error;
3dc92fdb7f 2007-09-21       drh:     if( p->nParent>0 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:     if( p->nAttach>0 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:     if( p->nField>0 ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:     if( p->zWiki ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:     if( p->zWikiTitle ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:     if( p->zTicketUuid ) goto manifest_syntax_error;
2ab2db0bd3 2007-10-05       drh:     if( !seenZ ) goto manifest_syntax_error;
3b5514ed82 2007-09-22       drh:     p->type = CFTYPE_CONTROL;
3dc92fdb7f 2007-09-21       drh:   }else{
c8da83ca36 2008-02-04       drh:     if( p->nCChild>0 ) goto manifest_syntax_error;
c8da83ca36 2008-02-04       drh:     if( p->rDate==0.0 ) goto manifest_syntax_error;
c8da83ca36 2008-02-04       drh:     if( p->nField>0 ) goto manifest_syntax_error;
c8da83ca36 2008-02-04       drh:     if( p->zTicketUuid ) goto manifest_syntax_error;
c8da83ca36 2008-02-04       drh:     if( p->nAttach>0 ) goto manifest_syntax_error;
c8da83ca36 2008-02-04       drh:     if( p->zWiki ) goto manifest_syntax_error;
c8da83ca36 2008-02-04       drh:     if( p->zWikiTitle ) goto manifest_syntax_error;
c8da83ca36 2008-02-04       drh:     if( p->zTicketUuid ) goto manifest_syntax_error;
c8da83ca36 2008-02-04       drh:     p->type = CFTYPE_MANIFEST;
3dc92fdb7f 2007-09-21       drh:   }
3dc92fdb7f 2007-09-21       drh: 
dbda8d6ce9 2007-07-21       drh:   md5sum_init();
dbda8d6ce9 2007-07-21       drh:   return 1;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: manifest_syntax_error:
2ad378d065 2007-09-23       jnc:   /*fprintf(stderr, "Manifest error on line %i\n", lineNo);fflush(stderr);*/
dbda8d6ce9 2007-07-21       drh:   md5sum_init();
dbda8d6ce9 2007-07-21       drh:   manifest_clear(p);
dbda8d6ce9 2007-07-21       drh:   return 0;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Add a single entry to the mlink table.  Also add the filename to
dbda8d6ce9 2007-07-21       drh: ** the filename table if it is not there already.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static void add_one_mlink(
dbda8d6ce9 2007-07-21       drh:   int mid,                  /* The record ID of the manifest */
dbda8d6ce9 2007-07-21       drh:   const char *zFromUuid,    /* UUID for the mlink.pid field */
dbda8d6ce9 2007-07-21       drh:   const char *zToUuid,      /* UUID for the mlink.fid field */
dbda8d6ce9 2007-07-21       drh:   const char *zFilename     /* Filename */
dbda8d6ce9 2007-07-21       drh: ){
dbda8d6ce9 2007-07-21       drh:   int fnid, pid, fid;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename);
dbda8d6ce9 2007-07-21       drh:   if( fnid==0 ){
dbda8d6ce9 2007-07-21       drh:     db_multi_exec("INSERT INTO filename(name) VALUES(%Q)", zFilename);
dbda8d6ce9 2007-07-21       drh:     fnid = db_last_insert_rowid();
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   if( zFromUuid==0 ){
dbda8d6ce9 2007-07-21       drh:     pid = 0;
dbda8d6ce9 2007-07-21       drh:   }else{
dbda8d6ce9 2007-07-21       drh:     pid = uuid_to_rid(zFromUuid, 1);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   if( zToUuid==0 ){
dbda8d6ce9 2007-07-21       drh:     fid = 0;
dbda8d6ce9 2007-07-21       drh:   }else{
dbda8d6ce9 2007-07-21       drh:     fid = uuid_to_rid(zToUuid, 1);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   db_multi_exec(
dbda8d6ce9 2007-07-21       drh:     "INSERT INTO mlink(mid,pid,fid,fnid)"
dbda8d6ce9 2007-07-21       drh:     "VALUES(%d,%d,%d,%d)", mid, pid, fid, fnid
dbda8d6ce9 2007-07-21       drh:   );
dbda8d6ce9 2007-07-21       drh:   if( pid && fid ){
dbda8d6ce9 2007-07-21       drh:     content_deltify(pid, fid, 0);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Add mlink table entries associated with manifest cid.
dbda8d6ce9 2007-07-21       drh: ** There is an mlink entry for every file that changed going
dbda8d6ce9 2007-07-21       drh: ** from pid to cid.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** Deleted files have mlink.fid=0.
dbda8d6ce9 2007-07-21       drh: ** Added files have mlink.pid=0.
dbda8d6ce9 2007-07-21       drh: ** Edited files have both mlink.pid!=0 and mlink.fid!=0
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static void add_mlink(int pid, Manifest *pParent, int cid, Manifest *pChild){
dbda8d6ce9 2007-07-21       drh:   Manifest other;
dbda8d6ce9 2007-07-21       drh:   Blob otherContent;
dbda8d6ce9 2007-07-21       drh:   int i, j;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   if( db_exists("SELECT 1 FROM mlink WHERE mid=%d", cid) ){
dbda8d6ce9 2007-07-21       drh:     return;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   assert( pParent==0 || pChild==0 );
dbda8d6ce9 2007-07-21       drh:   if( pParent==0 ){
dbda8d6ce9 2007-07-21       drh:     pParent = &other;
dbda8d6ce9 2007-07-21       drh:     content_get(pid, &otherContent);
dbda8d6ce9 2007-07-21       drh:   }else{
dbda8d6ce9 2007-07-21       drh:     pChild = &other;
dbda8d6ce9 2007-07-21       drh:     content_get(cid, &otherContent);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   if( blob_size(&otherContent)==0 ) return;
dbda8d6ce9 2007-07-21       drh:   if( manifest_parse(&other, &otherContent)==0 ) return;
dbda8d6ce9 2007-07-21       drh:   content_deltify(pid, cid, 0);
5b58559c0c 2007-07-31       drh:   for(i=j=0; i<pParent->nFile && j<pChild->nFile; ){
dbda8d6ce9 2007-07-21       drh:     int c = strcmp(pParent->aFile[i].zName, pChild->aFile[j].zName);
dbda8d6ce9 2007-07-21       drh:     if( c<0 ){
dbda8d6ce9 2007-07-21       drh:       add_one_mlink(cid, pParent->aFile[i].zUuid, 0, pParent->aFile[i].zName);
dbda8d6ce9 2007-07-21       drh:       i++;
dbda8d6ce9 2007-07-21       drh:     }else if( c>0 ){
dbda8d6ce9 2007-07-21       drh:       add_one_mlink(cid, 0, pChild->aFile[j].zUuid, pChild->aFile[j].zName);
dbda8d6ce9 2007-07-21       drh:       j++;
dbda8d6ce9 2007-07-21       drh:     }else{
dbda8d6ce9 2007-07-21       drh:       if( strcmp(pParent->aFile[i].zUuid, pChild->aFile[j].zUuid)!=0 ){
dbda8d6ce9 2007-07-21       drh:       add_one_mlink(cid, pParent->aFile[i].zUuid, pChild->aFile[j].zUuid,
dbda8d6ce9 2007-07-21       drh:                     pChild->aFile[j].zName);
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:       i++;
dbda8d6ce9 2007-07-21       drh:       j++;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   while( i<pParent->nFile ){
dbda8d6ce9 2007-07-21       drh:     add_one_mlink(cid, pParent->aFile[i].zUuid, 0, pParent->aFile[i].zName);
dbda8d6ce9 2007-07-21       drh:     i++;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   while( j<pChild->nFile ){
dbda8d6ce9 2007-07-21       drh:     add_one_mlink(cid, 0, pChild->aFile[j].zUuid, pChild->aFile[j].zName);
dbda8d6ce9 2007-07-21       drh:     j++;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   manifest_clear(&other);
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
243e02bfbd 2008-05-18       drh: ** Scan artifact rid/pContent to see if it is a control artifact of
243e02bfbd 2008-05-18       drh: ** any key:
243e02bfbd 2008-05-18       drh: **
243e02bfbd 2008-05-18       drh: **      *  Manifest
243e02bfbd 2008-05-18       drh: **      *  Control
243e02bfbd 2008-05-18       drh: **      *  Wiki Page
243e02bfbd 2008-05-18       drh: **      *  Ticket Change
243e02bfbd 2008-05-18       drh: **      *  Cluster
243e02bfbd 2008-05-18       drh: **
243e02bfbd 2008-05-18       drh: ** If the input is a control artifact, then make appropriate entries
243e02bfbd 2008-05-18       drh: ** in the auxiliary tables of the database in order to crosslink the
243e02bfbd 2008-05-18       drh: ** artifact.
243e02bfbd 2008-05-18       drh: **
243e02bfbd 2008-05-18       drh: ** If global variable g.xlinkClusterOnly is true, then ignore all
243e02bfbd 2008-05-18       drh: ** control artifacts other than clusters.
ba486fec5a 2007-09-03       drh: **
243e02bfbd 2008-05-18       drh: ** Historical note:  This routine original processed manifests only.
243e02bfbd 2008-05-18       drh: ** Processing for other control artifacts was added later.  The name
243e02bfbd 2008-05-18       drh: ** of the routine, "manifest_crosslink", and the name of this source
243e02bfbd 2008-05-18       drh: ** file, is a legacy of its original use.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: int manifest_crosslink(int rid, Blob *pContent){
dbda8d6ce9 2007-07-21       drh:   int i;
dbda8d6ce9 2007-07-21       drh:   Manifest m;
dbda8d6ce9 2007-07-21       drh:   Stmt q;
913608a5a6 2007-09-25       drh:   int parentid = 0;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   if( manifest_parse(&m, pContent)==0 ){
dbda8d6ce9 2007-07-21       drh:     return 0;
dbda8d6ce9 2007-07-21       drh:   }
243e02bfbd 2008-05-18       drh:   if( g.xlinkClusterOnly && m.type!=CFTYPE_CLUSTER ){
243e02bfbd 2008-05-18       drh:     manifest_clear(&m);
3b5514ed82 2007-09-22       drh:     return 0;
3b5514ed82 2007-09-22       drh:   }
dbda8d6ce9 2007-07-21       drh:   db_begin_transaction();
3b5514ed82 2007-09-22       drh:   if( m.type==CFTYPE_MANIFEST ){
3b5514ed82 2007-09-22       drh:     if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d", rid) ){
3b5514ed82 2007-09-22       drh:       for(i=0; i<m.nParent; i++){
3b5514ed82 2007-09-22       drh:         int pid = uuid_to_rid(m.azParent[i], 1);
3b5514ed82 2007-09-22       drh:         db_multi_exec("INSERT OR IGNORE INTO plink(pid, cid, isprim, mtime)"
3b5514ed82 2007-09-22       drh:                       "VALUES(%d, %d, %d, %.17g)", pid, rid, i==0, m.rDate);
3b5514ed82 2007-09-22       drh:         if( i==0 ){
3b5514ed82 2007-09-22       drh:           add_mlink(pid, 0, rid, &m);
913608a5a6 2007-09-25       drh:           parentid = pid;
3b5514ed82 2007-09-22       drh:         }
3b5514ed82 2007-09-22       drh:       }
3b5514ed82 2007-09-22       drh:       db_prepare(&q, "SELECT cid FROM plink WHERE pid=%d AND isprim", rid);
3b5514ed82 2007-09-22       drh:       while( db_step(&q)==SQLITE_ROW ){
3b5514ed82 2007-09-22       drh:         int cid = db_column_int(&q, 0);
3b5514ed82 2007-09-22       drh:         add_mlink(rid, &m, cid, 0);
3b5514ed82 2007-09-22       drh:       }
3b5514ed82 2007-09-22       drh:       db_finalize(&q);
3b5514ed82 2007-09-22       drh:       db_multi_exec(
6af8fdc230 2007-12-04       drh:         "REPLACE INTO event(type,mtime,objid,user,comment,"
ce7900a0b6 2007-09-25       drh:         "                  bgcolor,brbgcolor,euser,ecomment)"
ce7900a0b6 2007-09-25       drh:         "VALUES('ci',%.17g,%d,%Q,%Q,"
ce7900a0b6 2007-09-25       drh:         " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d AND tagtype=1),"
ce7900a0b6 2007-09-25       drh:         "(SELECT value FROM tagxref WHERE tagid=%d AND rid=%d AND tagtype!=1),"
ce7900a0b6 2007-09-25       drh:         "  (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d),"
ce7900a0b6 2007-09-25       drh:         "  (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d));",
ce7900a0b6 2007-09-25       drh:         m.rDate, rid, m.zUser, m.zComment,
ce7900a0b6 2007-09-25       drh:         TAG_BGCOLOR, rid,
ce7900a0b6 2007-09-25       drh:         TAG_BGCOLOR, rid,
ce7900a0b6 2007-09-25       drh:         TAG_USER, rid,
ce7900a0b6 2007-09-25       drh:         TAG_COMMENT, rid
3b5514ed82 2007-09-22       drh:       );
3b5514ed82 2007-09-22       drh:     }
3b5514ed82 2007-09-22       drh:   }
3b5514ed82 2007-09-22       drh:   if( m.type==CFTYPE_CLUSTER ){
a48474bc75 2008-05-29       drh:     tag_insert("cluster", 1, 0, rid, m.rDate, rid);
3b5514ed82 2007-09-22       drh:     for(i=0; i<m.nCChild; i++){
3b5514ed82 2007-09-22       drh:       int mid;
3b5514ed82 2007-09-22       drh:       mid = uuid_to_rid(m.azCChild[i], 1);
3b5514ed82 2007-09-22       drh:       if( mid>0 ){
3b5514ed82 2007-09-22       drh:         db_multi_exec("DELETE FROM unclustered WHERE rid=%d", mid);
3b5514ed82 2007-09-22       drh:       }
3b5514ed82 2007-09-22       drh:     }
3b5514ed82 2007-09-22       drh:   }
3b5514ed82 2007-09-22       drh:   if( m.type==CFTYPE_CONTROL || m.type==CFTYPE_MANIFEST ){
3b5514ed82 2007-09-22       drh:     for(i=0; i<m.nTag; i++){
3b5514ed82 2007-09-22       drh:       int tid;
09c4adeb6f 2007-09-22       drh:       int type;
0afb5e8e39 2008-03-08       drh:       if( m.aTag[i].zUuid ){
0afb5e8e39 2008-03-08       drh:         tid = uuid_to_rid(m.aTag[i].zUuid, 1);
0afb5e8e39 2008-03-08       drh:       }else{
0afb5e8e39 2008-03-08       drh:         tid = rid;
913608a5a6 2007-09-25       drh:       }
a48474bc75 2008-05-29       drh:       if( tid ){
a48474bc75 2008-05-29       drh:         switch( m.aTag[i].zName[0] ){
a48474bc75 2008-05-29       drh:           case '+':  type = 1; break;
a48474bc75 2008-05-29       drh:           case '*':  type = 2; break;
a48474bc75 2008-05-29       drh:           case '-':  type = 0; break;
a48474bc75 2008-05-29       drh:           default:
a48474bc75 2008-05-29       drh:             fossil_fatal("unknown tag type in manifest: %s", m.aTag);
a48474bc75 2008-05-29       drh:             return 0;
a48474bc75 2008-05-29       drh:         }
a48474bc75 2008-05-29       drh:         tag_insert(&m.aTag[i].zName[1], type, m.aTag[i].zValue,
a48474bc75 2008-05-29       drh:                    rid, m.rDate, tid);
ba486fec5a 2007-09-03       drh:       }
ba486fec5a 2007-09-03       drh:     }
913608a5a6 2007-09-25       drh:     if( parentid ){
913608a5a6 2007-09-25       drh:       tag_propagate_all(parentid);
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
2ab2db0bd3 2007-10-05       drh:   if( m.type==CFTYPE_WIKI ){
2ab2db0bd3 2007-10-05       drh:     char *zTag = mprintf("wiki-%s", m.zWikiTitle);
2ab2db0bd3 2007-10-05       drh:     int tagid = tag_findid(zTag, 1);
2ab2db0bd3 2007-10-05       drh:     int prior;
6d58613757 2007-10-06       drh:     char *zComment;
2ab2db0bd3 2007-10-05       drh:     tag_insert(zTag, 1, 0, rid, m.rDate, rid);
2ab2db0bd3 2007-10-05       drh:     free(zTag);
70d5cc86b7 2007-10-05       drh:     prior = db_int(0,
70d5cc86b7 2007-10-05       drh:       "SELECT rid FROM tagxref"
70d5cc86b7 2007-10-05       drh:       " WHERE tagid=%d AND mtime<%.17g"
70d5cc86b7 2007-10-05       drh:       " ORDER BY mtime DESC",
70d5cc86b7 2007-10-05       drh:       tagid, m.rDate
70d5cc86b7 2007-10-05       drh:     );
2ab2db0bd3 2007-10-05       drh:     if( prior ){
2ab2db0bd3 2007-10-05       drh:       content_deltify(prior, rid, 0);
ba486fec5a 2007-09-03       drh:     }
6d58613757 2007-10-06       drh:     zComment = mprintf("Changes to wiki page [%h]", m.zWikiTitle);
ba486fec5a 2007-09-03       drh:     db_multi_exec(
6af8fdc230 2007-12-04       drh:       "REPLACE INTO event(type,mtime,objid,user,comment,"
6d58613757 2007-10-06       drh:       "                  bgcolor,brbgcolor,euser,ecomment)"
6d58613757 2007-10-06       drh:       "VALUES('w',%.17g,%d,%Q,%Q,"
a48474bc75 2008-05-29       drh:       "  (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d AND tagtype=1),"
a48474bc75 2008-05-29       drh:       "  (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d AND tagtype!=1),"
6d58613757 2007-10-06       drh:       "  (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d),"
6d58613757 2007-10-06       drh:       "  (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d));",
6d58613757 2007-10-06       drh:       m.rDate, rid, m.zUser, zComment,
6d58613757 2007-10-06       drh:       TAG_BGCOLOR, rid,
6d58613757 2007-10-06       drh:       TAG_BGCOLOR, rid,
6d58613757 2007-10-06       drh:       TAG_USER, rid,
6d58613757 2007-10-06       drh:       TAG_COMMENT, rid
ba486fec5a 2007-09-03       drh:     );
6d58613757 2007-10-06       drh:     free(zComment);
dbda8d6ce9 2007-07-21       drh:   }
fb358ca492 2007-11-24       drh:   if( m.type==CFTYPE_TICKET ){
f0c8693845 2008-10-20       drh:     int i;
f0c8693845 2008-10-20       drh:     char *zTitle;
fb358ca492 2007-11-24       drh:     char *zTag;
b3ee50c946 2008-07-15       drh:     Blob comment;
f0c8693845 2008-10-20       drh:     char *zNewStatus = 0;
f0c8693845 2008-10-20       drh:     static char *zTitleExpr = 0;
f0c8693845 2008-10-20       drh:     static char *zStatusColumn = 0;
f0c8693845 2008-10-20       drh:     static int once = 1;
f0c8693845 2008-10-20       drh:     int isNew;
fb358ca492 2007-11-24       drh: 
f0c8693845 2008-10-20       drh:     isNew = ticket_insert(&m, 1, 1);
fb358ca492 2007-11-24       drh:     zTag = mprintf("tkt-%s", m.zTicketUuid);
fb358ca492 2007-11-24       drh:     tag_insert(zTag, 1, 0, rid, m.rDate, rid);
fb358ca492 2007-11-24       drh:     free(zTag);
b3ee50c946 2008-07-15       drh:     blob_zero(&comment);
f0c8693845 2008-10-20       drh: #if 0
b3ee50c946 2008-07-15       drh:     if( m.nField==1 ){
b3ee50c946 2008-07-15       drh:       if( m.aField[0].zName[0]=='+' ){
b3ee50c946 2008-07-15       drh:         blob_appendf(&comment,
b3ee50c946 2008-07-15       drh:           "Appended to %h in ticket [%.10s]",
b3ee50c946 2008-07-15       drh:           &m.aField[0].zName[1], m.zTicketUuid
b3ee50c946 2008-07-15       drh:         );
b3ee50c946 2008-07-15       drh:       }else if( strlen(m.aField[0].zValue)<40 ){
b3ee50c946 2008-07-15       drh:         blob_appendf(&comment,
b3ee50c946 2008-07-15       drh:           "Changed %h to \"%h\" in ticket [%.10s]",
b3ee50c946 2008-07-15       drh:           m.aField[0].zName, m.aField[0].zValue, m.zTicketUuid
b3ee50c946 2008-07-15       drh:         );
b3ee50c946 2008-07-15       drh:       }else{
b3ee50c946 2008-07-15       drh:         blob_appendf(&comment,
b3ee50c946 2008-07-15       drh:           "Changed %h in ticket [%.10s]",
b3ee50c946 2008-07-15       drh:           m.aField[0].zName, m.zTicketUuid
b3ee50c946 2008-07-15       drh:         );
b3ee50c946 2008-07-15       drh:       }
b3ee50c946 2008-07-15       drh:     }else{
ac3f1f2ba7 2008-10-18       drh:       int i;
b3ee50c946 2008-07-15       drh:       const char *z;
b3ee50c946 2008-07-15       drh:       const char *zSep = " ";
b3ee50c946 2008-07-15       drh:       blob_appendf(&comment, "%d changes to ticket [%.10s]:",
b3ee50c946 2008-07-15       drh:                             m.nField, m.zTicketUuid);
b3ee50c946 2008-07-15       drh:       for(i=0; i<m.nField; i++){
b3ee50c946 2008-07-15       drh:         z = m.aField[i].zName;
b3ee50c946 2008-07-15       drh:         if( z[0]=='+' ) z++;
b3ee50c946 2008-07-15       drh:         blob_appendf(&comment, "%s%h", zSep, z);
b3ee50c946 2008-07-15       drh:         zSep = ", ";
b3ee50c946 2008-07-15       drh:       }
f0c8693845 2008-10-20       drh:       int i;
f0c8693845 2008-10-20       drh:       const char *zStatus = 0;
f0c8693845 2008-10-20       drh:       const char *zTitle;
f0c8693845 2008-10-20       drh:       for(i=0; i<m.nField; i++){
f0c8693845 2008-10-20       drh:         z = m.aField[i].zName;
f0c8693845 2008-10-20       drh:         if( strcmp(z, "status") ) zStatus = m.aField[i].zValue;
18b1f6788d 2007-08-28       drh:       }
f0c8693845 2008-10-20       drh:       if( zField
ac3f1f2ba7 2008-10-18       drh:       blob_appendf(&comment, "Edits to ticket [%.10s]", m.zTicketUuid);
ac3f1f2ba7 2008-10-18       drh:     }
f0c8693845 2008-10-20       drh: #endif
f0c8693845 2008-10-20       drh:     if( once ){
f0c8693845 2008-10-20       drh:       once = 0;
f0c8693845 2008-10-20       drh:       zTitleExpr = db_get("ticket-title-expr", "title");
f0c8693845 2008-10-20       drh:       zStatusColumn = db_get("ticket-status-column", "status");
18b1f6788d 2007-08-28       drh:     }
f0c8693845 2008-10-20       drh:     zTitle = db_text("unknown",
f0c8693845 2008-10-20       drh:       "SELECT %s FROM ticket WHERE tkt_uuid='%s'",
f0c8693845 2008-10-20       drh:       zTitleExpr, m.zTicketUuid
f0c8693845 2008-10-20       drh:     );
f0c8693845 2008-10-20       drh:     if( !isNew ){
f0c8693845 2008-10-20       drh:       for(i=0; i<m.nField; i++){
f0c8693845 2008-10-20       drh:         if( strcmp(m.aField[i].zName, zStatusColumn)==0 ){
f0c8693845 2008-10-20       drh:           zNewStatus = m.aField[i].zValue;
f0c8693845 2008-10-20       drh:         }
f0c8693845 2008-10-20       drh:       }
f0c8693845 2008-10-20       drh:       if( zNewStatus ){
f0c8693845 2008-10-20       drh:         blob_appendf(&comment, "%h ticket [%.10s]: <i>%h</i>",
f0c8693845 2008-10-20       drh:            zNewStatus, m.zTicketUuid, zTitle
f0c8693845 2008-10-20       drh:         );
f0c8693845 2008-10-20       drh:         if( m.nField>1 ){
f0c8693845 2008-10-20       drh:           blob_appendf(&comment, " plus %d other change%s",
f0c8693845 2008-10-20       drh:             m.nField-1, m.nField==2 ? "" : "s");
f0c8693845 2008-10-20       drh:         }
f0c8693845 2008-10-20       drh:       }else{
f0c8693845 2008-10-20       drh:         zNewStatus = db_text("unknown",
f0c8693845 2008-10-20       drh:            "SELECT %s FROM ticket WHERE tkt_uuid='%s'",
f0c8693845 2008-10-20       drh:            zStatusColumn, m.zTicketUuid
f0c8693845 2008-10-20       drh:         );
f0c8693845 2008-10-20       drh:         blob_appendf(&comment, "Ticket [%.10s] <i>%h</i> status still %h with "
f0c8693845 2008-10-20       drh:              "%d other change%s",
f0c8693845 2008-10-20       drh:              m.zTicketUuid, zTitle, zNewStatus, m.nField,
f0c8693845 2008-10-20       drh:              m.nField==1 ? "" : "s"
f0c8693845 2008-10-20       drh:         );
f0c8693845 2008-10-20       drh:         free(zNewStatus);
09c4adeb6f 2007-09-22       drh:       }
f0c8693845 2008-10-20       drh:     }else{
f0c8693845 2008-10-20       drh:       blob_appendf(&comment, "New ticket [%.10s] <i>%h</i>.",
f0c8693845 2008-10-20       drh:         m.zTicketUuid, zTitle
f0c8693845 2008-10-20       drh:       );
18b1f6788d 2007-08-28       drh:     }
f0c8693845 2008-10-20       drh:     free(zTitle);
18b1f6788d 2007-08-28       drh:     db_multi_exec(
6af8fdc230 2007-12-04       drh:       "REPLACE INTO event(type,mtime,objid,user,comment)"
fb358ca492 2007-11-24       drh:       "VALUES('t',%.17g,%d,%Q,%Q)",
b3ee50c946 2008-07-15       drh:       m.rDate, rid, m.zUser, blob_str(&comment)
18b1f6788d 2007-08-28       drh:     );
b3ee50c946 2008-07-15       drh:     blob_reset(&comment);
18b1f6788d 2007-08-28       drh:   }
dbda8d6ce9 2007-07-21       drh:   db_end_transaction(0);
dbda8d6ce9 2007-07-21       drh:   manifest_clear(&m);
dbda8d6ce9 2007-07-21       drh:   return 1;
dbda8d6ce9 2007-07-21       drh: }