Fossil SCM

Internal API refactoring to allow for recording the mimetype of attachments.

stephan 2026-06-02 15:56 UTC attach-v2
Commit 639e2cf0b7c68618a71895d091a6d4b4c1ac210b684b3ef228af87f6e6c24bf1
+17 -1
--- src/attach.c
+++ src/attach.c
@@ -346,10 +346,11 @@
346346
void attach_commit(
347347
const char *zName, /* The filename of the attachment */
348348
const char *zTarget, /* The artifact hash to attach to */
349349
const char *aContent, /* The content of the attachment */
350350
int szContent, /* The length of the attachment */
351
+ const char *zMimetype, /* Content mimetype or NULL */
351352
int needModerator, /* Moderate the attachment? */
352353
const char *zComment /* The comment for the attachment */
353354
){
354355
Blob content;
355356
Blob manifest;
@@ -386,10 +387,13 @@
386387
if( n>0 ){
387388
blob_appendf(&manifest, "C %#F\n", n, zComment);
388389
}
389390
zDate = date_in_standard_format("now");
390391
blob_appendf(&manifest, "D %s\n", zDate);
392
+ if( zMimetype && 0!=zMimetype[0] ){
393
+ blob_appendf(&manifest, "N %F\n", zMimetype);
394
+ }
391395
blob_appendf(&manifest, "U %F\n", login_name());
392396
md5sum_blob(&manifest, &cksum);
393397
blob_appendf(&manifest, "Z %b\n", &cksum);
394398
attach_put(&manifest, rid, needModerator);
395399
assert( blob_is_reset(&manifest) );
@@ -414,10 +418,11 @@
414418
const char *zTechNote = P("technote");
415419
const char *zFrom = P("from");
416420
const char *aContent = P("f");
417421
const char *zName = PD("f:filename","unknown");
418422
const char *zComment = PD("comment", "");
423
+ const char *zMimetype = P("mimetype");
419424
const char *zTarget;
420425
char * zTo = 0;
421426
char *zTargetType = 0;
422427
char *zExtraFree = 0;
423428
int szContent = atoi(PD("f:bytes","0"));
@@ -501,11 +506,12 @@
501506
/* Fall through and render form. */
502507
}else if( P("ok") && szContent>0 && (goodCaptcha = captcha_is_correct(0)) ){
503508
int needModerator = (zForumPost!=0 && forum_need_moderation()) ||
504509
(zTkt!=0 && ticket_need_moderation(0)) ||
505510
(zPage!=0 && wiki_need_moderation(0));
506
- attach_commit(zName, zTarget, aContent, szContent, needModerator, zComment);
511
+ attach_commit(zName, zTarget, aContent, szContent, zMimetype,
512
+ needModerator, zComment);
507513
cgi_redirect(zTo ? zTo : zFrom);
508514
}
509515
510516
style_set_current_feature("attach");
511517
style_header("Add Attachment");
@@ -891,10 +897,12 @@
891897
** is to be made. The attachment will be
892898
** to the most recently modified tech note
893899
** with the specified timestamp.
894900
** -t|--technote TECHNOTE-ID Specifies the technote to be
895901
** updated by its technote id
902
+** --mimetype TYPE Optional mimetype of the attached
903
+** content
896904
**
897905
** One of PAGENAME, DATETIME or TECHNOTE-ID must be specified.
898906
**
899907
** DATETIME may be "now" or "YYYY-MM-DDTHH:MM:SS.SSS". If in
900908
** year-month-day form, it may be truncated, the "T" may be replaced by
@@ -915,16 +923,23 @@
915923
916924
if( strncmp(g.argv[2],"add",n)==0 ){
917925
const char *zPageName = 0; /* Name of the wiki page to attach to */
918926
const char *zFile; /* Name of the file to be attached */
919927
const char *zETime; /* The name of the technote to attach to */
928
+ const char *zMimetype; /* --mimetype NAME */
920929
Manifest *pWiki = 0; /* Parsed wiki page content */
921930
char *zBody = 0; /* Wiki page content */
922931
int rid;
923932
const char *zTarget; /* Target of the attachment */
924933
Blob content; /* The content of the attachment */
934
+ zMimetype = find_option("mimetype",0,1);
925935
zETime = find_option("technote","t",1);
936
+ /*
937
+ FIXME/TODO (2026-06-02): adapt this to use
938
+ attachment_target_type() and, when attaching to tech notes and
939
+ forum posts, always attach to their root version.
940
+ */
926941
if( !zETime ){
927942
if( g.argc!=5 ){
928943
usage("add PAGENAME FILENAME");
929944
}
930945
zPageName = g.argv[3];
@@ -967,10 +982,11 @@
967982
attach_commit(
968983
zFile, /* The filename of the attachment */
969984
zTarget, /* The artifact hash to attach to */
970985
blob_buffer(&content), /* The content of the attachment */
971986
blob_size(&content), /* The length of the attachment */
987
+ zMimetype, /* Mimetype */
972988
0, /* No need to moderate the attachment */
973989
"" /* Empty attachment comment */
974990
);
975991
if( !zETime ){
976992
fossil_print("Attached %s to wiki page %s.\n", zFile, zPageName);
977993
--- src/attach.c
+++ src/attach.c
@@ -346,10 +346,11 @@
346 void attach_commit(
347 const char *zName, /* The filename of the attachment */
348 const char *zTarget, /* The artifact hash to attach to */
349 const char *aContent, /* The content of the attachment */
350 int szContent, /* The length of the attachment */
 
351 int needModerator, /* Moderate the attachment? */
352 const char *zComment /* The comment for the attachment */
353 ){
354 Blob content;
355 Blob manifest;
@@ -386,10 +387,13 @@
386 if( n>0 ){
387 blob_appendf(&manifest, "C %#F\n", n, zComment);
388 }
389 zDate = date_in_standard_format("now");
390 blob_appendf(&manifest, "D %s\n", zDate);
 
 
 
391 blob_appendf(&manifest, "U %F\n", login_name());
392 md5sum_blob(&manifest, &cksum);
393 blob_appendf(&manifest, "Z %b\n", &cksum);
394 attach_put(&manifest, rid, needModerator);
395 assert( blob_is_reset(&manifest) );
@@ -414,10 +418,11 @@
414 const char *zTechNote = P("technote");
415 const char *zFrom = P("from");
416 const char *aContent = P("f");
417 const char *zName = PD("f:filename","unknown");
418 const char *zComment = PD("comment", "");
 
419 const char *zTarget;
420 char * zTo = 0;
421 char *zTargetType = 0;
422 char *zExtraFree = 0;
423 int szContent = atoi(PD("f:bytes","0"));
@@ -501,11 +506,12 @@
501 /* Fall through and render form. */
502 }else if( P("ok") && szContent>0 && (goodCaptcha = captcha_is_correct(0)) ){
503 int needModerator = (zForumPost!=0 && forum_need_moderation()) ||
504 (zTkt!=0 && ticket_need_moderation(0)) ||
505 (zPage!=0 && wiki_need_moderation(0));
506 attach_commit(zName, zTarget, aContent, szContent, needModerator, zComment);
 
507 cgi_redirect(zTo ? zTo : zFrom);
508 }
509
510 style_set_current_feature("attach");
511 style_header("Add Attachment");
@@ -891,10 +897,12 @@
891 ** is to be made. The attachment will be
892 ** to the most recently modified tech note
893 ** with the specified timestamp.
894 ** -t|--technote TECHNOTE-ID Specifies the technote to be
895 ** updated by its technote id
 
 
896 **
897 ** One of PAGENAME, DATETIME or TECHNOTE-ID must be specified.
898 **
899 ** DATETIME may be "now" or "YYYY-MM-DDTHH:MM:SS.SSS". If in
900 ** year-month-day form, it may be truncated, the "T" may be replaced by
@@ -915,16 +923,23 @@
915
916 if( strncmp(g.argv[2],"add",n)==0 ){
917 const char *zPageName = 0; /* Name of the wiki page to attach to */
918 const char *zFile; /* Name of the file to be attached */
919 const char *zETime; /* The name of the technote to attach to */
 
920 Manifest *pWiki = 0; /* Parsed wiki page content */
921 char *zBody = 0; /* Wiki page content */
922 int rid;
923 const char *zTarget; /* Target of the attachment */
924 Blob content; /* The content of the attachment */
 
925 zETime = find_option("technote","t",1);
 
 
 
 
 
926 if( !zETime ){
927 if( g.argc!=5 ){
928 usage("add PAGENAME FILENAME");
929 }
930 zPageName = g.argv[3];
@@ -967,10 +982,11 @@
967 attach_commit(
968 zFile, /* The filename of the attachment */
969 zTarget, /* The artifact hash to attach to */
970 blob_buffer(&content), /* The content of the attachment */
971 blob_size(&content), /* The length of the attachment */
 
972 0, /* No need to moderate the attachment */
973 "" /* Empty attachment comment */
974 );
975 if( !zETime ){
976 fossil_print("Attached %s to wiki page %s.\n", zFile, zPageName);
977
--- src/attach.c
+++ src/attach.c
@@ -346,10 +346,11 @@
346 void attach_commit(
347 const char *zName, /* The filename of the attachment */
348 const char *zTarget, /* The artifact hash to attach to */
349 const char *aContent, /* The content of the attachment */
350 int szContent, /* The length of the attachment */
351 const char *zMimetype, /* Content mimetype or NULL */
352 int needModerator, /* Moderate the attachment? */
353 const char *zComment /* The comment for the attachment */
354 ){
355 Blob content;
356 Blob manifest;
@@ -386,10 +387,13 @@
387 if( n>0 ){
388 blob_appendf(&manifest, "C %#F\n", n, zComment);
389 }
390 zDate = date_in_standard_format("now");
391 blob_appendf(&manifest, "D %s\n", zDate);
392 if( zMimetype && 0!=zMimetype[0] ){
393 blob_appendf(&manifest, "N %F\n", zMimetype);
394 }
395 blob_appendf(&manifest, "U %F\n", login_name());
396 md5sum_blob(&manifest, &cksum);
397 blob_appendf(&manifest, "Z %b\n", &cksum);
398 attach_put(&manifest, rid, needModerator);
399 assert( blob_is_reset(&manifest) );
@@ -414,10 +418,11 @@
418 const char *zTechNote = P("technote");
419 const char *zFrom = P("from");
420 const char *aContent = P("f");
421 const char *zName = PD("f:filename","unknown");
422 const char *zComment = PD("comment", "");
423 const char *zMimetype = P("mimetype");
424 const char *zTarget;
425 char * zTo = 0;
426 char *zTargetType = 0;
427 char *zExtraFree = 0;
428 int szContent = atoi(PD("f:bytes","0"));
@@ -501,11 +506,12 @@
506 /* Fall through and render form. */
507 }else if( P("ok") && szContent>0 && (goodCaptcha = captcha_is_correct(0)) ){
508 int needModerator = (zForumPost!=0 && forum_need_moderation()) ||
509 (zTkt!=0 && ticket_need_moderation(0)) ||
510 (zPage!=0 && wiki_need_moderation(0));
511 attach_commit(zName, zTarget, aContent, szContent, zMimetype,
512 needModerator, zComment);
513 cgi_redirect(zTo ? zTo : zFrom);
514 }
515
516 style_set_current_feature("attach");
517 style_header("Add Attachment");
@@ -891,10 +897,12 @@
897 ** is to be made. The attachment will be
898 ** to the most recently modified tech note
899 ** with the specified timestamp.
900 ** -t|--technote TECHNOTE-ID Specifies the technote to be
901 ** updated by its technote id
902 ** --mimetype TYPE Optional mimetype of the attached
903 ** content
904 **
905 ** One of PAGENAME, DATETIME or TECHNOTE-ID must be specified.
906 **
907 ** DATETIME may be "now" or "YYYY-MM-DDTHH:MM:SS.SSS". If in
908 ** year-month-day form, it may be truncated, the "T" may be replaced by
@@ -915,16 +923,23 @@
923
924 if( strncmp(g.argv[2],"add",n)==0 ){
925 const char *zPageName = 0; /* Name of the wiki page to attach to */
926 const char *zFile; /* Name of the file to be attached */
927 const char *zETime; /* The name of the technote to attach to */
928 const char *zMimetype; /* --mimetype NAME */
929 Manifest *pWiki = 0; /* Parsed wiki page content */
930 char *zBody = 0; /* Wiki page content */
931 int rid;
932 const char *zTarget; /* Target of the attachment */
933 Blob content; /* The content of the attachment */
934 zMimetype = find_option("mimetype",0,1);
935 zETime = find_option("technote","t",1);
936 /*
937 FIXME/TODO (2026-06-02): adapt this to use
938 attachment_target_type() and, when attaching to tech notes and
939 forum posts, always attach to their root version.
940 */
941 if( !zETime ){
942 if( g.argc!=5 ){
943 usage("add PAGENAME FILENAME");
944 }
945 zPageName = g.argv[3];
@@ -967,10 +982,11 @@
982 attach_commit(
983 zFile, /* The filename of the attachment */
984 zTarget, /* The artifact hash to attach to */
985 blob_buffer(&content), /* The content of the attachment */
986 blob_size(&content), /* The length of the attachment */
987 zMimetype, /* Mimetype */
988 0, /* No need to moderate the attachment */
989 "" /* Empty attachment comment */
990 );
991 if( !zETime ){
992 fossil_print("Attached %s to wiki page %s.\n", zFile, zPageName);
993
--- src/fossil.attach.js
+++ src/fossil.attach.js
@@ -216,10 +216,13 @@
216216
fd.append(`${namePrefix}${suffix}`, s.content, s.name);
217217
const d = s.description?.trim?.();
218218
if( d ){
219219
fd.append(`${namePrefix}${suffix}_desc`, d);
220220
}
221
+ if( s.mimetype ){
222
+ fd.append(`${namePrefix}${suffix}_mimetype`, s.mimetype);
223
+ }
221224
}
222225
return i;
223226
}
224227
}/*Attacher*/;
225228
226229
--- src/fossil.attach.js
+++ src/fossil.attach.js
@@ -216,10 +216,13 @@
216 fd.append(`${namePrefix}${suffix}`, s.content, s.name);
217 const d = s.description?.trim?.();
218 if( d ){
219 fd.append(`${namePrefix}${suffix}_desc`, d);
220 }
 
 
 
221 }
222 return i;
223 }
224 }/*Attacher*/;
225
226
--- src/fossil.attach.js
+++ src/fossil.attach.js
@@ -216,10 +216,13 @@
216 fd.append(`${namePrefix}${suffix}`, s.content, s.name);
217 const d = s.description?.trim?.();
218 if( d ){
219 fd.append(`${namePrefix}${suffix}_desc`, d);
220 }
221 if( s.mimetype ){
222 fd.append(`${namePrefix}${suffix}_mimetype`, s.mimetype);
223 }
224 }
225 return i;
226 }
227 }/*Attacher*/;
228
229
+2 -1
--- src/manifest.c
+++ src/manifest.c
@@ -863,11 +863,12 @@
863863
}
864864
865865
/*
866866
** N <uuid>
867867
**
868
- ** An N-line identifies the mimetype of wiki or comment text.
868
+ ** An N-line identifies the mimetype of wiki or comment text,
869
+ ** as well as that of the content of attachments.
869870
*/
870871
case 'N': {
871872
if( p->zMimetype!=0 ) SYNTAX("more than one N-card");
872873
p->zMimetype = next_token(&x,0);
873874
if( p->zMimetype==0 ) SYNTAX("missing mimetype on N-card");
874875
--- src/manifest.c
+++ src/manifest.c
@@ -863,11 +863,12 @@
863 }
864
865 /*
866 ** N <uuid>
867 **
868 ** An N-line identifies the mimetype of wiki or comment text.
 
869 */
870 case 'N': {
871 if( p->zMimetype!=0 ) SYNTAX("more than one N-card");
872 p->zMimetype = next_token(&x,0);
873 if( p->zMimetype==0 ) SYNTAX("missing mimetype on N-card");
874
--- src/manifest.c
+++ src/manifest.c
@@ -863,11 +863,12 @@
863 }
864
865 /*
866 ** N <uuid>
867 **
868 ** An N-line identifies the mimetype of wiki or comment text,
869 ** as well as that of the content of attachments.
870 */
871 case 'N': {
872 if( p->zMimetype!=0 ) SYNTAX("more than one N-card");
873 p->zMimetype = next_token(&x,0);
874 if( p->zMimetype==0 ) SYNTAX("missing mimetype on N-card");
875

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button