Fossil SCM

Code style cleanups. Wrap some over-long lines.

stephan 2026-06-05 08:28 UTC attach-v2
Commit a1d272a2066ca80f74943509ad01f8569fc863064df8a627e0d382030a2efb3d
1 file changed +58 -40
+58 -40
--- src/attach.c
+++ src/attach.c
@@ -40,11 +40,11 @@
4040
**
4141
** Wiki page names always require an exact match.
4242
**
4343
** Forum posts are a special case:
4444
**
45
-** - The ignore the bFull flag. That is, they will do prefix matches
45
+** - They ignore the bFull flag. That is, they will do prefix matches
4646
** but will not match an ambiguous prefix.
4747
**
4848
** - It is up to the caller to, if needed, resolve zTarget using
4949
** forumpost_head_rid2() to resolve the RID of the earliest version
5050
** of the post, as that is the only one which attachments should
@@ -773,11 +773,11 @@
773773
** subject to amendment.
774774
*/
775775
void attachadd_ajax_post(void){
776776
const char *zTarget;
777777
char *zExtraFree = 0;
778
- int iTgtType = 0;
778
+ int eTgtType = 0;
779779
int bNeedsModeration = 0;
780780
int i;
781781
int goodCaptcha = 1;
782782
int szLimit; /* attachment-max-size setting */
783783
int bRollback = 0; /* Roll back if true. */
@@ -794,13 +794,13 @@
794794
ajax_route_error(403, "Invalid CSRF signature.");
795795
return;
796796
}
797797
db_begin_transaction();
798798
zTarget = P("target");
799
- iTgtType = attachment_target_type(zTarget, 1);
799
+ eTgtType = attachment_target_type(zTarget, 1);
800800
CX("{");
801
- switch( iTgtType ){
801
+ switch( eTgtType ){
802802
default:
803803
case 0:
804804
ajax_route_error(400, "Invalid attachment target.");
805805
db_rollback_transaction();
806806
return;
@@ -824,11 +824,12 @@
824824
}
825825
case CFTYPE_EVENT:{
826826
if( g.perm.Write==0 || g.perm.ApndWiki==0 || g.perm.Attach==0 ){
827827
goto ajax_post_403;
828828
}
829
- if( !db_exists("SELECT 1 FROM tag WHERE tagname='event-%q'", zTarget) ){
829
+ if( !db_exists("SELECT 1 FROM tag WHERE tagname='event-%q'",
830
+ zTarget) ){
830831
zTarget = zExtraFree =
831832
db_text(0, "SELECT substr(tagname,7) FROM tag"
832833
" WHERE tagname GLOB 'event-%q*'", zTarget);
833834
if( zTarget==0){
834835
goto ajax_post_404;
@@ -839,11 +840,12 @@
839840
}
840841
case CFTYPE_TICKET:{
841842
if( g.perm.ApndTkt==0 || g.perm.Attach==0 ){
842843
goto ajax_post_403;
843844
}
844
- if( !db_exists("SELECT 1 FROM tag WHERE tagname='tkt-%q'", zTarget) ){
845
+ if( !db_exists("SELECT 1 FROM tag WHERE tagname='tkt-%q'",
846
+ zTarget) ){
845847
zTarget = db_text(0, "SELECT substr(tagname,5) FROM tag"
846848
" WHERE tagname GLOB 'tkt-%q*'", zTarget);
847849
if( zTarget==0 ){
848850
goto ajax_post_404;
849851
}
@@ -853,11 +855,12 @@
853855
}
854856
case CFTYPE_WIKI:{
855857
if( g.perm.ApndWiki==0 || g.perm.Attach==0 ){
856858
goto ajax_post_403;
857859
}
858
- if( !db_exists("SELECT 1 FROM tag WHERE tagname='wiki-%q'", zTarget) ){
860
+ if( !db_exists("SELECT 1 FROM tag WHERE tagname='wiki-%q'",
861
+ zTarget) ){
859862
goto ajax_post_404;
860863
}
861864
bNeedsModeration = wiki_need_moderation(0);
862865
break;
863866
}
@@ -878,10 +881,11 @@
878881
aKeyPrefix);
879882
szContent = atoi(PD(aKeySize,"-1"));
880883
if( szContent<=0 ){
881884
bRollback = 1;
882885
ajax_route_error(400,"Invalid file size: %d", szContent);
886
+ break;
883887
}else if( szLimit>0 && szContent>szLimit ){
884888
bRollback = 1;
885889
ajax_route_error(400, "File size limit is %d bytes.", szLimit);
886890
break;
887891
}else{
@@ -919,18 +923,15 @@
919923
**
920924
** target=TKT_HASH|WIKIPAGE_NAME|TECHNOTE_HASH|FORUMPOST_HASH
921925
** from=ORIGINATING_URL
922926
**
923927
** Works like /attachadd but uses a JS-based interactive attachment
924
-** selector. If from=X is set, this page arrganges for a redirect
925
-** back to X after attaching.
926
-**
927
-** from=X and to=X tell it how to redirect when it's done. to=X
928
-** overrides from=X. If neither is set, it will redirect back to this
929
-** page to render the updated attachment list.
930
-**
931
-** This page requires a post-2020 JS-capable browser.
928
+** selector.
929
+**
930
+** from=X tells it where to redirect to when it's done.
931
+**
932
+** This page requires a post-2018-ish JS-capable browser.
932933
*/
933934
void attachaddV2_page(void){
934935
const char *zFrom = P("from");
935936
const char *zTarget = P("target");
936937
char *zTo = 0;
@@ -964,23 +965,27 @@
964965
webpage_error("Only admins can attach files to other users' "
965966
"forum posts.");
966967
}
967968
zTarget = zExtraFree = rid_to_uuid(fpid);
968969
noJsArgs[0] = zTarget;
969
- zTargetType = mprintf("Forum post <a href=\"%R/forumpost/%S\">%.16h</a>",
970
- zTarget, zTarget);
970
+ zTargetType = mprintf(
971
+ "Forum post <a href=\"%R/forumpost/%S\">%.16h</a>",
972
+ zTarget, zTarget
973
+ );
971974
zTo = mprintf("%R/forumpost/%S", zTarget);
972975
break;
973976
}
974977
case CFTYPE_EVENT:{
975978
if( g.perm.Write==0 || g.perm.ApndWiki==0 || g.perm.Attach==0 ){
976979
login_needed(g.anon.Write && g.anon.ApndWiki && g.anon.Attach);
977980
return;
978981
}
979
- if( !db_exists("SELECT 1 FROM tag WHERE tagname='event-%q'", zTarget) ){
982
+ if( !db_exists("SELECT 1 FROM tag WHERE tagname='event-%q'",
983
+ zTarget) ){
980984
zTarget = db_text(0, "SELECT substr(tagname,7) FROM tag"
981
- " WHERE tagname GLOB 'event-%q*'", zTarget);
985
+ " WHERE tagname GLOB 'event-%q*'",
986
+ zTarget);
982987
if( zTarget==0) fossil_redirect_home();
983988
}
984989
zTo = zFrom ? 0 : mprintf("%R/technote?name=%T", zTarget);
985990
zTargetType = mprintf("Tech-note <a href=\"%R/technote/%s\">%S</a>",
986991
zTarget, zTarget);
@@ -990,11 +995,12 @@
990995
case CFTYPE_TICKET:{
991996
if( g.perm.ApndTkt==0 || g.perm.Attach==0 ){
992997
login_needed(g.anon.ApndTkt && g.anon.Attach);
993998
return;
994999
}
995
- if( !db_exists("SELECT 1 FROM tag WHERE tagname='tkt-%q'", zTarget) ){
1000
+ if( !db_exists("SELECT 1 FROM tag WHERE tagname='tkt-%q'",
1001
+ zTarget) ){
9961002
zTarget = db_text(0, "SELECT substr(tagname,5) FROM tag"
9971003
" WHERE tagname GLOB 'tkt-%q*'", zTarget);
9981004
if( zTarget==0 ) fossil_redirect_home();
9991005
}
10001006
zTo = zFrom ? 0 : mprintf("%R/tktview/%t", zTarget);
@@ -1006,16 +1012,19 @@
10061012
case CFTYPE_WIKI:{
10071013
if( g.perm.ApndWiki==0 || g.perm.Attach==0 ){
10081014
login_needed(g.anon.ApndWiki && g.anon.Attach);
10091015
return;
10101016
}
1011
- if( !db_exists("SELECT 1 FROM tag WHERE tagname='wiki-%q'", zTarget) ){
1017
+ if( !db_exists("SELECT 1 FROM tag WHERE tagname='wiki-%q'",
1018
+ zTarget) ){
10121019
fossil_redirect_home();
10131020
}
10141021
zTo = zFrom ? 0 : mprintf("%R/wiki?name=%T", zTarget);
1015
- zTargetType = mprintf("Wiki page <a href=\"%R/wiki?name=%h\">%h</a>",
1016
- zTarget, zTarget);
1022
+ zTargetType = mprintf(
1023
+ "Wiki page <a href=\"%R/wiki?name=%h\">%h</a>",
1024
+ zTarget, zTarget
1025
+ );
10171026
noJsArgs[3] = zTarget;
10181027
break;
10191028
}
10201029
}
10211030
@@ -1117,15 +1126,17 @@
11171126
&& db_exists("SELECT 1 FROM ticket WHERE tkt_uuid='%q'", zTarget)
11181127
){
11191128
if( !g.perm.RdTkt ){ login_needed(g.anon.RdTkt); return; }
11201129
zTktUuid = zTarget;
11211130
showDelMenu = g.perm.WrTkt;
1122
- }else if( db_exists("SELECT 1 FROM tag WHERE tagname='wiki-%q'",zTarget) ){
1131
+ }else if( db_exists("SELECT 1 FROM tag WHERE tagname='wiki-%q'",
1132
+ zTarget) ){
11231133
if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; }
11241134
zWikiName = zTarget;
11251135
showDelMenu = g.perm.WrWiki;
1126
- }else if( db_exists("SELECT 1 FROM tag WHERE tagname='event-%q'",zTarget) ){
1136
+ }else if( db_exists("SELECT 1 FROM tag WHERE tagname='event-%q'",
1137
+ zTarget) ){
11271138
if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; }
11281139
zTNUuid = zTarget;
11291140
showDelMenu = g.perm.Write && g.perm.WrWiki;
11301141
}
11311142
if( showDelMenu ){
@@ -1149,11 +1160,13 @@
11491160
Blob cksum;
11501161
const char *zFile = zName;
11511162
11521163
if( !bUserIsOwner ){
11531164
if( zForumPost ? !forumpost_may_close() : !g.perm.Admin ){
1154
- webpage_error("Only admins can delete other users' attachments.");
1165
+ webpage_error(
1166
+ "Only admins can delete other users' attachments."
1167
+ );
11551168
}
11561169
}
11571170
db_begin_transaction();
11581171
blob_zero(&manifest);
11591172
for(i=n=0; zFile[i]; i++){
@@ -1173,14 +1186,14 @@
11731186
@ <p>The attachment below has been deleted.</p>
11741187
fossil_free(zNewDate);
11751188
}
11761189
11771190
if( P("del")
1178
- && ((zForumPost && (bUserIsOwner || forumpost_may_close())) ||
1179
- (zTktUuid && g.perm.WrTkt) ||
1180
- (zWikiName && g.perm.WrWiki) ||
1181
- (zTNUuid && g.perm.Write && g.perm.WrWiki))
1191
+ && ((zForumPost && (bUserIsOwner || forumpost_may_close()))
1192
+ || (zTktUuid && g.perm.WrTkt)
1193
+ || (zWikiName && g.perm.WrWiki)
1194
+ || (zTNUuid && g.perm.Write && g.perm.WrWiki))
11821195
){
11831196
form_begin(0, "%R/ainfo/%!S", zUuid);
11841197
@ <p>Confirm you want to delete the attachment shown below.
11851198
@ <input type="submit" name="confirm" value="Confirm">
11861199
login_insert_csrf_secret();
@@ -1228,20 +1241,22 @@
12281241
@ (%d(rid))
12291242
}
12301243
modPending = moderation_pending_www(rid);
12311244
if( zForumPost ){
12321245
@ <tr><th>Forum&nbsp;Post:</th>
1233
- @ <td>%z(href("%R/forumpost/%s",zForumPost))%h(zForumPost)</a></td></tr>
1246
+ @ <td>%z(href("%R/forumpost/%s",zForumPost))%h(zForumPost)</a>\
1247
+ @ </td></tr>
12341248
}else if( zTktUuid ){
12351249
@ <tr><th>Ticket:</th>
12361250
@ <td>%z(href("%R/tktview/%s",zTktUuid))%s(zTktUuid)</a></td></tr>
12371251
}else if( zTNUuid ){
12381252
@ <tr><th>Tech Note:</th>
12391253
@ <td>%z(href("%R/technote/%s",zTNUuid))%s(zTNUuid)</a></td></tr>
12401254
}else if( zWikiName ){
12411255
@ <tr><th>Wiki&nbsp;Page:</th>
1242
- @ <td>%z(href("%R/wiki?name=%t",zWikiName))%h(zWikiName)</a></td></tr>
1256
+ @ <td>%z(href("%R/wiki?name=%t",zWikiName))%h(zWikiName)</a>\
1257
+ @ </td></tr>
12431258
}
12441259
@ <tr><th>Date:</th><td>
12451260
hyperlink_to_date(zDate, "</td></tr>");
12461261
@ <tr><th>User:</th><td>
12471262
hyperlink_to_user(pAttach->zUser, zDate, "</td></tr>");
@@ -1252,11 +1267,12 @@
12521267
}
12531268
@ <tr><th>Filename:</th><td>%h(zName)</td></tr>
12541269
if( g.perm.Setup ){
12551270
@ <tr><th>MIME-Type:</th><td>%h(zMime)</td></tr>
12561271
}
1257
- @ <tr><th valign="top">Description:</th><td valign="top">%h(zDesc)</td></tr>
1272
+ @ <tr><th valign="top">Description:</th>\
1273
+ @ <td valign="top">%h(zDesc)</td></tr>
12581274
@ </table>
12591275
12601276
if( modPending && (isModerator || bUserIsOwner) ){
12611277
@ <div class="section">Moderation</div>
12621278
@ <blockquote>
@@ -1263,18 +1279,19 @@
12631279
form_begin(0, "%R/ainfo/%s", zUuid);
12641280
@ <label><input type="radio" name="modaction" value="delete">
12651281
@ Delete this attachment</label><br>
12661282
if( isModerator ){
12671283
#if 0
1268
- /* TODO: only allow approval of an attachment if its target has
1269
- ** been approved. Without this, we can end up with stale
1270
- ** attachments which refer to rejected targets. We need a
1271
- ** type-specific RID/UUID here, which requires refactoring
1272
- ** above to get it. */
1284
+ /* TODO/FIXME (2026-06-03): only allow approval of an attachment
1285
+ ** if its target has been approved. Without this, we can end up
1286
+ ** with stale attachments which refer to rejected targets. We
1287
+ ** need a type-specific RID/UUID here, which requires
1288
+ ** refactoring above to get it. */
12731289
const int tgtid = 0;
12741290
if( moderation_pending(tgtid) ){
1275
- @ <label><input type="radio" name="modaction" disabled value="approve">
1291
+ @ <label><input type="radio" name="modaction" \
1292
+ @ disabled value="approve">
12761293
@ <span class='modpending'>Cannot approve:
12771294
@ target is pending moderation</span>\
12781295
@ </label><br>
12791296
}else
12801297
#else
@@ -1301,11 +1318,12 @@
13011318
const char *z;
13021319
content_get(ridSrc, &attach);
13031320
blob_to_utf8_no_bom(&attach, 0);
13041321
z = blob_str(&attach);
13051322
if( zLn ){
1306
- output_text_with_line_numbers(z, blob_size(&attach), zName, zLn, 1);
1323
+ output_text_with_line_numbers(z, blob_size(&attach),
1324
+ zName, zLn, 1);
13071325
}else{
13081326
@ <pre>
13091327
@ %h(z)
13101328
@ </pre>
13111329
}
13121330
--- src/attach.c
+++ src/attach.c
@@ -40,11 +40,11 @@
40 **
41 ** Wiki page names always require an exact match.
42 **
43 ** Forum posts are a special case:
44 **
45 ** - The ignore the bFull flag. That is, they will do prefix matches
46 ** but will not match an ambiguous prefix.
47 **
48 ** - It is up to the caller to, if needed, resolve zTarget using
49 ** forumpost_head_rid2() to resolve the RID of the earliest version
50 ** of the post, as that is the only one which attachments should
@@ -773,11 +773,11 @@
773 ** subject to amendment.
774 */
775 void attachadd_ajax_post(void){
776 const char *zTarget;
777 char *zExtraFree = 0;
778 int iTgtType = 0;
779 int bNeedsModeration = 0;
780 int i;
781 int goodCaptcha = 1;
782 int szLimit; /* attachment-max-size setting */
783 int bRollback = 0; /* Roll back if true. */
@@ -794,13 +794,13 @@
794 ajax_route_error(403, "Invalid CSRF signature.");
795 return;
796 }
797 db_begin_transaction();
798 zTarget = P("target");
799 iTgtType = attachment_target_type(zTarget, 1);
800 CX("{");
801 switch( iTgtType ){
802 default:
803 case 0:
804 ajax_route_error(400, "Invalid attachment target.");
805 db_rollback_transaction();
806 return;
@@ -824,11 +824,12 @@
824 }
825 case CFTYPE_EVENT:{
826 if( g.perm.Write==0 || g.perm.ApndWiki==0 || g.perm.Attach==0 ){
827 goto ajax_post_403;
828 }
829 if( !db_exists("SELECT 1 FROM tag WHERE tagname='event-%q'", zTarget) ){
 
830 zTarget = zExtraFree =
831 db_text(0, "SELECT substr(tagname,7) FROM tag"
832 " WHERE tagname GLOB 'event-%q*'", zTarget);
833 if( zTarget==0){
834 goto ajax_post_404;
@@ -839,11 +840,12 @@
839 }
840 case CFTYPE_TICKET:{
841 if( g.perm.ApndTkt==0 || g.perm.Attach==0 ){
842 goto ajax_post_403;
843 }
844 if( !db_exists("SELECT 1 FROM tag WHERE tagname='tkt-%q'", zTarget) ){
 
845 zTarget = db_text(0, "SELECT substr(tagname,5) FROM tag"
846 " WHERE tagname GLOB 'tkt-%q*'", zTarget);
847 if( zTarget==0 ){
848 goto ajax_post_404;
849 }
@@ -853,11 +855,12 @@
853 }
854 case CFTYPE_WIKI:{
855 if( g.perm.ApndWiki==0 || g.perm.Attach==0 ){
856 goto ajax_post_403;
857 }
858 if( !db_exists("SELECT 1 FROM tag WHERE tagname='wiki-%q'", zTarget) ){
 
859 goto ajax_post_404;
860 }
861 bNeedsModeration = wiki_need_moderation(0);
862 break;
863 }
@@ -878,10 +881,11 @@
878 aKeyPrefix);
879 szContent = atoi(PD(aKeySize,"-1"));
880 if( szContent<=0 ){
881 bRollback = 1;
882 ajax_route_error(400,"Invalid file size: %d", szContent);
 
883 }else if( szLimit>0 && szContent>szLimit ){
884 bRollback = 1;
885 ajax_route_error(400, "File size limit is %d bytes.", szLimit);
886 break;
887 }else{
@@ -919,18 +923,15 @@
919 **
920 ** target=TKT_HASH|WIKIPAGE_NAME|TECHNOTE_HASH|FORUMPOST_HASH
921 ** from=ORIGINATING_URL
922 **
923 ** Works like /attachadd but uses a JS-based interactive attachment
924 ** selector. If from=X is set, this page arrganges for a redirect
925 ** back to X after attaching.
926 **
927 ** from=X and to=X tell it how to redirect when it's done. to=X
928 ** overrides from=X. If neither is set, it will redirect back to this
929 ** page to render the updated attachment list.
930 **
931 ** This page requires a post-2020 JS-capable browser.
932 */
933 void attachaddV2_page(void){
934 const char *zFrom = P("from");
935 const char *zTarget = P("target");
936 char *zTo = 0;
@@ -964,23 +965,27 @@
964 webpage_error("Only admins can attach files to other users' "
965 "forum posts.");
966 }
967 zTarget = zExtraFree = rid_to_uuid(fpid);
968 noJsArgs[0] = zTarget;
969 zTargetType = mprintf("Forum post <a href=\"%R/forumpost/%S\">%.16h</a>",
970 zTarget, zTarget);
 
 
971 zTo = mprintf("%R/forumpost/%S", zTarget);
972 break;
973 }
974 case CFTYPE_EVENT:{
975 if( g.perm.Write==0 || g.perm.ApndWiki==0 || g.perm.Attach==0 ){
976 login_needed(g.anon.Write && g.anon.ApndWiki && g.anon.Attach);
977 return;
978 }
979 if( !db_exists("SELECT 1 FROM tag WHERE tagname='event-%q'", zTarget) ){
 
980 zTarget = db_text(0, "SELECT substr(tagname,7) FROM tag"
981 " WHERE tagname GLOB 'event-%q*'", zTarget);
 
982 if( zTarget==0) fossil_redirect_home();
983 }
984 zTo = zFrom ? 0 : mprintf("%R/technote?name=%T", zTarget);
985 zTargetType = mprintf("Tech-note <a href=\"%R/technote/%s\">%S</a>",
986 zTarget, zTarget);
@@ -990,11 +995,12 @@
990 case CFTYPE_TICKET:{
991 if( g.perm.ApndTkt==0 || g.perm.Attach==0 ){
992 login_needed(g.anon.ApndTkt && g.anon.Attach);
993 return;
994 }
995 if( !db_exists("SELECT 1 FROM tag WHERE tagname='tkt-%q'", zTarget) ){
 
996 zTarget = db_text(0, "SELECT substr(tagname,5) FROM tag"
997 " WHERE tagname GLOB 'tkt-%q*'", zTarget);
998 if( zTarget==0 ) fossil_redirect_home();
999 }
1000 zTo = zFrom ? 0 : mprintf("%R/tktview/%t", zTarget);
@@ -1006,16 +1012,19 @@
1006 case CFTYPE_WIKI:{
1007 if( g.perm.ApndWiki==0 || g.perm.Attach==0 ){
1008 login_needed(g.anon.ApndWiki && g.anon.Attach);
1009 return;
1010 }
1011 if( !db_exists("SELECT 1 FROM tag WHERE tagname='wiki-%q'", zTarget) ){
 
1012 fossil_redirect_home();
1013 }
1014 zTo = zFrom ? 0 : mprintf("%R/wiki?name=%T", zTarget);
1015 zTargetType = mprintf("Wiki page <a href=\"%R/wiki?name=%h\">%h</a>",
1016 zTarget, zTarget);
 
 
1017 noJsArgs[3] = zTarget;
1018 break;
1019 }
1020 }
1021
@@ -1117,15 +1126,17 @@
1117 && db_exists("SELECT 1 FROM ticket WHERE tkt_uuid='%q'", zTarget)
1118 ){
1119 if( !g.perm.RdTkt ){ login_needed(g.anon.RdTkt); return; }
1120 zTktUuid = zTarget;
1121 showDelMenu = g.perm.WrTkt;
1122 }else if( db_exists("SELECT 1 FROM tag WHERE tagname='wiki-%q'",zTarget) ){
 
1123 if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; }
1124 zWikiName = zTarget;
1125 showDelMenu = g.perm.WrWiki;
1126 }else if( db_exists("SELECT 1 FROM tag WHERE tagname='event-%q'",zTarget) ){
 
1127 if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; }
1128 zTNUuid = zTarget;
1129 showDelMenu = g.perm.Write && g.perm.WrWiki;
1130 }
1131 if( showDelMenu ){
@@ -1149,11 +1160,13 @@
1149 Blob cksum;
1150 const char *zFile = zName;
1151
1152 if( !bUserIsOwner ){
1153 if( zForumPost ? !forumpost_may_close() : !g.perm.Admin ){
1154 webpage_error("Only admins can delete other users' attachments.");
 
 
1155 }
1156 }
1157 db_begin_transaction();
1158 blob_zero(&manifest);
1159 for(i=n=0; zFile[i]; i++){
@@ -1173,14 +1186,14 @@
1173 @ <p>The attachment below has been deleted.</p>
1174 fossil_free(zNewDate);
1175 }
1176
1177 if( P("del")
1178 && ((zForumPost && (bUserIsOwner || forumpost_may_close())) ||
1179 (zTktUuid && g.perm.WrTkt) ||
1180 (zWikiName && g.perm.WrWiki) ||
1181 (zTNUuid && g.perm.Write && g.perm.WrWiki))
1182 ){
1183 form_begin(0, "%R/ainfo/%!S", zUuid);
1184 @ <p>Confirm you want to delete the attachment shown below.
1185 @ <input type="submit" name="confirm" value="Confirm">
1186 login_insert_csrf_secret();
@@ -1228,20 +1241,22 @@
1228 @ (%d(rid))
1229 }
1230 modPending = moderation_pending_www(rid);
1231 if( zForumPost ){
1232 @ <tr><th>Forum&nbsp;Post:</th>
1233 @ <td>%z(href("%R/forumpost/%s",zForumPost))%h(zForumPost)</a></td></tr>
 
1234 }else if( zTktUuid ){
1235 @ <tr><th>Ticket:</th>
1236 @ <td>%z(href("%R/tktview/%s",zTktUuid))%s(zTktUuid)</a></td></tr>
1237 }else if( zTNUuid ){
1238 @ <tr><th>Tech Note:</th>
1239 @ <td>%z(href("%R/technote/%s",zTNUuid))%s(zTNUuid)</a></td></tr>
1240 }else if( zWikiName ){
1241 @ <tr><th>Wiki&nbsp;Page:</th>
1242 @ <td>%z(href("%R/wiki?name=%t",zWikiName))%h(zWikiName)</a></td></tr>
 
1243 }
1244 @ <tr><th>Date:</th><td>
1245 hyperlink_to_date(zDate, "</td></tr>");
1246 @ <tr><th>User:</th><td>
1247 hyperlink_to_user(pAttach->zUser, zDate, "</td></tr>");
@@ -1252,11 +1267,12 @@
1252 }
1253 @ <tr><th>Filename:</th><td>%h(zName)</td></tr>
1254 if( g.perm.Setup ){
1255 @ <tr><th>MIME-Type:</th><td>%h(zMime)</td></tr>
1256 }
1257 @ <tr><th valign="top">Description:</th><td valign="top">%h(zDesc)</td></tr>
 
1258 @ </table>
1259
1260 if( modPending && (isModerator || bUserIsOwner) ){
1261 @ <div class="section">Moderation</div>
1262 @ <blockquote>
@@ -1263,18 +1279,19 @@
1263 form_begin(0, "%R/ainfo/%s", zUuid);
1264 @ <label><input type="radio" name="modaction" value="delete">
1265 @ Delete this attachment</label><br>
1266 if( isModerator ){
1267 #if 0
1268 /* TODO: only allow approval of an attachment if its target has
1269 ** been approved. Without this, we can end up with stale
1270 ** attachments which refer to rejected targets. We need a
1271 ** type-specific RID/UUID here, which requires refactoring
1272 ** above to get it. */
1273 const int tgtid = 0;
1274 if( moderation_pending(tgtid) ){
1275 @ <label><input type="radio" name="modaction" disabled value="approve">
 
1276 @ <span class='modpending'>Cannot approve:
1277 @ target is pending moderation</span>\
1278 @ </label><br>
1279 }else
1280 #else
@@ -1301,11 +1318,12 @@
1301 const char *z;
1302 content_get(ridSrc, &attach);
1303 blob_to_utf8_no_bom(&attach, 0);
1304 z = blob_str(&attach);
1305 if( zLn ){
1306 output_text_with_line_numbers(z, blob_size(&attach), zName, zLn, 1);
 
1307 }else{
1308 @ <pre>
1309 @ %h(z)
1310 @ </pre>
1311 }
1312
--- src/attach.c
+++ src/attach.c
@@ -40,11 +40,11 @@
40 **
41 ** Wiki page names always require an exact match.
42 **
43 ** Forum posts are a special case:
44 **
45 ** - They ignore the bFull flag. That is, they will do prefix matches
46 ** but will not match an ambiguous prefix.
47 **
48 ** - It is up to the caller to, if needed, resolve zTarget using
49 ** forumpost_head_rid2() to resolve the RID of the earliest version
50 ** of the post, as that is the only one which attachments should
@@ -773,11 +773,11 @@
773 ** subject to amendment.
774 */
775 void attachadd_ajax_post(void){
776 const char *zTarget;
777 char *zExtraFree = 0;
778 int eTgtType = 0;
779 int bNeedsModeration = 0;
780 int i;
781 int goodCaptcha = 1;
782 int szLimit; /* attachment-max-size setting */
783 int bRollback = 0; /* Roll back if true. */
@@ -794,13 +794,13 @@
794 ajax_route_error(403, "Invalid CSRF signature.");
795 return;
796 }
797 db_begin_transaction();
798 zTarget = P("target");
799 eTgtType = attachment_target_type(zTarget, 1);
800 CX("{");
801 switch( eTgtType ){
802 default:
803 case 0:
804 ajax_route_error(400, "Invalid attachment target.");
805 db_rollback_transaction();
806 return;
@@ -824,11 +824,12 @@
824 }
825 case CFTYPE_EVENT:{
826 if( g.perm.Write==0 || g.perm.ApndWiki==0 || g.perm.Attach==0 ){
827 goto ajax_post_403;
828 }
829 if( !db_exists("SELECT 1 FROM tag WHERE tagname='event-%q'",
830 zTarget) ){
831 zTarget = zExtraFree =
832 db_text(0, "SELECT substr(tagname,7) FROM tag"
833 " WHERE tagname GLOB 'event-%q*'", zTarget);
834 if( zTarget==0){
835 goto ajax_post_404;
@@ -839,11 +840,12 @@
840 }
841 case CFTYPE_TICKET:{
842 if( g.perm.ApndTkt==0 || g.perm.Attach==0 ){
843 goto ajax_post_403;
844 }
845 if( !db_exists("SELECT 1 FROM tag WHERE tagname='tkt-%q'",
846 zTarget) ){
847 zTarget = db_text(0, "SELECT substr(tagname,5) FROM tag"
848 " WHERE tagname GLOB 'tkt-%q*'", zTarget);
849 if( zTarget==0 ){
850 goto ajax_post_404;
851 }
@@ -853,11 +855,12 @@
855 }
856 case CFTYPE_WIKI:{
857 if( g.perm.ApndWiki==0 || g.perm.Attach==0 ){
858 goto ajax_post_403;
859 }
860 if( !db_exists("SELECT 1 FROM tag WHERE tagname='wiki-%q'",
861 zTarget) ){
862 goto ajax_post_404;
863 }
864 bNeedsModeration = wiki_need_moderation(0);
865 break;
866 }
@@ -878,10 +881,11 @@
881 aKeyPrefix);
882 szContent = atoi(PD(aKeySize,"-1"));
883 if( szContent<=0 ){
884 bRollback = 1;
885 ajax_route_error(400,"Invalid file size: %d", szContent);
886 break;
887 }else if( szLimit>0 && szContent>szLimit ){
888 bRollback = 1;
889 ajax_route_error(400, "File size limit is %d bytes.", szLimit);
890 break;
891 }else{
@@ -919,18 +923,15 @@
923 **
924 ** target=TKT_HASH|WIKIPAGE_NAME|TECHNOTE_HASH|FORUMPOST_HASH
925 ** from=ORIGINATING_URL
926 **
927 ** Works like /attachadd but uses a JS-based interactive attachment
928 ** selector.
929 **
930 ** from=X tells it where to redirect to when it's done.
931 **
932 ** This page requires a post-2018-ish JS-capable browser.
 
 
 
933 */
934 void attachaddV2_page(void){
935 const char *zFrom = P("from");
936 const char *zTarget = P("target");
937 char *zTo = 0;
@@ -964,23 +965,27 @@
965 webpage_error("Only admins can attach files to other users' "
966 "forum posts.");
967 }
968 zTarget = zExtraFree = rid_to_uuid(fpid);
969 noJsArgs[0] = zTarget;
970 zTargetType = mprintf(
971 "Forum post <a href=\"%R/forumpost/%S\">%.16h</a>",
972 zTarget, zTarget
973 );
974 zTo = mprintf("%R/forumpost/%S", zTarget);
975 break;
976 }
977 case CFTYPE_EVENT:{
978 if( g.perm.Write==0 || g.perm.ApndWiki==0 || g.perm.Attach==0 ){
979 login_needed(g.anon.Write && g.anon.ApndWiki && g.anon.Attach);
980 return;
981 }
982 if( !db_exists("SELECT 1 FROM tag WHERE tagname='event-%q'",
983 zTarget) ){
984 zTarget = db_text(0, "SELECT substr(tagname,7) FROM tag"
985 " WHERE tagname GLOB 'event-%q*'",
986 zTarget);
987 if( zTarget==0) fossil_redirect_home();
988 }
989 zTo = zFrom ? 0 : mprintf("%R/technote?name=%T", zTarget);
990 zTargetType = mprintf("Tech-note <a href=\"%R/technote/%s\">%S</a>",
991 zTarget, zTarget);
@@ -990,11 +995,12 @@
995 case CFTYPE_TICKET:{
996 if( g.perm.ApndTkt==0 || g.perm.Attach==0 ){
997 login_needed(g.anon.ApndTkt && g.anon.Attach);
998 return;
999 }
1000 if( !db_exists("SELECT 1 FROM tag WHERE tagname='tkt-%q'",
1001 zTarget) ){
1002 zTarget = db_text(0, "SELECT substr(tagname,5) FROM tag"
1003 " WHERE tagname GLOB 'tkt-%q*'", zTarget);
1004 if( zTarget==0 ) fossil_redirect_home();
1005 }
1006 zTo = zFrom ? 0 : mprintf("%R/tktview/%t", zTarget);
@@ -1006,16 +1012,19 @@
1012 case CFTYPE_WIKI:{
1013 if( g.perm.ApndWiki==0 || g.perm.Attach==0 ){
1014 login_needed(g.anon.ApndWiki && g.anon.Attach);
1015 return;
1016 }
1017 if( !db_exists("SELECT 1 FROM tag WHERE tagname='wiki-%q'",
1018 zTarget) ){
1019 fossil_redirect_home();
1020 }
1021 zTo = zFrom ? 0 : mprintf("%R/wiki?name=%T", zTarget);
1022 zTargetType = mprintf(
1023 "Wiki page <a href=\"%R/wiki?name=%h\">%h</a>",
1024 zTarget, zTarget
1025 );
1026 noJsArgs[3] = zTarget;
1027 break;
1028 }
1029 }
1030
@@ -1117,15 +1126,17 @@
1126 && db_exists("SELECT 1 FROM ticket WHERE tkt_uuid='%q'", zTarget)
1127 ){
1128 if( !g.perm.RdTkt ){ login_needed(g.anon.RdTkt); return; }
1129 zTktUuid = zTarget;
1130 showDelMenu = g.perm.WrTkt;
1131 }else if( db_exists("SELECT 1 FROM tag WHERE tagname='wiki-%q'",
1132 zTarget) ){
1133 if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; }
1134 zWikiName = zTarget;
1135 showDelMenu = g.perm.WrWiki;
1136 }else if( db_exists("SELECT 1 FROM tag WHERE tagname='event-%q'",
1137 zTarget) ){
1138 if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; }
1139 zTNUuid = zTarget;
1140 showDelMenu = g.perm.Write && g.perm.WrWiki;
1141 }
1142 if( showDelMenu ){
@@ -1149,11 +1160,13 @@
1160 Blob cksum;
1161 const char *zFile = zName;
1162
1163 if( !bUserIsOwner ){
1164 if( zForumPost ? !forumpost_may_close() : !g.perm.Admin ){
1165 webpage_error(
1166 "Only admins can delete other users' attachments."
1167 );
1168 }
1169 }
1170 db_begin_transaction();
1171 blob_zero(&manifest);
1172 for(i=n=0; zFile[i]; i++){
@@ -1173,14 +1186,14 @@
1186 @ <p>The attachment below has been deleted.</p>
1187 fossil_free(zNewDate);
1188 }
1189
1190 if( P("del")
1191 && ((zForumPost && (bUserIsOwner || forumpost_may_close()))
1192 || (zTktUuid && g.perm.WrTkt)
1193 || (zWikiName && g.perm.WrWiki)
1194 || (zTNUuid && g.perm.Write && g.perm.WrWiki))
1195 ){
1196 form_begin(0, "%R/ainfo/%!S", zUuid);
1197 @ <p>Confirm you want to delete the attachment shown below.
1198 @ <input type="submit" name="confirm" value="Confirm">
1199 login_insert_csrf_secret();
@@ -1228,20 +1241,22 @@
1241 @ (%d(rid))
1242 }
1243 modPending = moderation_pending_www(rid);
1244 if( zForumPost ){
1245 @ <tr><th>Forum&nbsp;Post:</th>
1246 @ <td>%z(href("%R/forumpost/%s",zForumPost))%h(zForumPost)</a>\
1247 @ </td></tr>
1248 }else if( zTktUuid ){
1249 @ <tr><th>Ticket:</th>
1250 @ <td>%z(href("%R/tktview/%s",zTktUuid))%s(zTktUuid)</a></td></tr>
1251 }else if( zTNUuid ){
1252 @ <tr><th>Tech Note:</th>
1253 @ <td>%z(href("%R/technote/%s",zTNUuid))%s(zTNUuid)</a></td></tr>
1254 }else if( zWikiName ){
1255 @ <tr><th>Wiki&nbsp;Page:</th>
1256 @ <td>%z(href("%R/wiki?name=%t",zWikiName))%h(zWikiName)</a>\
1257 @ </td></tr>
1258 }
1259 @ <tr><th>Date:</th><td>
1260 hyperlink_to_date(zDate, "</td></tr>");
1261 @ <tr><th>User:</th><td>
1262 hyperlink_to_user(pAttach->zUser, zDate, "</td></tr>");
@@ -1252,11 +1267,12 @@
1267 }
1268 @ <tr><th>Filename:</th><td>%h(zName)</td></tr>
1269 if( g.perm.Setup ){
1270 @ <tr><th>MIME-Type:</th><td>%h(zMime)</td></tr>
1271 }
1272 @ <tr><th valign="top">Description:</th>\
1273 @ <td valign="top">%h(zDesc)</td></tr>
1274 @ </table>
1275
1276 if( modPending && (isModerator || bUserIsOwner) ){
1277 @ <div class="section">Moderation</div>
1278 @ <blockquote>
@@ -1263,18 +1279,19 @@
1279 form_begin(0, "%R/ainfo/%s", zUuid);
1280 @ <label><input type="radio" name="modaction" value="delete">
1281 @ Delete this attachment</label><br>
1282 if( isModerator ){
1283 #if 0
1284 /* TODO/FIXME (2026-06-03): only allow approval of an attachment
1285 ** if its target has been approved. Without this, we can end up
1286 ** with stale attachments which refer to rejected targets. We
1287 ** need a type-specific RID/UUID here, which requires
1288 ** refactoring above to get it. */
1289 const int tgtid = 0;
1290 if( moderation_pending(tgtid) ){
1291 @ <label><input type="radio" name="modaction" \
1292 @ disabled value="approve">
1293 @ <span class='modpending'>Cannot approve:
1294 @ target is pending moderation</span>\
1295 @ </label><br>
1296 }else
1297 #else
@@ -1301,11 +1318,12 @@
1318 const char *z;
1319 content_get(ridSrc, &attach);
1320 blob_to_utf8_no_bom(&attach, 0);
1321 z = blob_str(&attach);
1322 if( zLn ){
1323 output_text_with_line_numbers(z, blob_size(&attach),
1324 zName, zLn, 1);
1325 }else{
1326 @ <pre>
1327 @ %h(z)
1328 @ </pre>
1329 }
1330

Keyboard Shortcuts

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