From b3e94c4e7ce62a34a52cc51f74e1635b9d6c18fe Mon Sep 17 00:00:00 2001 From: rswindell <> Date: Sat, 17 Aug 2019 02:21:01 +0000 Subject: [PATCH] New QWK setting: Include UTF-8 chars. When off/false (the default), UTF-8 characters in message headers and body text will be converted to CP437. Also include a new field in HEADERS.DAT: utf8 = true/false to indicate that the message headers and body text contain UTF-8 encoding (not CP437). --- src/sbbs3/getmsg.cpp | 2 +- src/sbbs3/msgtoqwk.cpp | 48 +++++++++++++++++++++++++++------------ src/sbbs3/pack_qwk.cpp | 3 +-- src/sbbs3/pack_rep.cpp | 4 ++-- src/sbbs3/postmsg.cpp | 8 +++---- src/sbbs3/qwk.cpp | 7 +++++- src/sbbs3/qwk.h | 1 + src/sbbs3/sbbsdefs.h | 2 ++ src/sbbs3/text.h | 1 + src/sbbs3/text_defaults.c | 8 ++++--- 10 files changed, 56 insertions(+), 28 deletions(-) diff --git a/src/sbbs3/getmsg.cpp b/src/sbbs3/getmsg.cpp index d486132735..9113a13cfc 100644 --- a/src/sbbs3/getmsg.cpp +++ b/src/sbbs3/getmsg.cpp @@ -139,7 +139,7 @@ const char* sbbs_t::msghdr_field(const smbmsg_t* msg, const char* str, char* buf if(msg == NULL || !(msg->hdr.auxattr & MSG_HFIELDS_UTF8)) return str; - if(can_utf8 && term_supports(UTF8)) + if(can_utf8) return str; if(buf == NULL) diff --git a/src/sbbs3/msgtoqwk.cpp b/src/sbbs3/msgtoqwk.cpp index 563b93ac48..67c8049da7 100644 --- a/src/sbbs3/msgtoqwk.cpp +++ b/src/sbbs3/msgtoqwk.cpp @@ -35,6 +35,7 @@ #include "sbbs.h" #include "qwk.h" +#include "utf8.h" #define MAX_MSGNUM 0x7FFFFFUL // only 7 (decimal) digits allowed for msg num @@ -46,7 +47,10 @@ ulong sbbs_t::msgtoqwk(smbmsg_t* msg, FILE *qwk_fp, long mode, smb_t* smb , int conf, FILE* hdrs, FILE* voting) { - char str[512],from[512],to[512],ch=0,tear=0,tearwatch=0,*buf,*p; + char str[512],ch=0,tear=0,tearwatch=0,*buf,*p; + char to[512] = ""; + char from[512] = ""; + char subj[512] = ""; char msgid[256]; char reply_id[256]; char tmp[512]; @@ -61,6 +65,13 @@ ulong sbbs_t::msgtoqwk(smbmsg_t* msg, FILE *qwk_fp, long mode, smb_t* smb get_msgid(&cfg, subnum, msg, msgid, sizeof(msgid)); offset=(long)ftell(qwk_fp); + if(msg->to != NULL) + SAFECOPY(to, msghdr_field(msg, msg->to, NULL, mode&QM_UTF8)); + if(msg->from != NULL) + SAFECOPY(from, msghdr_field(msg, msg->from, NULL, mode&QM_UTF8)); + if(msg->subj != NULL) + SAFECOPY(subj, msghdr_field(msg, msg->subj, NULL, mode&QM_UTF8)); + if(msg->hdr.type != SMB_MSG_TYPE_NORMAL) { if(voting == NULL) return 0; @@ -78,6 +89,8 @@ ulong sbbs_t::msgtoqwk(smbmsg_t* msg, FILE *qwk_fp, long mode, smb_t* smb unsigned comments = 0; unsigned answers = 0; fprintf(voting, "[poll:%s]\n", msgid); + fprintf(voting , "Utf8 = %s\n" + ,((msg->hdr.auxattr & MSG_HFIELDS_UTF8) && (mode&QM_UTF8)) ? "true" : "false"); if(msg->hdr.votes) fprintf(voting, "MaxVotes = %hd\n", msg->hdr.votes); if(msg->hdr.auxattr&POLL_RESULTS_MASK) @@ -94,8 +107,8 @@ ulong sbbs_t::msgtoqwk(smbmsg_t* msg, FILE *qwk_fp, long mode, smb_t* smb fprintf(voting, "[close:%s]\n", msgid); break; } - if(msg->subj && *msg->subj) - fprintf(voting, "%s: %s\n",smb_hfieldtype(SUBJECT), msg->subj); + if(subj[0]) + fprintf(voting, "%s: %s\n",smb_hfieldtype(SUBJECT), subj); if((p = get_replyid(&cfg, smb, msg, reply_id, sizeof(reply_id))) != NULL) fprintf(voting, "%s: %s\n", smb_hfieldtype(RFC822REPLYID), p); /* Time/Date/Zone info */ @@ -108,7 +121,7 @@ ulong sbbs_t::msgtoqwk(smbmsg_t* msg, FILE *qwk_fp, long mode, smb_t* smb ); /* SENDER */ - fprintf(voting, "%s: %s\n", smb_hfieldtype(SENDER), msg->from); + fprintf(voting, "%s: %s\n", smb_hfieldtype(SENDER), from); if(msg->from_net.type) fprintf(voting, "%s: %s\n", smb_hfieldtype(SENDERNETADDR), smb_netaddrstr(&msg->from_net, tmp)); fprintf(voting, "Conference: %u\n", conf); @@ -117,6 +130,10 @@ ulong sbbs_t::msgtoqwk(smbmsg_t* msg, FILE *qwk_fp, long mode, smb_t* smb else if(hdrs!=NULL) { fprintf(hdrs,"[%lx]\n",offset); + fprintf(voting , "Utf8 = %s\n" + ,((smb_msg_is_utf8(msg) || (msg->hdr.auxattr & MSG_HFIELDS_UTF8)) && (mode&QM_UTF8)) + ? "true" : "false"); + /* Message-IDs */ fprintf(hdrs,"%s: %s\n", smb_hfieldtype(RFC822MSGID), msgid); if((p = get_replyid(&cfg, smb, msg, reply_id, sizeof(reply_id))) != NULL) @@ -151,7 +168,7 @@ ulong sbbs_t::msgtoqwk(smbmsg_t* msg, FILE *qwk_fp, long mode, smb_t* smb ); /* SENDER */ - fprintf(hdrs,"%s: %s\n",smb_hfieldtype(SENDER),msg->from); + fprintf(hdrs,"%s: %s\n",smb_hfieldtype(SENDER), from); if(msg->from_net.type) fprintf(hdrs,"%s: %s\n",smb_hfieldtype(SENDERNETADDR),smb_netaddrstr(&msg->from_net,tmp)); if((p=(char*)smb_get_hfield(msg,hfield_type=SENDERIPADDR,NULL))!=NULL) @@ -176,10 +193,10 @@ ulong sbbs_t::msgtoqwk(smbmsg_t* msg, FILE *qwk_fp, long mode, smb_t* smb fprintf(hdrs,"Reply-To: %s\n",p); /* use original RFC822 header field */ /* SUBJECT */ - fprintf(hdrs,"%s: %s\n",smb_hfieldtype(SUBJECT),msg->subj); + fprintf(hdrs,"%s: %s\n",smb_hfieldtype(SUBJECT), subj); /* RECIPIENT */ - fprintf(hdrs,"%s: %s\n",smb_hfieldtype(RECIPIENT),msg->to); + fprintf(hdrs,"%s: %s\n",smb_hfieldtype(RECIPIENT), to); if(msg->to_net.type!=NET_NONE && subnum==INVALID_SUB) fprintf(hdrs,"%s: %s\n",smb_hfieldtype(RECIPIENTNETADDR),smb_netaddrstr(&msg->to_net,tmp)); @@ -242,14 +259,15 @@ ulong sbbs_t::msgtoqwk(smbmsg_t* msg, FILE *qwk_fp, long mode, smb_t* smb return(0); char qwk_newline = QWK_NEWLINE; - if(smb_msg_is_utf8(msg)) - qwk_newline = '\n'; + if(smb_msg_is_utf8(msg)) { + if(mode&QM_UTF8) + qwk_newline = '\n'; + else + utf8_normalize_str(buf); + } fprintf(qwk_fp,"%*s",QWK_BLOCK_LEN,""); /* Init header to space */ - SAFECOPY(from,msg->from); - SAFECOPY(to,msg->to); - if(msg->hdr.type == SMB_MSG_TYPE_NORMAL) { /* QWKE compatible kludges */ if(msg->from_net.addr && (uint)subnum==INVALID_SUB && !(mode&QM_TO_QNET)) { @@ -297,8 +315,8 @@ ulong sbbs_t::msgtoqwk(smbmsg_t* msg, FILE *qwk_fp, long mode, smb_t* smb else SAFECOPY(to,msg->to); } - if((mode&QM_EXT) && strlen(msg->subj) > QWK_HFIELD_LEN) - size+=fprintf(qwk_fp,"Subject: %.128s%c", msg->subj, qwk_newline); + if((mode&QM_EXT) && strlen(subj) > QWK_HFIELD_LEN) + size+=fprintf(qwk_fp,"Subject: %.128s%c", subj, qwk_newline); if(msg->from_net.type==NET_QWK && mode&QM_VIA && !msg->forwarded) size+=fprintf(qwk_fp,"@VIA: %s%c" @@ -535,7 +553,7 @@ ulong sbbs_t::msgtoqwk(smbmsg_t* msg, FILE *qwk_fp, long mode, smb_t* smb ,tmp /* date and time */ ,to /* To: */ ,from /* From: */ - ,msg->subj /* Subject */ + ,subj /* Subject */ ,nulstr /* Password */ ,msg->hdr.thread_back&MAX_MSGNUM /* Message Re: Number */ ,(size/QWK_BLOCK_LEN)+1 /* Number of blocks */ diff --git a/src/sbbs3/pack_qwk.cpp b/src/sbbs3/pack_qwk.cpp index 24c6dd513d..c9f3551fc2 100644 --- a/src/sbbs3/pack_qwk.cpp +++ b/src/sbbs3/pack_qwk.cpp @@ -105,8 +105,7 @@ bool sbbs_t::pack_qwk(char *packet, ulong *msgcnt, bool prepack) mode|=QM_VIA; if(useron.qwk&QWK_MSGID) mode|=QM_MSGID; - if(useron.qwk&QWK_EXT) - mode|=QM_EXT; + mode |= useron.qwk&(QWK_EXT | QWK_UTF8); (*msgcnt)=0L; if(/* !prepack && */ !(useron.qwk&QWK_NOCTRL)) { diff --git a/src/sbbs3/pack_rep.cpp b/src/sbbs3/pack_rep.cpp index 10b8f5b73d..de6a7e7efb 100644 --- a/src/sbbs3/pack_rep.cpp +++ b/src/sbbs3/pack_rep.cpp @@ -149,7 +149,7 @@ bool sbbs_t::pack_rep(uint hubnum) } mode = QM_TO_QNET|QM_REP; - mode |= (cfg.qhub[hubnum]->misc&(QHUB_EXT|QHUB_CTRL_A)); + mode |= (cfg.qhub[hubnum]->misc&(QHUB_EXT | QHUB_CTRL_A | QHUB_UTF8)); /* For an unclear reason, kludge lines (including @VIA and @TZ) were not included in NetMail previously */ if(!(cfg.qhub[hubnum]->misc&QHUB_NOHEADERS)) mode|=(QM_VIA|QM_TZ|QM_MSGID|QM_REPLYTO); msgtoqwk(&msg, rep, mode, &smb, /* confnum: */0, hdrs); @@ -223,7 +223,7 @@ bool sbbs_t::pack_rep(uint hubnum) } mode = cfg.qhub[hubnum]->mode[i]|QM_TO_QNET|QM_REP; - mode |= (cfg.qhub[hubnum]->misc&(QHUB_EXT|QHUB_CTRL_A)); + mode |= (cfg.qhub[hubnum]->misc&(QHUB_EXT | QHUB_CTRL_A | QHUB_UTF8)); if(!(cfg.qhub[hubnum]->misc&QHUB_NOHEADERS)) mode|=(QM_VIA|QM_TZ|QM_MSGID|QM_REPLYTO); if(msg.from_net.type!=NET_QWK) mode|=QM_TAGLINE; diff --git a/src/sbbs3/postmsg.cpp b/src/sbbs3/postmsg.cpp index 5326f08ce0..41ec13ec82 100644 --- a/src/sbbs3/postmsg.cpp +++ b/src/sbbs3/postmsg.cpp @@ -91,23 +91,23 @@ bool sbbs_t::postmsg(uint subnum, long wm_mode, smb_t* resmb, smbmsg_t* remsg) uint reason; if(remsg) { - SAFECOPY(title, msghdr_field(remsg, remsg->subj, NULL, /* UTF8: */true)); + SAFECOPY(title, msghdr_field(remsg, remsg->subj, NULL, term_supports(UTF8))); if(remsg->hdr.attr&MSG_ANONYMOUS) SAFECOPY(from,text[Anonymous]); else - SAFECOPY(from, msghdr_field(remsg, remsg->from, NULL, /* UTF8: */true)); + SAFECOPY(from, msghdr_field(remsg, remsg->from, NULL, term_supports(UTF8))); // If user posted this message, reply to the original recipient again if(remsg->to != NULL && ((remsg->from_ext != NULL && atoi(remsg->from_ext)==useron.number) || stricmp(useron.alias,remsg->from) == 0 || stricmp(useron.name,remsg->from) == 0)) - SAFECOPY(touser, msghdr_field(remsg, remsg->to, NULL, /* UTF8: */true)); + SAFECOPY(touser, msghdr_field(remsg, remsg->to, NULL, term_supports(UTF8))); else SAFECOPY(touser,from); msgattr=(ushort)(remsg->hdr.attr&MSG_PRIVATE); sprintf(top,text[RegardingByToOn] ,title ,from - ,msghdr_field(remsg, remsg->to, NULL, /* UTF8: */true) + ,msghdr_field(remsg, remsg->to, NULL, term_supports(UTF8)) ,timestr(remsg->hdr.when_written.time) ,smb_zonestr(remsg->hdr.when_written.zone,NULL)); if(remsg->tags != NULL) diff --git a/src/sbbs3/qwk.cpp b/src/sbbs3/qwk.cpp index 7222702e45..9dc9bbd42d 100644 --- a/src/sbbs3/qwk.cpp +++ b/src/sbbs3/qwk.cpp @@ -483,10 +483,12 @@ void sbbs_t::qwk_sec() ,useron.qwk&QWK_VIA ? text[Yes]:text[No]); bprintf(text[QWKSettingsMsgID] ,useron.qwk&QWK_MSGID ? text[Yes]:text[No]); + bprintf(text[QWKSettingsUtf8] + ,useron.qwk&QWK_UTF8 ? text[Yes]:text[No]); bprintf(text[QWKSettingsExtended] ,useron.qwk&QWK_EXT ? text[Yes]:text[No]); bputs(text[QWKSettingsWhich]); - ch=(char)getkeys("AEDFHIOPQTYMNCXZV",0); + ch=(char)getkeys("AEDFHIOPQTUYMNCXZV",0); if(sys_status&SS_ABORT || !ch || ch=='Q' || !online) break; switch(ch) { @@ -555,6 +557,9 @@ void sbbs_t::qwk_sec() case 'X': /* QWKE */ useron.qwk^=QWK_EXT; break; + case 'U': + useron.qwk^=QWK_UTF8; + break; } putuserrec(&cfg,useron.number,U_QWK,8,ultoa(useron.qwk,str,16)); } diff --git a/src/sbbs3/qwk.h b/src/sbbs3/qwk.h index 8a289f7a02..a8939207d6 100644 --- a/src/sbbs3/qwk.h +++ b/src/sbbs3/qwk.h @@ -50,6 +50,7 @@ #define QM_MSGID (1<<10) /* Include @MSGID and @REPLY kludges */ #define QM_REPLYTO (1<<11) /* Include @REPLYTO kludge */ #define QM_EXT (1<<13) /* QWK Extended (QWKE) mode (same as QWK_EXT and QHUB_EXT) */ +#define QM_UTF8 (1<<18) /* Include UTF-8 characters */ float ltomsbin(long val); bool route_circ(char *via, char *id); diff --git a/src/sbbs3/sbbsdefs.h b/src/sbbs3/sbbsdefs.h index 7b13063903..1395a77788 100644 --- a/src/sbbs3/sbbsdefs.h +++ b/src/sbbs3/sbbsdefs.h @@ -436,6 +436,7 @@ typedef enum { /* Values for xtrn_t.event */ #define QWK_MSGID (1L<<14) /* Include "@MSGID" in msgs */ #define QWK_HEADERS (1L<<16) /* Include HEADERS.DAT file */ #define QWK_VOTING (1L<<17) /* Include VOTING.DAT */ +#define QWK_UTF8 (1L<<18) /* Include UTF-8 characters */ #define QWK_DEFAULT (QWK_FILES|QWK_ATTACH|QWK_EMAIL|QWK_DELMAIL) @@ -447,6 +448,7 @@ typedef enum { /* Values for xtrn_t.event */ #define QHUB_NOKLUDGES (1<<14) /* Don't include @-kludges */ #define QHUB_NOHEADERS (1<<16) /* Don't include HEADERS.DAT */ #define QHUB_NOVOTING (1<<17) /* Don't include VOTING.DAT */ +#define QHUB_UTF8 (1<<18) /* Include UTF-8 characters */ /* Bits in user.chat */ #define CHAT_ECHO (1<<0) /* Multinode chat echo */ diff --git a/src/sbbs3/text.h b/src/sbbs3/text.h index 325f6add70..74906184c3 100644 --- a/src/sbbs3/text.h +++ b/src/sbbs3/text.h @@ -837,6 +837,7 @@ enum { ,Utf8TerminalQ ,MsgCarbonCopyList ,LoggingOn + ,QWKSettingsUtf8 ,TOTAL_TEXT }; diff --git a/src/sbbs3/text_defaults.c b/src/sbbs3/text_defaults.c index 8f720cffd4..d8310ca798 100644 --- a/src/sbbs3/text_defaults.c +++ b/src/sbbs3/text_defaults.c @@ -116,9 +116,9 @@ const char * const text_defaults[TOTAL_TEXT]={ ,"\x01\x6e\x0d\x0a\x4e\x6f\x20\x6d\x61\x69\x6c\x20\x6f\x6e\x20\x73\x79\x73\x74\x65\x6d\x2e\x0d\x0a" // 063 NoMailOnSystem ,"\x01\x6e\x0d\x0a\x01\x63\xfe\x20\x01\x68\x01\x62\x52\x65\x61\x64\x69\x6e\x67\x20\x41\x6c\x6c\x20\x45\x2d\x6d\x61\x69\x6c\x20\x01" "\x6e\x01\x63\xfe\x20\x01\x68\x01\x62\x28\x01\x77\x25\x75\x20\x01\x62\x6f\x66\x20\x01\x77\x25\x75\x01\x62\x29\x3a\x20\x01\x6e" // 064 ReadingAllMail - ,"\x01\x5f\x0d\x0a\x01\x71\x01\x67\x01\x68\x20\x20\x20\x20\x20\x20\x46\x72\x6f\x6d\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20" - "\x20\x20\x20\x20\x20\x20\x20\x54\x6f\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x41\x20" - "\x53\x75\x62\x6a\x65\x63\x74\x0d\x0a\x01\x6e" // 065 MailOnSystemLstHdr + ,"\x01\x5f\x0d\x0a\x01\x67\x01\x68\x20\x20\x20\x20\x20\x20\x46\x72\x6f\x6d\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20" + "\x20\x20\x20\x20\x20\x54\x6f\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x41\x20\x53\x75" + "\x62\x6a\x65\x63\x74\x0d\x0a\x01\x6e" // 065 MailOnSystemLstHdr ,"\x01\x67\x01\x68\x25\x35\x64\x01\x6e\x01\x67\x20\x25\x2d\x32\x32\x2e\x32\x32\x73\x20\x25\x2d\x32\x32\x2e\x32\x32\x73\x20\x01\x68" "\x25\x63\x01\x6e\x01\x67\x20\x25\x73\x0d\x0a" // 066 MailOnSystemLstFmt ,"\x01\x2d\x0d\x0a\x01\x63\x25\x2d\x31\x35\x2e\x31\x35\x73\x20\x01\x79\x01\x68\x25\x2d\x34\x34\x2e\x34\x34\x73\x20\x01\x6e\x01\x63" @@ -1362,4 +1362,6 @@ const char * const text_defaults[TOTAL_TEXT]={ ,"\x0d\x0a\xb3\x20\x01\x62\x43\x43\x20\x20\x01\x6e\x01\x62\x3a\x20\x01\x68\x01\x63\x25\x2e\x37\x30\x73" // 825 MsgCarbonCopyList ,"\x01\x6e\x01\x68\x4c\x6f\x67\x67\x69\x6e\x67\x20\x6f\x6e\x20\x74\x6f\x20\x40\x42\x42\x53\x40\x20\x61\x73\x20\x40\x41\x4c\x49\x41" "\x53\x40\x20\x40\x45\x4c\x4c\x49\x50\x53\x49\x53\x40\x01\x6e\x0d\x0a\x40\x52\x45\x53\x45\x54\x50\x41\x55\x53\x45\x40" // 826 LoggingOn + ,"\x01\x6e\x01\x62\x5b\x01\x68\x01\x77\x55\x01\x6e\x01\x62\x5d\x20\x01\x68\x49\x6e\x63\x6c\x75\x64\x65\x20\x55\x54\x46\x2d\x38\x20" + "\x43\x68\x61\x72\x61\x63\x74\x65\x72\x73\x20\x20\x20\x20\x20\x01\x6e\x01\x62\x3a\x20\x01\x63\x25\x73\x0d\x0a" // 827 QWKSettingsUtf8 }; -- GitLab