Esempio n. 1
0
/*
** The pTkt object is a ticket change artifact.  Output a detailed
** description of this object.
*/
void ticket_output_change_artifact(Manifest *pTkt, const char *zListType){
  int i;
  int wikiFlags = WIKI_NOBADLINKS;
  const char *zBlock = "<blockquote>";
  const char *zEnd = "</blockquote>";
  if( P("plaintext")!=0 ){
    wikiFlags |= WIKI_LINKSONLY;
    zBlock = "<blockquote><pre class='verbatim'>";
    zEnd = "</pre></blockquote>";
  }
  if( zListType==0 ) zListType = "1";
  cgi_printf("<ol type=\"%s\">\n",(zListType));
  for(i=0; i<pTkt->nField; i++){
    Blob val;
    const char *z;
    z = pTkt->aField[i].zName;
    blob_set(&val, pTkt->aField[i].zValue);
    if( z[0]=='+' ){
      cgi_printf("<li>Appended to %h:%s\n",(&z[1]),(zBlock));
      wiki_convert(&val, 0, wikiFlags);
      cgi_printf("%s</li>\n",(zEnd));
    }else if( blob_size(&val)>50 || contains_newline(&val) ){
      cgi_printf("<li>Change %h to:%s\n",(z),(zBlock));
      wiki_convert(&val, 0, wikiFlags);
      cgi_printf("%s</li>\n",(zEnd));
    }else{
      cgi_printf("<li>Change %h to \"%h\"</li>\n",(z),(blob_str(&val)));
    }
    blob_reset(&val);
  }
  cgi_printf("</ol>\n");
}
Esempio n. 2
0
File: file.c Progetto: oopos/fossil
/*
** Create symlink to file on Unix, or plain-text file with
** symlink target if "allow-symlinks" is off or we're on Windows.
**
** Arguments: target file (symlink will point to it), link file
**/
void symlink_create(const char *zTargetFile, const char *zLinkFile) {
#if !defined(_WIN32)
    if( g.allowSymlinks ) {
        int i, nName;
        char *zName, zBuf[1000];

        nName = strlen(zLinkFile);
        if( nName>=sizeof(zBuf) ) {
            zName = mprintf("%s", zLinkFile);
        } else {
            zName = zBuf;
            memcpy(zName, zLinkFile, nName+1);
        }
        nName = file_simplify_name(zName, nName);
        for(i=1; i<nName; i++) {
            if( zName[i]=='/' ) {
                zName[i] = 0;
                if( file_mkdir(zName, 1) ) {
                    fossil_fatal_recursive("unable to create directory %s", zName);
                    return;
                }
                zName[i] = '/';
            }
        }
        if( zName!=zBuf ) free(zName);

        if( symlink(zTargetFile, zName)!=0 ) {
            fossil_fatal_recursive("unable to create symlink \"%s\"", zName);
        }
    } else
#endif
    {
        Blob content;
        blob_set(&content, zTargetFile);
        blob_write_to_file(&content, zLinkFile);
        blob_reset(&content);
    }
}
/*
** Impl of /json/artifact. This basically just determines the type of
** an artifact and forwards the real work to another function.
*/
cson_value * json_page_artifact(){
  cson_object * pay = NULL;
  char const * zName = NULL;
  char const * zType = NULL;
  char const * zUuid = NULL;
  cson_value * entry = NULL;
  Blob uuid = empty_blob;
  int rc;
  int rid = 0;
  ArtifactDispatchEntry const * dispatcher = &ArtifactDispatchList[0];
  zName = json_find_option_cstr2("name", NULL, NULL, g.json.dispatchDepth+1);
  if(!zName || !*zName) {
    json_set_err(FSL_JSON_E_MISSING_ARGS,
                 "Missing 'name' argument.");
    return NULL;
  }

  if( validate16(zName, strlen(zName)) ){
    if( db_exists("SELECT 1 FROM ticket WHERE tkt_uuid GLOB '%q*'", zName) ){
      zType = "ticket";
      goto handle_entry;
    }
    if( db_exists("SELECT 1 FROM tag WHERE tagname GLOB 'event-%q*'", zName) ){
      zType = "tag";
      goto handle_entry;
    }
  }
  blob_set(&uuid,zName);
  rc = name_to_uuid(&uuid,-1,"*");
  /* FIXME: check for a filename if all else fails. */
  if(1==rc){
    g.json.resultCode = FSL_JSON_E_RESOURCE_NOT_FOUND;
    goto error;
  }else if(2==rc){
    g.json.resultCode = FSL_JSON_E_AMBIGUOUS_UUID;
    goto error;
  }
  zUuid = blob_str(&uuid);
  rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", zUuid);
  if(0==rid){
    g.json.resultCode = FSL_JSON_E_RESOURCE_NOT_FOUND;
    goto error;
  }

  if( db_exists("SELECT 1 FROM mlink WHERE mid=%d", rid)
      || db_exists("SELECT 1 FROM plink WHERE cid=%d", rid)
      || db_exists("SELECT 1 FROM plink WHERE pid=%d", rid)){
    zType = "checkin";
    goto handle_entry;
  }else if( db_exists("SELECT 1 FROM tagxref JOIN tag USING(tagid)"
                      " WHERE rid=%d AND tagname LIKE 'wiki-%%'", rid) ){
    zType = "wiki";
    goto handle_entry;
  }else if( db_exists("SELECT 1 FROM tagxref JOIN tag USING(tagid)"
                      " WHERE rid=%d AND tagname LIKE 'tkt-%%'", rid) ){
    zType = "ticket";
    goto handle_entry;
  }else if ( db_exists("SELECT 1 FROM mlink WHERE fid = %d", rid) ){
    zType = "file";
    goto handle_entry;
  }else{
    g.json.resultCode = FSL_JSON_E_RESOURCE_NOT_FOUND;
    goto error;
  }

  error:
  assert( 0 != g.json.resultCode );
  goto veryend;

  handle_entry:
  pay = cson_new_object();
  assert( (NULL != zType) && "Internal dispatching error." );
  for( ; dispatcher->name; ++dispatcher ){
    if(0!=strcmp(dispatcher->name, zType)){
      continue;
    }else{
      entry = (*dispatcher->func)(pay, rid);
      break;
    }
  }
  if(!g.json.resultCode){
    assert( NULL != entry );
    assert( NULL != zType );
    cson_object_set( pay, "type", json_new_string(zType) );
    cson_object_set( pay, "uuid", json_new_string(zUuid) );
    /*cson_object_set( pay, "name", json_new_string(zName ? zName : zUuid) );*/
    /*cson_object_set( pay, "rid", cson_value_new_integer(rid) );*/
    if(cson_value_is_object(entry) && (cson_value_get_object(entry) != pay)){
      cson_object_set(pay, "artifact", entry);
    }
  }
  veryend:
  blob_reset(&uuid);
  if(g.json.resultCode && pay){
    cson_free_object(pay);
    pay = NULL;
  }
  return cson_object_value(pay);
}
Esempio n. 4
0
/*
** 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?
**       ?-R|--repository FILE?
**
**     Run the ticket report, identified by the report format title
**     used in the gui. The data is written as flat file on stdout,
**     using TAB as separator. The separator 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. This has no effect in JSON mode.
**
**     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 list fields
**
**     list all fields, defined for ticket in the fossil repository
**
**   %fossil ticket list reports
**
**     list all ticket reports, defined in the fossil repository
**
**   %fossil ticket set TICKETUUID (FIELD VALUE)+ ?-q|--quote?
**   %fossil ticket change TICKETUUID (FIELD VALUE)+ ?-q|--quote?
**
**     change ticket identified by TICKETUUID and set the value of
**     field FIELD to VALUE.
**
**     Field names as defined in the TICKET table.  By default, these
**     names include: type, status, subsystem, priority, severity, foundin,
**     resolution, title, and comment, but other field names can be added
**     or substituted in customized installations.
**
**     If you use +FIELD, the VALUE Is appended to the field FIELD.
**     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.
**
**   %fossil ticket history TICKETUUID
**
**     Show the complete change history for the ticket
**
** The values in set|add are not validated against the definitions
** given in "Ticket Common Script".
*/
void ticket_cmd(void){
  int n;
  const char *zUser;
  const char *zDate;
  const char *zTktUuid;

  /* do some ints, we want to be inside a checkout */
  db_find_and_open_repository(0, 0);
  user_select();

  zUser = find_option("user-override",0,1);
  if( zUser==0 ) zUser = g.zLogin;
  zDate = find_option("date-override",0,1);
  if( zDate==0 ) zDate = "now";
  zDate = date_in_standard_format(zDate);
  zTktUuid = find_option("uuid-override",0,1);
  if( zTktUuid && (strlen(zTktUuid)!=40 || !validate16(zTktUuid,40)) ){
    fossil_fatal("invalid --uuid-override: must be 40 characters of hex");
  }

  /*
  ** Check that the user exists.
  */
  if( !db_exists("SELECT 1 FROM user WHERE login=%Q", zUser) ){
    fossil_fatal("no such user: %s", zUser);
  }

  if( g.argc<3 ){
    usage("add|change|list|set|show|history");
  }
  n = strlen(g.argv[2]);
  if( n==1 && g.argv[2][0]=='s' ){
    /* set/show cannot be distinguished, so show the usage */
    usage("add|change|list|set|show|history");
  }
  if( strncmp(g.argv[2],"list",n)==0 ){
    if( g.argc==3 ){
      usage("list fields|reports");
    }else{
      n = strlen(g.argv[3]);
      if( !strncmp(g.argv[3],"fields",n) ){
        /* simply show all field names */
        int i;

        /* read all available ticket fields */
        getAllTicketFields();
        for(i=0; i<nField; i++){
          printf("%s\n",aField[i].zName);
        }
      }else if( !strncmp(g.argv[3],"reports",n) ){
        rpt_list_reports();
      }else{
        fossil_fatal("unknown ticket list option '%s'!",g.argv[3]);
      }
    }
  }else{
    /* add a new ticket or set fields on existing tickets */
    tTktShowEncoding tktEncoding;

    tktEncoding = find_option("quote","q",0) ? tktFossilize : tktNoTab;
    
    if( strncmp(g.argv[2],"show",n)==0 ){
      if( g.argc==3 ){
        usage("show REPORTNR");
      }else{
        const char *zRep = 0;
        const char *zSep = 0;
        const char *zFilterUuid = 0;
        zSep = find_option("limit","l",1);
        zRep = g.argv[3];
        if( !strcmp(zRep,"0") ){
          zRep = 0;
        }
        if( g.argc>4 ){
          zFilterUuid = g.argv[4];
        }
        rptshow( zRep, zSep, zFilterUuid, tktEncoding );
      }
    }else{
      /* add a new ticket or update an existing ticket */
      enum { set,add,history,err } eCmd = err;
      int i = 0;
      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 ||
         strncmp(g.argv[2],"history",n)==0 ){
        if( strncmp(g.argv[2],"history",n)==0 ){
          eCmd = history;
        }else{
          eCmd = set;
        }
        if( g.argc==3 ){
          usage("set|change|history 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;
        if( zTktUuid==0 ){
          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|history");
      }

      /* we just handle history separately here, does not get out */
      if( eCmd==history ){
        Stmt q;
        int tagid;

        if ( i != g.argc ){
          fossil_fatal("no other parameters expected to %s!",g.argv[2]);
        }
        tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'",
                       zTktUuid);
        if( tagid==0 ){
          fossil_fatal("no such ticket %h", zTktUuid);
        }  
        db_prepare(&q,
          "SELECT datetime(mtime%s), objid, uuid, NULL, NULL, NULL"
          "  FROM event, blob"
          " WHERE objid IN (SELECT rid FROM tagxref WHERE tagid=%d)"
          "   AND blob.rid=event.objid"
          " UNION "
          "SELECT datetime(mtime%s), attachid, uuid, src, "
          "       filename, user"
          "  FROM attachment, blob"
          " WHERE target=(SELECT substr(tagname,5) FROM tag WHERE tagid=%d)"
          "   AND blob.rid=attachid"
          " ORDER BY 1 DESC",
          timeline_utc(), tagid, timeline_utc(), tagid
        );
        while( db_step(&q)==SQLITE_ROW ){
          Manifest *pTicket;
          char zShort[12];
          const char *zDate = db_column_text(&q, 0);
          int rid = db_column_int(&q, 1);
          const char *zChngUuid = db_column_text(&q, 2);
          const char *zFile = db_column_text(&q, 4);
          memcpy(zShort, zChngUuid, 10);
          zShort[10] = 0;
          if( zFile!=0 ){
            const char *zSrc = db_column_text(&q, 3);
            const char *zUser = db_column_text(&q, 5);
            if( zSrc==0 || zSrc[0]==0 ){
              fossil_print("Delete attachment %s\n", zFile);
            }else{
              fossil_print("Add attachment %s\n", zFile);
            }
            fossil_print(" by %s on %s\n", zUser, zDate);
          }else{
            pTicket = manifest_get(rid, CFTYPE_TICKET, 0);
            if( pTicket ){
              int i;

              fossil_print("Ticket Change by %s on %s:\n",
                           pTicket->zUser, zDate);
              for(i=0; i<pTicket->nField; i++){
                Blob val;
                const char *z;
                z = pTicket->aField[i].zName;
                blob_set(&val, pTicket->aField[i].zValue);
                if( z[0]=='+' ){
                  fossil_print("  Append to ");
            z++;
          }else{
            fossil_print("  Change ");
          }
          fossil_print("%h: ",z);
          if( blob_size(&val)>50 || contains_newline(&val)) {
                  fossil_print("\n    ",blob_str(&val));
                  comment_print(blob_str(&val),4,79);
                }else{
                  fossil_print("%s\n",blob_str(&val));
                }
                blob_reset(&val);
              }
            }
            manifest_destroy(pTicket);
          }
        }
        db_finalize(&q);
        return;
      }
      /* 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 aField[].zValue array */
      while( i<g.argc ){
        char *zFName;
        char *zFValue;
        int j;
        int append = 0;

        zFName = g.argv[i++];
        if( i==g.argc ){
          fossil_fatal("missing value for '%s'!",zFName);
        }
        zFValue = g.argv[i++];
        if( tktEncoding == tktFossilize ){
          zFValue=mprintf("%s",zFValue);
          defossilize(zFValue);
        }
        append = (zFName[0] == '+');
        if (append){
          zFName++;
        }
        j = fieldId(zFName);
        if( j == -1 ){
          fossil_fatal("unknown field name '%s'!",zFName);
        }else{
          if (append) {
            aField[j].zAppend = zFValue;
          } else {
            aField[j].zValue = zFValue;
          }
        }
      }

      /* now add the needed artifacts to the repository */
      blob_zero(&tktchng);
      /* add the time to the ticket manifest */
      blob_appendf(&tktchng, "D %s\n", zDate);
      /* append defined elements */
      for(i=0; i<nField; i++){
        char *zValue = 0;
        char *zPfx;

        if (aField[i].zAppend && aField[i].zAppend[0] ){
          zPfx = " +";
          zValue = aField[i].zAppend;
        } else if( aField[i].zValue && aField[i].zValue[0] ){
          zPfx = " ";
          zValue = aField[i].zValue;
        } else {
          continue;
        }
        if( memcmp(aField[i].zName, "private_", 8)==0 ){
          zValue = db_conceal(zValue, strlen(zValue));
          blob_appendf(&tktchng, "J%s%s %s\n", zPfx, aField[i].zName, zValue);
        }else{
          blob_appendf(&tktchng, "J%s%s %#F\n", zPfx,
                       aField[i].zName, strlen(zValue), zValue);
        }
      }
      blob_appendf(&tktchng, "K %s\n", zTktUuid);
      blob_appendf(&tktchng, "U %F\n", zUser);
      md5sum_blob(&tktchng, &cksum);
      blob_appendf(&tktchng, "Z %b\n", &cksum);
      if( ticket_put(&tktchng, zTktUuid, 0) ){
        fossil_fatal("%s\n", g.zErrMsg);
      }else{
        fossil_print("ticket %s succeeded for %s\n",
             (eCmd==set?"set":"add"),zTktUuid);
      }
    }
  }
}