summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--format.c16
-rw-r--r--html.c109
-rw-r--r--snac.h1
-rw-r--r--xs.h15
4 files changed, 82 insertions, 59 deletions
diff --git a/format.c b/format.c
index 482edce..4491ae0 100644
--- a/format.c
+++ b/format.c
@@ -238,3 +238,19 @@ xs_str *sanitize(const char *content)
238 238
239 return s; 239 return s;
240} 240}
241
242
243xs_str *encode_html(const char *str)
244/* escapes html characters */
245{
246 xs_str *encoded = xs_replace(str, "&", "&");
247 encoded = xs_replace_i(encoded, "<", "&lt;");
248 encoded = xs_replace_i(encoded, ">", "&gt;");
249 encoded = xs_replace_i(encoded, "\"", "&#34;");
250 encoded = xs_replace_i(encoded, "'", "&#39;");
251
252 /* Restore only <br>. Probably safe. Let's hope nothing goes wrong with this. */
253 encoded = xs_replace_i(encoded, "&lt;br&gt;", "<br>");
254
255 return encoded;
256}
diff --git a/html.c b/html.c
index 4541571..a88961e 100644
--- a/html.c
+++ b/html.c
@@ -52,7 +52,7 @@ xs_str *actor_name(xs_dict *actor)
52 } 52 }
53 } 53 }
54 54
55 name = xs_dup(v); 55 name = encode_html(v);
56 56
57 /* replace the :shortnames: */ 57 /* replace the :shortnames: */
58 if (!xs_is_null(p = xs_dict_get(actor, "tag"))) { 58 if (!xs_is_null(p = xs_dict_get(actor, "tag"))) {
@@ -105,7 +105,7 @@ xs_str *html_actor_icon(xs_str *os, char *actor,
105 105
106 { 106 {
107 xs *s1 = xs_fmt("<a href=\"%s\" class=\"p-author h-card snac-author\">%s</a>", 107 xs *s1 = xs_fmt("<a href=\"%s\" class=\"p-author h-card snac-author\">%s</a>",
108 xs_dict_get(actor, "id"), xs_encode_html(name)); 108 xs_dict_get(actor, "id"), name);
109 s = xs_str_cat(s, s1); 109 s = xs_str_cat(s, s1);
110 } 110 }
111 111
@@ -137,9 +137,11 @@ xs_str *html_actor_icon(xs_str *os, char *actor,
137 date_title = xs_str_cat(date_title, udate); 137 date_title = xs_str_cat(date_title, udate);
138 } 138 }
139 139
140 xs *edt = encode_html(date_title);
141 xs *edl = encode_html(date_label);
140 xs *s1 = xs_fmt( 142 xs *s1 = xs_fmt(
141 "\n<time class=\"dt-published snac-pubdate\" title=\"%s\">%s</time>\n", 143 "\n<time class=\"dt-published snac-pubdate\" title=\"%s\">%s</time>\n",
142 xs_encode_html(date_title), xs_encode_html(date_label)); 144 edt, edl);
143 145
144 s = xs_str_cat(s, s1); 146 s = xs_str_cat(s, s1);
145 } 147 }
@@ -162,9 +164,10 @@ xs_str *html_actor_icon(xs_str *os, char *actor,
162 xs *domain = xs_split(id, "/"); 164 xs *domain = xs_split(id, "/");
163 xs *user = xs_fmt("@%s@%s", username, xs_list_get(domain, 2)); 165 xs *user = xs_fmt("@%s@%s", username, xs_list_get(domain, 2));
164 166
167 xs *u1 = encode_html(user);
165 s1 = xs_fmt( 168 s1 = xs_fmt(
166 "<br><a href=\"%s\" class=\"p-author-tag h-card snac-author-tag\">%s</a>", 169 "<br><a href=\"%s\" class=\"p-author-tag h-card snac-author-tag\">%s</a>",
167 xs_dict_get(actor, "id"), xs_encode_html(user)); 170 xs_dict_get(actor, "id"), u1);
168 171
169 s = xs_str_cat(s, s1); 172 s = xs_str_cat(s, s1);
170 } 173 }
@@ -244,10 +247,10 @@ d_char *html_user_header(snac *snac, d_char *s, int local)
244 } 247 }
245 248
246 { 249 {
247 xs *s1 = xs_fmt("<title>%s (@%s@%s)</title>\n", 250 xs *es1 = encode_html(xs_dict_get(snac->config, "name"));
248 xs_encode_html(xs_dict_get(snac->config, "name")), 251 xs *es2 = encode_html(snac->uid);
249 xs_encode_html(snac->uid), 252 xs *es3 = encode_html(xs_dict_get(srv_config, "host"));
250 xs_encode_html(xs_dict_get(srv_config, "host"))); 253 xs *s1 = xs_fmt("<title>%s (@%s@%s)</title>\n", es1, es2, es3);
251 254
252 s = xs_str_cat(s, s1); 255 s = xs_str_cat(s, s1);
253 } 256 }
@@ -277,6 +280,13 @@ d_char *html_user_header(snac *snac, d_char *s, int local)
277 } 280 }
278 281
279 /* og properties */ 282 /* og properties */
283 xs *es1 = encode_html(xs_dict_get(srv_config, "host"));
284 xs *es2 = encode_html(xs_dict_get(snac->config, "name"));
285 xs *es3 = encode_html(snac->uid);
286 xs *es4 = encode_html(xs_dict_get(srv_config, "host"));
287 xs *es5 = encode_html(s_bio);
288 xs *es6 = encode_html(s_avatar);
289
280 xs *s1 = xs_fmt( 290 xs *s1 = xs_fmt(
281 "<meta property=\"og:site_name\" content=\"%s\"/>\n" 291 "<meta property=\"og:site_name\" content=\"%s\"/>\n"
282 "<meta property=\"og:title\" content=\"%s (@%s@%s)\"/>\n" 292 "<meta property=\"og:title\" content=\"%s (@%s@%s)\"/>\n"
@@ -284,12 +294,7 @@ d_char *html_user_header(snac *snac, d_char *s, int local)
284 "<meta property=\"og:image\" content=\"%s\"/>\n" 294 "<meta property=\"og:image\" content=\"%s\"/>\n"
285 "<meta property=\"og:image:width\" content=\"300\"/>\n" 295 "<meta property=\"og:image:width\" content=\"300\"/>\n"
286 "<meta property=\"og:image:height\" content=\"300\"/>\n", 296 "<meta property=\"og:image:height\" content=\"300\"/>\n",
287 xs_encode_html(xs_dict_get(srv_config, "host")), 297 es1, es2, es3, es4, es5, es6);
288 xs_encode_html(xs_dict_get(snac->config, "name")),
289 xs_encode_html(snac->uid),
290 xs_encode_html(xs_dict_get(srv_config, "host")),
291 xs_encode_html(s_bio),
292 xs_encode_html(s_avatar));
293 s = xs_str_cat(s, s1); 298 s = xs_str_cat(s, s1);
294 } 299 }
295 300
@@ -354,17 +359,19 @@ d_char *html_user_header(snac *snac, d_char *s, int local)
354 "<p class=\"p-name snac-top-user-name\">%s</p>\n" 359 "<p class=\"p-name snac-top-user-name\">%s</p>\n"
355 "<p class=\"snac-top-user-id\">@%s@%s</p>\n"; 360 "<p class=\"snac-top-user-id\">@%s@%s</p>\n";
356 361
357 xs *s1 = xs_fmt(_tmpl, 362 xs *es1 = encode_html(xs_dict_get(snac->config, "name"));
358 xs_encode_html(xs_dict_get(snac->config, "name")), 363 xs *es2 = encode_html(xs_dict_get(snac->config, "uid"));
359 xs_encode_html(xs_dict_get(snac->config, "uid")), xs_encode_html(xs_dict_get(srv_config, "host")) 364 xs *es3 = encode_html(xs_dict_get(srv_config, "host"));
360 ); 365
366 xs *s1 = xs_fmt(_tmpl, es1, es2, es3);
361 367
362 s = xs_str_cat(s, s1); 368 s = xs_str_cat(s, s1);
363 369
364 if (local) { 370 if (local) {
365 xs *bio1 = not_really_markdown(xs_encode_html(xs_dict_get(snac->config, "bio")), NULL); 371 xs *es1 = encode_html(xs_dict_get(snac->config, "bio"));
372 xs *bio1 = not_really_markdown(es1, NULL);
366 xs *tags = xs_list_new(); 373 xs *tags = xs_list_new();
367 xs *bio2 = xs_encode_html(process_tags(snac, bio1, &tags)); 374 xs *bio2 = encode_html(process_tags(snac, bio1, &tags));
368 xs *s1 = xs_fmt("<div class=\"p-note snac-top-user-bio\">%s</div>\n", bio2); 375 xs *s1 = xs_fmt("<div class=\"p-note snac-top-user-bio\">%s</div>\n", bio2);
369 376
370 s = xs_str_cat(s, s1); 377 s = xs_str_cat(s, s1);
@@ -911,10 +918,11 @@ xs_str *html_entry(snac *snac, xs_str *os, const xs_dict *msg, int local,
911 918
912 if (xs_list_in(boosts, snac->md5) != -1) { 919 if (xs_list_in(boosts, snac->md5) != -1) {
913 /* we boosted this */ 920 /* we boosted this */
921 xs *es1 = encode_html(xs_dict_get(snac->config, "name"));
914 xs *s1 = xs_fmt( 922 xs *s1 = xs_fmt(
915 "<div class=\"snac-origin\">" 923 "<div class=\"snac-origin\">"
916 "<a href=\"%s\">%s</a> %s</a></div>", 924 "<a href=\"%s\">%s</a> %s</a></div>",
917 snac->actor, xs_encode_html(xs_dict_get(snac->config, "name")), L("boosted") 925 snac->actor, es1, L("boosted")
918 ); 926 );
919 927
920 s = xs_str_cat(s, s1); 928 s = xs_str_cat(s, s1);
@@ -928,7 +936,7 @@ xs_str *html_entry(snac *snac, xs_str *os, const xs_dict *msg, int local,
928 "<div class=\"snac-origin\">" 936 "<div class=\"snac-origin\">"
929 "<a href=\"%s\">%s</a> %s</div>\n", 937 "<a href=\"%s\">%s</a> %s</div>\n",
930 xs_dict_get(actor_r, "id"), 938 xs_dict_get(actor_r, "id"),
931 xs_encode_html(name), 939 name,
932 L("boosted") 940 L("boosted")
933 ); 941 );
934 942
@@ -967,7 +975,8 @@ xs_str *html_entry(snac *snac, xs_str *os, const xs_dict *msg, int local,
967 char *cw = xs_dict_get(snac->config, "cw"); 975 char *cw = xs_dict_get(snac->config, "cw");
968 if (xs_is_null(cw) || local) 976 if (xs_is_null(cw) || local)
969 cw = ""; 977 cw = "";
970 xs *s1 = xs_fmt("<details %s><summary>%s [%s]</summary>\n", cw, xs_encode_html(v), L("SENSITIVE CONTENT")); 978 xs *es1 = encode_html(v);
979 xs *s1 = xs_fmt("<details %s><summary>%s [%s]</summary>\n", cw, es1, L("SENSITIVE CONTENT"));
971 s = xs_str_cat(s, s1); 980 s = xs_str_cat(s, s1);
972 sensitive = 1; 981 sensitive = 1;
973 } 982 }
@@ -1049,7 +1058,8 @@ xs_str *html_entry(snac *snac, xs_str *os, const xs_dict *msg, int local,
1049 1058
1050 if (name && replies) { 1059 if (name && replies) {
1051 int nr = xs_number_get(xs_dict_get(replies, "totalItems")); 1060 int nr = xs_number_get(xs_dict_get(replies, "totalItems"));
1052 xs *l = xs_fmt("<tr><td>%s:</td><td>%d</td></tr>\n", xs_encode_html(name), nr); 1061 xs *es1 = encode_html(name);
1062 xs *l = xs_fmt("<tr><td>%s:</td><td>%d</td></tr>\n", es1, nr);
1053 1063
1054 c = xs_str_cat(c, l); 1064 c = xs_str_cat(c, l);
1055 } 1065 }
@@ -1070,10 +1080,11 @@ xs_str *html_entry(snac *snac, xs_str *os, const xs_dict *msg, int local,
1070 const char *name = xs_dict_get(v, "name"); 1080 const char *name = xs_dict_get(v, "name");
1071 1081
1072 if (name) { 1082 if (name) {
1083 xs *es1 = encode_html(name);
1073 xs *opt = xs_fmt("<input type=\"%s\"" 1084 xs *opt = xs_fmt("<input type=\"%s\""
1074 " id=\"%s\" value=\"%s\" name=\"question\"> %s<br>\n", 1085 " id=\"%s\" value=\"%s\" name=\"question\"> %s<br>\n",
1075 !xs_is_null(oo) ? "radio" : "checkbox", 1086 !xs_is_null(oo) ? "radio" : "checkbox",
1076 xs_encode_html(name), xs_encode_html(name), xs_encode_html(name)); 1087 es1, es1, es1);
1077 1088
1078 s1 = xs_str_cat(s1, opt); 1089 s1 = xs_str_cat(s1, opt);
1079 } 1090 }
@@ -1107,7 +1118,8 @@ xs_str *html_entry(snac *snac, xs_str *os, const xs_dict *msg, int local,
1107 /* skip leading zeros */ 1118 /* skip leading zeros */
1108 for (; *p == '0' || *p == ':'; p++); 1119 for (; *p == '0' || *p == ':'; p++);
1109 1120
1110 xs *s1 = xs_fmt("<p>%s %s</p>", L("Closes in"), xs_encode_html(p)); 1121 xs *es1 = encode_html(p);
1122 xs *s1 = xs_fmt("<p>%s %s</p>", L("Closes in"), es1);
1111 c = xs_str_cat(c, s1); 1123 c = xs_str_cat(c, s1);
1112 } 1124 }
1113 } 1125 }
@@ -1135,8 +1147,8 @@ xs_str *html_entry(snac *snac, xs_str *os, const xs_dict *msg, int local,
1135 continue; 1147 continue;
1136 1148
1137 if (xs_startswith(t, "image/")) { 1149 if (xs_startswith(t, "image/")) {
1138 char *url = xs_dict_get(v, "url"); 1150 char *url = xs_dict_get(v, "url");
1139 char *name = xs_encode_html(xs_dict_get(v, "name")); 1151 xs *name = encode_html(xs_dict_get(v, "name"));
1140 1152
1141 if (url != NULL) { 1153 if (url != NULL) {
1142 if (xs_is_null(name)) 1154 if (xs_is_null(name))
@@ -1150,8 +1162,8 @@ xs_str *html_entry(snac *snac, xs_str *os, const xs_dict *msg, int local,
1150 } 1162 }
1151 else 1163 else
1152 if (xs_startswith(t, "video/")) { 1164 if (xs_startswith(t, "video/")) {
1153 char *url = xs_dict_get(v, "url"); 1165 char *url = xs_dict_get(v, "url");
1154 char *name = xs_encode_html(xs_dict_get(v, "name")); 1166 xs *name = encode_html(xs_dict_get(v, "name"));
1155 1167
1156 if (url != NULL) { 1168 if (url != NULL) {
1157 xs *s1 = xs_fmt("<video style=\"max-width: 90vw; max-height: 70vh;\" controls src=\"%s\">Video: <a href=\"%s\">%s</a></video>\n", url, url, name ? name : "No description."); 1169 xs *s1 = xs_fmt("<video style=\"max-width: 90vw; max-height: 70vh;\" controls src=\"%s\">Video: <a href=\"%s\">%s</a></video>\n", url, url, name ? name : "No description.");
@@ -1161,8 +1173,8 @@ xs_str *html_entry(snac *snac, xs_str *os, const xs_dict *msg, int local,
1161 } 1173 }
1162 else 1174 else
1163 if (xs_startswith(t, "audio/")) { 1175 if (xs_startswith(t, "audio/")) {
1164 char *url = xs_dict_get(v, "url"); 1176 char *url = xs_dict_get(v, "url");
1165 char *name = xs_encode_html(xs_dict_get(v, "name")); 1177 xs *name = encode_html(xs_dict_get(v, "name"));
1166 1178
1167 if (url != NULL) { 1179 if (url != NULL) {
1168 xs *s1 = xs_fmt("<audio style=\"max-width: 90vw\" controls src=\"%s\">Audio: <a href=\"%s\">%s</a></audio>\n", url, url, name ? name : "No description."); 1180 xs *s1 = xs_fmt("<audio style=\"max-width: 90vw\" controls src=\"%s\">Audio: <a href=\"%s\">%s</a></audio>\n", url, url, name ? name : "No description.");
@@ -1171,8 +1183,8 @@ xs_str *html_entry(snac *snac, xs_str *os, const xs_dict *msg, int local,
1171 } 1183 }
1172 } 1184 }
1173 else { 1185 else {
1174 char *url = xs_dict_get(v, "url"); 1186 char *url = xs_dict_get(v, "url");
1175 char *name = xs_encode_html(xs_dict_get(v, "name")); 1187 xs *name = encode_html(xs_dict_get(v, "name"));
1176 1188
1177 if (url != NULL) { 1189 if (url != NULL) {
1178 xs *s1 = xs_fmt("<a href=\"%s\">Attachment: %s</a>", url, name ? name : "No description"); 1190 xs *s1 = xs_fmt("<a href=\"%s\">Attachment: %s</a>", url, name ? name : "No description");
@@ -1349,7 +1361,8 @@ xs_str *html_timeline(snac *snac, const xs_list *list, int local, int skip, int
1349d_char *html_people_list(snac *snac, d_char *os, d_char *list, const char *header, const char *t) 1361d_char *html_people_list(snac *snac, d_char *os, d_char *list, const char *header, const char *t)
1350{ 1362{
1351 xs *s = xs_str_new(NULL); 1363 xs *s = xs_str_new(NULL);
1352 xs *h = xs_fmt("<h2 class=\"snac-header\">%s</h2>\n", xs_encode_html(header)); 1364 xs *es1 = encode_html(header);
1365 xs *h = xs_fmt("<h2 class=\"snac-header\">%s</h2>\n", es1);
1353 char *p, *actor_id; 1366 char *p, *actor_id;
1354 1367
1355 s = xs_str_cat(s, h); 1368 s = xs_str_cat(s, h);
@@ -1379,7 +1392,8 @@ d_char *html_people_list(snac *snac, d_char *os, d_char *list, const char *heade
1379 if (xs_startswith(sc, "<p>")) 1392 if (xs_startswith(sc, "<p>"))
1380 s = xs_str_cat(s, sc); 1393 s = xs_str_cat(s, sc);
1381 else { 1394 else {
1382 xs *s1 = xs_fmt("<p>%s</p>", xs_encode_html(sc)); 1395 xs *es1 = encode_html(sc);
1396 xs *s1 = xs_fmt("<p>%s</p>", es1);
1383 s = xs_str_cat(s, s1); 1397 s = xs_str_cat(s, s1);
1384 } 1398 }
1385 1399
@@ -1549,9 +1563,10 @@ xs_str *html_notifications(snac *snac)
1549 if (strcmp(type, "Undo") == 0 && strcmp(utype, "Follow") == 0) 1563 if (strcmp(type, "Undo") == 0 && strcmp(utype, "Follow") == 0)
1550 label = L("Unfollow"); 1564 label = L("Unfollow");
1551 1565
1566 xs *es1 = encode_html(label);
1552 xs *s1 = xs_fmt("<div class=\"snac-post-with-desc\">\n" 1567 xs *s1 = xs_fmt("<div class=\"snac-post-with-desc\">\n"
1553 "<p><b>%s by <a href=\"%s\">%s</a></b>:</p>\n", 1568 "<p><b>%s by <a href=\"%s\">%s</a></b>:</p>\n",
1554 xs_encode_html(label), actor_id, xs_encode_html(a_name)); 1569 es1, actor_id, a_name);
1555 s = xs_str_cat(s, s1); 1570 s = xs_str_cat(s, s1);
1556 1571
1557 if (strcmp(type, "Follow") == 0 || strcmp(utype, "Follow") == 0) { 1572 if (strcmp(type, "Follow") == 0 || strcmp(utype, "Follow") == 0) {
@@ -1776,7 +1791,10 @@ int html_get_handler(const xs_dict *req, const char *q_path,
1776 xs *bio = not_really_markdown(xs_dict_get(snac.config, "bio"), NULL); 1791 xs *bio = not_really_markdown(xs_dict_get(snac.config, "bio"), NULL);
1777 char *p, *v; 1792 char *p, *v;
1778 1793
1779 1794 xs *es1 = encode_html(xs_dict_get(snac.config, "name"));
1795 xs *es2 = encode_html(snac.uid);
1796 xs *es3 = encode_html(xs_dict_get(srv_config, "host"));
1797 xs *es4 = encode_html(bio);
1780 rss = xs_fmt( 1798 rss = xs_fmt(
1781 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" 1799 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1782 "<rss version=\"0.91\">\n" 1800 "<rss version=\"0.91\">\n"
@@ -1785,11 +1803,11 @@ int html_get_handler(const xs_dict *req, const char *q_path,
1785 "<language>en</language>\n" 1803 "<language>en</language>\n"
1786 "<link>%s.rss</link>\n" 1804 "<link>%s.rss</link>\n"
1787 "<description>%s</description>\n", 1805 "<description>%s</description>\n",
1788 xs_encode_html(xs_dict_get(snac.config, "name")), 1806 es1,
1789 xs_encode_html(snac.uid), 1807 es2,
1790 xs_encode_html(xs_dict_get(srv_config, "host")), 1808 es3,
1791 snac.actor, 1809 snac.actor,
1792 xs_encode_html(bio) 1810 es4
1793 ); 1811 );
1794 1812
1795 p = elems; 1813 p = elems;
@@ -1804,20 +1822,23 @@ int html_get_handler(const xs_dict *req, const char *q_path,
1804 if (!xs_startswith(id, snac.actor)) 1822 if (!xs_startswith(id, snac.actor))
1805 continue; 1823 continue;
1806 1824
1807 xs *content = xs_encode_html(sanitize(xs_dict_get(msg, "content"))); 1825 xs *es1 = sanitize(xs_dict_get(msg, "content"));
1826 xs *content = encode_html(es1);
1808 xs *title = xs_str_new(NULL); 1827 xs *title = xs_str_new(NULL);
1809 int i; 1828 int i;
1810 1829
1811 for (i = 0; content[i] && content[i] != '<' && content[i] != '&' && i < 40; i++) 1830 for (i = 0; content[i] && content[i] != '<' && content[i] != '&' && i < 40; i++)
1812 title = xs_append_m(title, &content[i], 1); 1831 title = xs_append_m(title, &content[i], 1);
1813 1832
1833 xs *es11 = encode_html(title);
1834 xs *es12 = encode_html(content);
1814 xs *s = xs_fmt( 1835 xs *s = xs_fmt(
1815 "<item>\n" 1836 "<item>\n"
1816 "<title>%s...</title>\n" 1837 "<title>%s...</title>\n"
1817 "<link>%s</link>\n" 1838 "<link>%s</link>\n"
1818 "<description>%s</description>\n" 1839 "<description>%s</description>\n"
1819 "</item>\n", 1840 "</item>\n",
1820 xs_encode_html(title), id, xs_encode_html(content) 1841 es11, id, es12
1821 ); 1842 );
1822 1843
1823 rss = xs_str_cat(rss, s); 1844 rss = xs_str_cat(rss, s);
diff --git a/snac.h b/snac.h
index af6c912..9ba332c 100644
--- a/snac.h
+++ b/snac.h
@@ -251,6 +251,7 @@ int activitypub_post_handler(const xs_dict *req, const char *q_path,
251 251
252xs_str *not_really_markdown(const char *content, xs_list **attach); 252xs_str *not_really_markdown(const char *content, xs_list **attach);
253xs_str *sanitize(const char *content); 253xs_str *sanitize(const char *content);
254xs_str *encode_html(const char *str);
254 255
255int html_get_handler(const xs_dict *req, const char *q_path, 256int html_get_handler(const xs_dict *req, const char *q_path,
256 char **body, int *b_size, char **ctype, xs_str **etag); 257 char **body, int *b_size, char **ctype, xs_str **etag);
diff --git a/xs.h b/xs.h
index 6bf3eb8..ad8a35d 100644
--- a/xs.h
+++ b/xs.h
@@ -72,7 +72,6 @@ xs_str *xs_replace_in(xs_str *str, const char *sfrom, const char *sto, int times
72xs_str *xs_fmt(const char *fmt, ...); 72xs_str *xs_fmt(const char *fmt, ...);
73int xs_str_in(const char *haystack, const char *needle); 73int xs_str_in(const char *haystack, const char *needle);
74int _xs_startsorends(const char *str, const char *xfix, int ends); 74int _xs_startsorends(const char *str, const char *xfix, int ends);
75xs_str *xs_encode_html(const xs_str *str);
76#define xs_startswith(str, prefix) _xs_startsorends(str, prefix, 0) 75#define xs_startswith(str, prefix) _xs_startsorends(str, prefix, 0)
77#define xs_endswith(str, postfix) _xs_startsorends(str, postfix, 1) 76#define xs_endswith(str, postfix) _xs_startsorends(str, postfix, 1)
78xs_str *xs_crop_i(xs_str *str, int start, int end); 77xs_str *xs_crop_i(xs_str *str, int start, int end);
@@ -507,20 +506,6 @@ int _xs_startsorends(const char *str, const char *xfix, int ends)
507 return !!(ssz >= psz && memcmp(xfix, str + (ends ? ssz - psz : 0), psz) == 0); 506 return !!(ssz >= psz && memcmp(xfix, str + (ends ? ssz - psz : 0), psz) == 0);
508} 507}
509 508
510xs_str *xs_encode_html(const char *str)
511/* escapes html characters */
512{
513 xs_str *encoded = xs_replace(str, "&", "&amp;");
514 encoded = xs_replace(encoded, "<", "&lt;");
515 encoded = xs_replace(encoded, ">", "&gt;");
516 encoded = xs_replace(encoded, "\"", "&#34;");
517 encoded = xs_replace(encoded, "'", "&#39;");
518
519 // Restore only <br>. Probably safe. Let's hope nothing goes wrong with this.
520 encoded = xs_replace(encoded, "&lt;br&gt;", "<br>");
521
522 return encoded;
523}
524 509
525xs_str *xs_crop_i(xs_str *str, int start, int end) 510xs_str *xs_crop_i(xs_str *str, int start, int end)
526/* crops the d_char to be only from start to end */ 511/* crops the d_char to be only from start to end */