commit 6ede649
default
·
2023-08-17 15:38:39 +0000 UTC
parent b3b4a4e
Convert 'Link' attachments that have a media extension to something more useful.
5 files changed,
+112,
-51
M
html.c
+10,
-0
1@@ -1313,6 +1313,16 @@ xs_str *html_entry(snac *user, xs_str *os, const xs_dict *msg, int local,
2 if (xs_is_null(url))
3 continue;
4
5+ /* if it's a plain Link, check if it can be "rewritten" */
6+ if (strcmp(t, "Link") == 0) {
7+ const char *mt = xs_mime_by_ext(url);
8+
9+ if (xs_startswith(mt, "image/") ||
10+ xs_startswith(mt, "audio/") ||
11+ xs_startswith(mt, "video/"))
12+ t = mt;
13+ }
14+
15 const char *name = xs_dict_get(v, "name");
16 if (xs_is_null(name))
17 name = xs_dict_get(msg, "name");
+50,
-40
1@@ -6,57 +6,67 @@
2
3 const char *xs_mime_by_ext(const char *file);
4
5+extern const char *xs_mime_types[];
6+
7 #ifdef XS_IMPLEMENTATION
8
9 /* intentionally brain-dead simple */
10-struct _mime_info {
11- const char *type;
12- const char *ext;
13-} mime_info[] = {
14- { "application/json", ".json" },
15- { "image/gif", ".gif" },
16- { "image/jpeg", ".jpeg" },
17- { "image/jpeg", ".jpg" },
18- { "image/png", ".png" },
19- { "image/webp", ".webp" },
20- { "video/mp4", ".mp4" },
21- { "video/mp4", ".mpg4" },
22- { "video/mp4", ".m4v" },
23- { "video/webm", ".webm" },
24- { "video/quicktime", ".mov" },
25- { "video/3gpp", ".3gp" },
26- { "video/ogg", ".ogv" },
27- { "video/flv", ".flv" },
28- { "audio/mp3", ".mp3" },
29- { "audio/ogg", ".ogg" },
30- { "audio/ogg", ".oga" },
31- { "audio/ogg", ".opus" },
32- { "audio/flac", ".flac" },
33- { "audio/wav", ".wav" },
34- { "audio/wma", ".wma" },
35- { "audio/aac", ".aac" },
36- { "audio/aac", ".m4a" },
37- { "text/css", ".css" },
38- { "text/html", ".html" },
39- { "text/plain", ".txt" },
40- { "text/xml", ".xml" },
41- { "text/markdown", ".md" },
42- { "text/gemini", ".gmi" },
43- { NULL, NULL }
44+/* CAUTION: sorted */
45+
46+const char *xs_mime_types[] = {
47+ "3gp", "video/3gpp",
48+ "aac", "audio/aac",
49+ "css", "text/css",
50+ "flac", "audio/flac",
51+ "flv", "video/flv",
52+ "gif", "image/gif",
53+ "gmi", "text/gemini",
54+ "html", "text/html",
55+ "jpeg", "image/jpeg",
56+ "jpg", "image/jpeg",
57+ "json", "application/json",
58+ "m4a", "audio/aac",
59+ "m4v", "video/mp4",
60+ "md", "text/markdown",
61+ "mov", "video/quicktime",
62+ "mp3", "audio/mp3",
63+ "mp4", "video/mp4",
64+ "mpg4", "video/mp4",
65+ "oga", "audio/ogg",
66+ "ogg", "audio/ogg",
67+ "ogv", "video/ogg",
68+ "opus", "audio/ogg",
69+ "png", "image/png",
70+ "txt", "text/plain",
71+ "wav", "audio/wav",
72+ "webm", "video/webm",
73+ "webp", "image/webp",
74+ "wma", "audio/wma",
75+ "xml", "text/xml",
76+ NULL, NULL,
77 };
78
79
80 const char *xs_mime_by_ext(const char *file)
81 /* returns the MIME type by file extension */
82 {
83- struct _mime_info *mi = mime_info;
84- xs *lfile = xs_tolower_i(xs_dup(file));
85+ const char *ext = strrchr(file, '.');
86+
87+ if (ext) {
88+ const char **p = xs_mime_types;
89+ xs *uext = xs_tolower_i(xs_dup(ext + 1));
90+
91+ while (**p) {
92+ int c;
93
94- while (mi->type != NULL) {
95- if (xs_endswith(lfile, mi->ext))
96- return mi->type;
97+ if ((c = strcmp(*p, uext)) == 0)
98+ return p[1];
99+ else
100+ if (c > 0)
101+ break;
102
103- mi++;
104+ p += 2;
105+ }
106 }
107
108 return "application/octet-stream";
+7,
-3
1@@ -8,8 +8,10 @@ xs_list *xs_regex_split_n(const char *str, const char *rx, int count);
2 #define xs_regex_split(str, rx) xs_regex_split_n(str, rx, XS_ALL)
3 xs_list *xs_regex_match_n(const char *str, const char *rx, int count);
4 #define xs_regex_match(str, rx) xs_regex_match_n(str, rx, XS_ALL)
5-xs_list *xs_regex_replace_n(const char *str, const char *rx, const char *rep, int count);
6-#define xs_regex_replace(str, rx, rep) xs_regex_replace_n(str, rx, rep, XS_ALL)
7+xs_list *xs_regex_replace_in(xs_str *str, const char *rx, const char *rep, int count);
8+#define xs_regex_replace_i(str, rx, rep) xs_regex_replace_in(str, rx, rep, XS_ALL)
9+#define xs_regex_replace_n(str, rx, rep, count) xs_regex_replace_in(xs_dup(str), rx, rep, count)
10+#define xs_regex_replace(str, rx, rep) xs_regex_replace_in(xs_dup(str), rx, rep, XS_ALL)
11
12 #ifdef XS_IMPLEMENTATION
13
14@@ -78,7 +80,7 @@ xs_list *xs_regex_match_n(const char *str, const char *rx, int count)
15 }
16
17
18-xs_list *xs_regex_replace_n(const char *str, const char *rx, const char *rep, int count)
19+xs_list *xs_regex_replace_in(xs_str *str, const char *rx, const char *rep, int count)
20 /* replaces all matches with the rep string. If it contains unescaped &,
21 they are replaced with the match */
22 {
23@@ -121,6 +123,8 @@ xs_list *xs_regex_replace_n(const char *str, const char *rx, const char *rep, in
24 n++;
25 }
26
27+ xs_free(str);
28+
29 return s;
30 }
31
+44,
-7
1@@ -4,8 +4,10 @@
2
3 #define _XS_UNICODE_H
4
5+ int _xs_utf8_enc(char buf[4], unsigned int cpoint);
6 xs_str *xs_utf8_enc(xs_str *str, unsigned int cpoint);
7 unsigned int xs_utf8_dec(char **str);
8+ int xs_unicode_width(unsigned int cpoint);
9 unsigned int *_xs_unicode_upper_search(unsigned int cpoint);
10 unsigned int *_xs_unicode_lower_search(unsigned int cpoint);
11 #define xs_unicode_is_upper(cpoint) (!!_xs_unicode_upper_search(cpoint))
12@@ -18,8 +20,8 @@
13 #ifdef XS_IMPLEMENTATION
14
15
16-char *_xs_utf8_enc(char buf[4], unsigned int cpoint)
17-/* encodes an Unicode codepoint to utf-8 into buf and returns the new position */
18+int _xs_utf8_enc(char buf[4], unsigned int cpoint)
19+/* encodes an Unicode codepoint to utf-8 into buf and returns the size in bytes */
20 {
21 unsigned char *p = (unsigned char *)buf;
22
23@@ -42,18 +44,18 @@ char *_xs_utf8_enc(char buf[4], unsigned int cpoint)
24 *p++ = 0x80 | (cpoint & 0x3f);
25 }
26
27- return (char *)p;
28+ return p - (unsigned char *)buf;
29 }
30
31
32 xs_str *xs_utf8_enc(xs_str *str, unsigned int cpoint)
33 /* encodes an Unicode codepoint to utf-8 into str */
34 {
35- char tmp[4], *p;
36+ char tmp[4];
37
38- p = _xs_utf8_enc(tmp, cpoint);
39+ int c = _xs_utf8_enc(tmp, cpoint);
40
41- return xs_append_m(str, tmp, p - tmp);
42+ return xs_append_m(str, tmp, c);
43 }
44
45
46@@ -99,9 +101,44 @@ unsigned int xs_utf8_dec(char **str)
47 }
48
49
50+/* intentionally dead simple */
51+
52+static unsigned int xs_unicode_width_table[] = {
53+ 0x300, 0x36f, 0, /* diacritics */
54+ 0x1100, 0x11ff, 2, /* Hangul */
55+ 0x2e80, 0xa4cf, 2, /* CJK */
56+ 0xac00, 0xd7a3, 2, /* more Hangul */
57+ 0xe000, 0xf8ff, 0, /* private use */
58+ 0xf900, 0xfaff, 2, /* CJK compatibility */
59+ 0xff00, 0xff60, 2, /* full width things */
60+ 0xffdf, 0xffe6, 2, /* full width things */
61+ 0x1f200, 0x1ffff, 2, /* emojis */
62+ 0x20000, 0x2fffd, 2 /* more CJK */
63+};
64+
65+int xs_unicode_width(unsigned int cpoint)
66+/* returns the width in columns of a Unicode codepoint (somewhat simplified) */
67+{
68+ unsigned int *p = xs_unicode_width_table;
69+ unsigned int *e = p + sizeof(xs_unicode_width_table) / sizeof(unsigned int);
70+
71+ while (p < e) {
72+ if (cpoint < p[0])
73+ return 1;
74+
75+ if (cpoint >= p[0] && cpoint <= p[1])
76+ return p[2];
77+
78+ p += 3;
79+ }
80+
81+ return 0;
82+}
83+
84+
85 #ifdef _XS_UNICODE_TBL_H
86
87-/* include xs_unicode_tbl.h before to use these functions */
88+/* include xs_unicode_tbl.h before this one to use these functions */
89
90 static int int_cmp(const void *p1, const void *p2)
91 {
+1,
-1
1@@ -1 +1 @@
2-/* b7e9713d90382d8da0b58023f4c78416e6ca1bc5 */
3+/* e85f257dd8fcb2980fd21aa37c1594c1461ddf48 */