Index: src/report.c ================================================================== --- src/report.c +++ src/report.c @@ -145,11 +145,11 @@ ** This is the SQLite authorizer callback used to make sure that the ** SQL statements entered by users do not try to do anything untoward. ** If anything suspicious is tried, set *(char**)pError to an error ** message obtained from malloc. */ -static int report_query_authorizer( +int report_query_authorizer( void *pError, int code, const char *zArg1, const char *zArg2, const char *zArg3, @@ -942,5 +942,137 @@ sqlite3_exec(g.db, zSql, output_tab_separated, &count, &zErr2); sqlite3_set_authorizer(g.db, 0, 0); cgi_set_content_type("text/plain"); } } + +/* +** user defined separator used by ticket show command +*/ +static const char *zSep = 0; + +/* +** select the quoting algorithm for "ticket show" +*/ +#if INTERFACE +typedef enum eTktShowEnc { tktNoTab=0, tktFossilize=1 } tTktShowEncoding; +#endif +static tTktShowEncoding tktEncode = tktNoTab; + +/* +** Output the text given in the argument. Convert tabs and newlines into +** spaces. +*/ +static void output_no_tabs_file(const char *z){ + switch( tktEncode ){ + case tktFossilize: + { char *zFosZ; + + if( z && *z ){ + zFosZ = fossilize(z,-1); + printf("%s",zFosZ); + free(zFosZ); + } + break; + } + default: + while( z && z[0] ){ + int i, j; + for(i=0; z[i] && (!isspace(z[i]) || z[i]==' '); i++){} + if( i>0 ){ + printf("%.*s", i, z); + } + for(j=i; isspace(z[j]); j++){} + if( j>i ){ + printf("%*s", j-i, ""); + } + z += j; + } + break; + } +} + +/* +** Output a row as a tab-separated line of text. +*/ +int output_separated_file( + void *pUser, /* Pointer to row-count integer */ + int nArg, /* Number of columns in this result row */ + char **azArg, /* Text of data in all columns */ + char **azName /* Names of the columns */ +){ + int *pCount = (int*)pUser; + int i; + + if( *pCount==0 ){ + for(i=0; i } + +/* +** COMMAND: ticket +** Usage: %fossil ticket SUBCOMMAND ... +** +** Run various subcommands to control tickets +** +** %fossil ticket show (REPORTTITLE|REPORTNR) ?TICKETFILTER? ?options? +** +** options can be: +** ?-l|--limit LIMITCHAR? +** ?-q|--quote? +** +** Run the ticket report, identified by the report format title +** used in the gui. The data is written as flat file on stdout, +** using "," as separator. The seperator "," can be changed using +** the -l or --limit option. +** If TICKETFILTER is given on the commandline, the query is +** limited with a new WHERE-condition. +** example: Report lists a column # with the uuid +** TICKETFILTER may be [#]='uuuuuuuuu' +** example: Report only lists rows with status not open +** TICKETFILTER: status != 'open' +** If the option -q|--quote is used, the tickets are encoded by +** quoting special chars(space -> \\s, tab -> \\t, newline -> \\n, +** cr -> \\r, formfeed -> \\f, vtab -> \\v, nul -> \\0, \\ -> \\\\). +** Otherwise, the simplified encoding as on the show report raw +** page in the gui is used. +** +** Instead of the report title its possible to use the report +** number. Using the special report number 0 list all columns, +** defined in the ticket table. +** +** %fossil ticket fieldlist +** +** list all fields, defined for ticket in the fossil repository +** +** %fossil ticket set TICKETUUID FIELD VALUE ?FIELD VALUE .. ? ?-q|--quote? +** %fossil ticket change TICKETUUID FIELD VALUE ?FIELD VALUE .. ? ?-q|--quote? +** +** change ticket identified by TICKETUUID and set the value of +** field FIELD to VALUE. Valid field descriptions are: +** status, type, severity, priority, resolution, +** foundin, private_contact, resolution, title or comment +** Field names given above are the ones, defined in a standard +** fossil environment. If you have added, deleted columns, you +** change the all your configured columns. +** You can use more than one field/value pair on the commandline. +** Using -q|--quote enables the special character decoding as +** in "ticket show". So it's possible, to set multiline text or +** text with special characters. +** +** %fossil ticket add FIELD VALUE ?FIELD VALUE .. ? ?-q|--quote? +** +** like set, but create a new ticket with the given values. +** +** The values in set|add are not validated against the definitions +** given in "Ticket Common Script". +*/ +void ticket_cmd(void){ + int n; + + /* do some ints, we want to be inside a checkout */ + db_must_be_within_tree(); + db_find_and_open_repository(1); + user_select(); + /* + ** Check that the user exists. + */ + if( !db_exists("SELECT 1 FROM user WHERE login=%Q", g.zLogin) ){ + fossil_fatal("no such user: %s", g.zLogin); + } + + if( g.argc<3 ){ + usage("add|fieldlist|set|show"); + }else{ + n = strlen(g.argv[2]); + if( n==1 && g.argv[2][0]=='s' ){ + /* set/show cannot be distinguished, so show the usage */ + usage("add|fieldlist|set|show"); + }else if( strncmp(g.argv[2],"fieldlist",n)==0 ){ + /* simply show all field names */ + int i; + + /* read all available ticket fields */ + getAllTicketFields(); + for(i=0; i4 ){ + zFilterUuid = g.argv[4]; + } + + rptshow( zRep, zSep, zFilterUuid, tktEncoding ); + + } + }else{ + /* add a new ticket or update an existing ticket */ + enum { set,add,err } eCmd = err; + int i; + int rid; + const char *zTktUuid; + Blob tktchng, cksum; + + /* get command type (set/add) and get uuid, if needed for set */ + if( strncmp(g.argv[2],"set",n)==0 || strncmp(g.argv[2],"change",n)==0 ){ + eCmd = set; + if( g.argc==3 ){ + usage("set TICKETUUID"); + } + zTktUuid = db_text(0, + "SELECT tkt_uuid FROM ticket WHERE tkt_uuid GLOB '%s*'", g.argv[3] + ); + if( !zTktUuid ){ + fossil_fatal("unknown ticket: '%s'!",g.argv[3]); + } + i=4; + }else if( strncmp(g.argv[2],"add",n)==0 ){ + eCmd = add; + i = 3; + zTktUuid = db_text(0, "SELECT lower(hex(randomblob(20)))"); + } + /* none of set/add, so show the usage! */ + if( eCmd==err ){ + usage("add|fieldlist|set|show"); + } + + /* read all given ticket field/value pairs from command line */ + if( i==g.argc ){ + fossil_fatal("empty %s command aborted!",g.argv[2]); + } + getAllTicketFields(); + /* read commandline and assign fields in the azValue array */ + while( i $@ + +echo add allrepo attach bag blob branch browse captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode event file finfo graph http http_socket http_ssl http_transport info login main manifest md5 merge merge3 name pivot popen pqueue printf rebuild report rss schema search setup sha1 shun skins stat style sync tag th_main timeline tkt tktsetup undo update url user verify vfile wiki wikiformat winhttp xfer zip sqlite3 th th_lang > $@ +echo fossil >> $@ +echo fossil >> $@ +echo $(LIBS) >> $@ @@ -217,10 +217,16 @@ $(OBJDIR)\doc$O : doc_.c doc.h $(TCC) -o$@ -c doc_.c doc_.c : $(SRCDIR)\doc.c +translate$E $** > $@ + +$(OBJDIR)\event$O : event_.c event.h + $(TCC) -o$@ -c event_.c + +event_.c : $(SRCDIR)\event.c + +translate$E $** > $@ $(OBJDIR)\encode$O : encode_.c encode.h $(TCC) -o$@ -c encode_.c encode_.c : $(SRCDIR)\encode.c @@ -507,7 +513,7 @@ zip_.c : $(SRCDIR)\zip.c +translate$E $** > $@ headers: makeheaders$E page_index.h VERSION.h - +makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h file_.c:file.h finfo_.c:finfo.h graph_.c:graph.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h name_.c:name.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h skins_.c:skins.h stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h + +makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h file_.c:file.h finfo_.c:finfo.h graph_.c:graph.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h name_.c:name.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h skins_.c:skins.h stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h @copy /Y nul: headers