summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pttbbs/daemon/boardd/boardd.c79
1 files changed, 78 insertions, 1 deletions
diff --git a/pttbbs/daemon/boardd/boardd.c b/pttbbs/daemon/boardd/boardd.c
index 8bda7c82..9256e262 100644
--- a/pttbbs/daemon/boardd/boardd.c
+++ b/pttbbs/daemon/boardd/boardd.c
@@ -10,7 +10,7 @@
// 3. [done] split out independent server code
// 4. [done] add article list support
// 5. [done] add article content support
-// 6. encode output in UTF-8 (with UAO support)
+// 6. [done] encode output in UTF-8 (with UAO support)
// 7. encode article list in JSON for better structure
#include <stdlib.h>
@@ -28,6 +28,8 @@
#include "server.h"
+#define CONVERT_TO_UTF8
+
#define DEFAULT_ARTICLE_LIST 20
// helper function
@@ -254,3 +256,78 @@ setup_program()
attach_SHM();
}
+#ifdef CONVERT_TO_UTF8
+
+enum bufferevent_filter_result
+filter_pass(struct evbuffer *source, struct evbuffer *destination,
+ ev_ssize_t dst_limit, enum bufferevent_flush_mode mode, void *ctx)
+{
+ int len = evbuffer_get_length(source);
+
+ if (len == 0)
+ return BEV_NEED_MORE;
+
+ len = evbuffer_remove_buffer(source, destination, dst_limit >= 0 ? dst_limit : len);
+
+ return len > 0 ? BEV_OK : (len == 0 ? BEV_NEED_MORE : BEV_ERROR);
+}
+
+enum bufferevent_filter_result
+filter_b2u(struct evbuffer *source, struct evbuffer *destination,
+ ev_ssize_t dst_limit, enum bufferevent_flush_mode mode, void *ctx)
+{
+ char c[2];
+ int out = 0;
+
+ while (evbuffer_copyout(source, c, 1) > 0) {
+ if (isascii(c[0])) {
+ if (dst_limit > 0 && out >= dst_limit)
+ break;
+
+ if (evbuffer_add(destination, c, 1) < 0)
+ return BEV_ERROR;
+ evbuffer_drain(source, 1);
+ out++;
+ } else {
+ // Big5
+ if (dst_limit > 0 && (out + 1) >= dst_limit)
+ break;
+
+ // c must be little endian.
+ c[1] = c[0];
+
+ // Get second byte
+ if (evbuffer_copyout(source, c, 1) <= 0)
+ break;
+
+ uint16_t ucs = b2u_table[*(uint16_t*)c];
+ uint8_t utf8[4];
+
+ int len = ucs2utf(ucs, utf8);
+ utf8[len] = 0;
+
+ if (evbuffer_add(destination, utf8, len) < 0)
+ return BEV_ERROR;
+ evbuffer_drain(source, 2);
+ out += len;
+ }
+ }
+
+ return out ? BEV_OK : BEV_NEED_MORE;
+}
+
+void
+setup_client(struct event_base *base, evutil_socket_t fd,
+ struct sockaddr *address, int socklen)
+{
+ struct bufferevent *bev = bufferevent_socket_new(base, fd,
+ BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS);
+ struct bufferevent *bev2 = bufferevent_filter_new(bev, filter_b2u,
+ filter_pass, BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS,
+ NULL, NULL);
+ bufferevent_setcb(bev2, client_read_cb, NULL, client_event_cb, NULL);
+ bufferevent_set_timeouts(bev2, common_timeout, common_timeout);
+ bufferevent_enable(bev2, EV_READ|EV_WRITE);
+}
+
+#endif // CONVERT_TO_UTF8