+ if (((Source == NULL) && (PlainIn == NULL)) || (Target == NULL) )
+ return ;
+
+ if (PlainIn != NULL) {
+ aptr = PlainIn;
+ len = strlen(PlainIn);
+ eiptr = aptr + len;
+ }
+ else {
+ aptr = Source->buf;
+ eiptr = aptr + Source->BufUsed;
+ len = Source->BufUsed;
+ }
+
+ if (len == 0)
+ return;
+
+ eptr = Target->buf + Target->BufSize - 8;
+ tptr = Target->buf + Target->BufUsed;
+
+ while (aptr < eiptr){
+ if(tptr + 3 >= eptr) {
+ IncreaseBuf(Target, 1, -1);
+ eptr = Target->buf + Target->BufSize - 8;
+ tptr = Target->buf + Target->BufUsed;
+ }
+
+ if (*aptr == '\n') {
+ *tptr = '\\';
+ Target->BufUsed++;
+ tptr++;
+ *tptr = 'n';
+ Target->BufUsed++;
+ }
+ else if (*aptr == '\r') {
+ *tptr = '\\';
+ Target->BufUsed++;
+ tptr++;
+ *tptr = 'r';
+ Target->BufUsed++;
+ }
+ else if (*aptr == ',') {
+ *tptr = '\\';
+ Target->BufUsed++;
+ tptr++;
+ *tptr = ',';
+ Target->BufUsed++;
+ } else {
+ *tptr = *aptr;
+ Target->BufUsed++;
+ }
+ tptr++; aptr++;
+ }
+ *tptr = '\0';
+}
+
+/**
+ * @ingroup StrBuf_DeEnCoder
+ * @brief Append a string, escaping characters which have meaning in JavaScript strings .
+ *
+ * @param Target target buffer
+ * @param Source source buffer; set to NULL if you just have a C-String
+ * @param PlainIn Plain-C string to append; set to NULL if unused
+ * @returns size of result or -1
+ */
+long StrECMAEscAppend(StrBuf *Target, const StrBuf *Source, const char *PlainIn)
+{
+ const char *aptr, *eiptr;
+ char *bptr, *eptr;
+ long len;
+
+ if (((Source == NULL) && (PlainIn == NULL)) || (Target == NULL) )
+ return -1;
+
+ if (PlainIn != NULL) {
+ aptr = PlainIn;
+ len = strlen(PlainIn);
+ eiptr = aptr + len;
+ }
+ else {
+ aptr = Source->buf;
+ eiptr = aptr + Source->BufUsed;
+ len = Source->BufUsed;
+ }
+
+ if (len == 0)
+ return -1;
+
+ bptr = Target->buf + Target->BufUsed;
+ eptr = Target->buf + Target->BufSize - 3; /* our biggest unit to put in... */
+
+ while (aptr < eiptr){
+ if(bptr >= eptr) {
+ IncreaseBuf(Target, 1, -1);
+ eptr = Target->buf + Target->BufSize - 3;
+ bptr = Target->buf + Target->BufUsed;
+ }
+ if (*aptr == '"') {
+ *bptr = '\\';
+ bptr ++;
+ *bptr = '"';
+ bptr ++;
+ Target->BufUsed += 2;
+ } else if (*aptr == '\\') {
+ *bptr = '\\';
+ bptr ++;
+ *bptr = '\\';
+ bptr ++;
+ Target->BufUsed += 2;
+ }
+ else{
+ *bptr = *aptr;
+ bptr++;
+ Target->BufUsed ++;
+ }
+ aptr ++;
+ }
+ *bptr = '\0';
+ if ((bptr == eptr - 1 ) && !IsEmptyStr(aptr) )
+ return -1;
+ return Target->BufUsed;
+}
+
+/**
+ * @ingroup StrBuf_DeEnCoder
+ * @brief Append a string, escaping characters which have meaning in HTML + json.
+ *
+ * @param Target target buffer
+ * @param Source source buffer; set to NULL if you just have a C-String
+ * @param PlainIn Plain-C string to append; set to NULL if unused
+ * @param nbsp If nonzero, spaces are converted to non-breaking spaces.
+ * @param nolinebreaks if set to 1, linebreaks are removed from the string.
+ * if set to 2, linebreaks are replaced by <br/>
+ */
+long StrHtmlEcmaEscAppend(StrBuf *Target, const StrBuf *Source, const char *PlainIn, int nbsp, int nolinebreaks)
+{
+ const char *aptr, *eiptr;
+ char *bptr, *eptr;
+ long len;
+ int IsUtf8Sequence = 0;
+
+ if (((Source == NULL) && (PlainIn == NULL)) || (Target == NULL) )
+ return -1;
+
+ if (PlainIn != NULL) {
+ aptr = PlainIn;
+ len = strlen(PlainIn);
+ eiptr = aptr + len;
+ }
+ else {
+ aptr = Source->buf;
+ eiptr = aptr + Source->BufUsed;
+ len = Source->BufUsed;
+ }
+
+ if (len == 0)
+ return -1;
+
+ bptr = Target->buf + Target->BufUsed;
+ eptr = Target->buf + Target->BufSize - 11; /* our biggest unit to put in... */
+
+ while (aptr < eiptr){
+ if(bptr >= eptr) {
+ IncreaseBuf(Target, 1, -1);
+ eptr = Target->buf + Target->BufSize - 11; /* our biggest unit to put in... */
+ bptr = Target->buf + Target->BufUsed;
+ }
+ if (*aptr == '<') {
+ memcpy(bptr, "<", 4);
+ bptr += 4;
+ Target->BufUsed += 4;
+ }
+ else if (*aptr == '>') {
+ memcpy(bptr, ">", 4);
+ bptr += 4;
+ Target->BufUsed += 4;
+ }
+ else if (*aptr == '&') {
+ memcpy(bptr, "&", 5);
+ bptr += 5;
+ Target->BufUsed += 5;
+ }
+ else if (*aptr == LB) {
+ *bptr = '<';
+ bptr ++;
+ Target->BufUsed ++;
+ }
+ else if (*aptr == RB) {
+ *bptr = '>';
+ bptr ++;
+ Target->BufUsed ++;
+ }
+ else if ((*aptr == 32) && (nbsp == 1)) {
+ memcpy(bptr, " ", 6);
+ bptr += 6;
+ Target->BufUsed += 6;
+ }
+ else if ((*aptr == '\n') && (nolinebreaks == 1)) {
+ *bptr='\0'; /* nothing */
+ }
+ else if ((*aptr == '\n') && (nolinebreaks == 2)) {
+ memcpy(bptr, "<br/>", 11);
+ bptr += 11;
+ Target->BufUsed += 11;
+ }
+
+ else if ((*aptr == '\r') && (nolinebreaks != 0)) {
+ *bptr='\0'; /* nothing */
+ }
+
+ else if ((*aptr == '"') || (*aptr == QU)) {
+ *bptr = '\\';
+ bptr ++;
+ *bptr = '"';
+ bptr ++;
+ Target->BufUsed += 2;
+ } else if (*aptr == '\\') {
+ *bptr = '\\';
+ bptr ++;
+ *bptr = '\\';
+ bptr ++;
+ Target->BufUsed += 2;
+ }
+ else {
+ if (((unsigned char)*aptr) >= 0x20)
+ {
+ IsUtf8Sequence = Ctdl_GetUtf8SequenceLength(aptr, eiptr);
+
+ *bptr = *aptr;
+ Target->BufUsed ++;
+ while (IsUtf8Sequence > 1){
+ if(bptr + IsUtf8Sequence >= eptr) {
+ IncreaseBuf(Target, 1, -1);
+ eptr = Target->buf + Target->BufSize - 11; /* our biggest unit to put in... */
+ bptr = Target->buf + Target->BufUsed - 1;
+ }
+ bptr++; aptr++;
+ IsUtf8Sequence --;
+ *bptr = *aptr;
+ Target->BufUsed ++;
+ }
+ bptr++;
+ }
+
+ }
+ aptr ++;
+ }
+ *bptr = '\0';
+ if ((bptr = eptr - 1 ) && !IsEmptyStr(aptr) )
+ return -1;
+ return Target->BufUsed;
+}
+
+/**
+ * @ingroup StrBuf_DeEnCoder
+ * @brief unhide special chars hidden to the HTML escaper
+ * @param target buffer to put the unescaped string in
+ * @param source buffer to unescape
+ */
+void StrBufEUid_unescapize(StrBuf *target, const StrBuf *source)
+{
+ int a, b, len;
+ char hex[3];
+
+ if (target != NULL)
+ FlushStrBuf(target);
+
+ if (source == NULL ||target == NULL)
+ {
+ return;
+ }
+
+ len = source->BufUsed;
+ for (a = 0; a < len; ++a) {
+ if (target->BufUsed >= target->BufSize)
+ IncreaseBuf(target, 1, -1);
+
+ if (source->buf[a] == '=') {
+ hex[0] = source->buf[a + 1];
+ hex[1] = source->buf[a + 2];
+ hex[2] = 0;
+ b = 0;
+ sscanf(hex, "%02x", &b);
+ target->buf[target->BufUsed] = b;
+ target->buf[++target->BufUsed] = 0;
+ a += 2;
+ }
+ else {
+ target->buf[target->BufUsed] = source->buf[a];
+ target->buf[++target->BufUsed] = 0;
+ }
+ }
+}
+
+
+/**
+ * @ingroup StrBuf_DeEnCoder
+ * @brief hide special chars from the HTML escapers and friends
+ * @param target buffer to put the escaped string in
+ * @param source buffer to escape
+ */
+void StrBufEUid_escapize(StrBuf *target, const StrBuf *source)
+{
+ int i, len;
+
+ if (target != NULL)
+ FlushStrBuf(target);
+
+ if (source == NULL ||target == NULL)
+ {
+ return;
+ }
+
+ len = source->BufUsed;
+ for (i=0; i<len; ++i) {
+ if (target->BufUsed + 4 >= target->BufSize)
+ IncreaseBuf(target, 1, -1);
+ if ( (isalnum(source->buf[i])) ||
+ (source->buf[i]=='-') ||
+ (source->buf[i]=='_') ) {
+ target->buf[target->BufUsed++] = source->buf[i];
+ }
+ else {
+ sprintf(&target->buf[target->BufUsed],
+ "=%02X",
+ (0xFF &source->buf[i]));
+ target->BufUsed += 3;
+ }
+ }
+ target->buf[target->BufUsed + 1] = '\0';
+}
+
+
+/*******************************************************************************
+ * Quoted Printable de/encoding *
+ *******************************************************************************/
+
+/**
+ * @ingroup StrBuf_DeEnCoder
+ * @brief decode a buffer from base 64 encoding; destroys original
+ * @param Buf Buffor to transform
+ */
+int StrBufDecodeBase64(StrBuf *Buf)
+{
+ char *xferbuf;
+ size_t siz;
+ if (Buf == NULL) return -1;
+
+ xferbuf = (char*) malloc(Buf->BufSize);
+ *xferbuf = '\0';
+ siz = CtdlDecodeBase64(xferbuf,
+ Buf->buf,
+ Buf->BufUsed);
+ free(Buf->buf);
+ Buf->buf = xferbuf;
+ Buf->BufUsed = siz;
+ return siz;
+}
+
+/**
+ * @ingroup StrBuf_DeEnCoder
+ * @brief decode a buffer from base 64 encoding; destroys original
+ * @param Buf Buffor to transform
+ */
+int StrBufDecodeHex(StrBuf *Buf)
+{
+ unsigned int ch;
+ char *pch, *pche, *pchi;
+
+ if (Buf == NULL) return -1;
+
+ pch = pchi = Buf->buf;
+ pche = pch + Buf->BufUsed;
+
+ while (pchi < pche){
+ ch = decode_hex(pchi);
+ *pch = ch;
+ pch ++;
+ pchi += 2;
+ }
+
+ *pch = '\0';
+ Buf->BufUsed = pch - Buf->buf;
+ return Buf->BufUsed;
+}
+
+/**
+ * @ingroup StrBuf_DeEnCoder
+ * @brief replace all chars >0x20 && < 0x7F with Mute
+ * @param Mute char to put over invalid chars
+ * @param Buf Buffor to transform
+ */
+int StrBufSanitizeAscii(StrBuf *Buf, const char Mute)
+{
+ unsigned char *pch;
+
+ if (Buf == NULL) return -1;
+ pch = (unsigned char *)Buf->buf;
+ while (pch < (unsigned char *)Buf->buf + Buf->BufUsed) {
+ if ((*pch < 0x20) || (*pch > 0x7F))
+ *pch = Mute;
+ pch ++;
+ }
+ return Buf->BufUsed;
+}
+
+
+/**
+ * @ingroup StrBuf_DeEnCoder
+ * @brief remove escaped strings from i.e. the url string (like %20 for blanks)
+ * @param Buf Buffer to translate
+ * @param StripBlanks Reduce several blanks to one?
+ */
+long StrBufUnescape(StrBuf *Buf, int StripBlanks)
+{
+ int a, b;
+ char hex[3];
+ long len;
+
+ if (Buf == NULL)
+ return -1;
+
+ while ((Buf->BufUsed > 0) && (isspace(Buf->buf[Buf->BufUsed - 1]))){
+ Buf->buf[Buf->BufUsed - 1] = '\0';
+ Buf->BufUsed --;
+ }
+
+ a = 0;
+ while (a < Buf->BufUsed) {
+ if (Buf->buf[a] == '+')
+ Buf->buf[a] = ' ';
+ else if (Buf->buf[a] == '%') {
+ /* don't let % chars through, rather truncate the input. */
+ if (a + 2 > Buf->BufUsed) {
+ Buf->buf[a] = '\0';
+ Buf->BufUsed = a;
+ }
+ else {
+ hex[0] = Buf->buf[a + 1];
+ hex[1] = Buf->buf[a + 2];
+ hex[2] = 0;
+ b = 0;
+ sscanf(hex, "%02x", &b);
+ Buf->buf[a] = (char) b;
+ len = Buf->BufUsed - a - 2;
+ if (len > 0)
+ memmove(&Buf->buf[a + 1], &Buf->buf[a + 3], len);
+
+ Buf->BufUsed -=2;
+ }
+ }
+ a++;
+ }
+ return a;
+}
+
+
+/**
+ * @ingroup StrBuf_DeEnCoder
+ * @brief RFC2047-encode a header field if necessary.
+ * If no non-ASCII characters are found, the string
+ * will be copied verbatim without encoding.
+ *
+ * @param target Target buffer.
+ * @param source Source string to be encoded.
+ * @returns encoded length; -1 if non success.
+ */
+int StrBufRFC2047encode(StrBuf **target, const StrBuf *source)
+{
+ const char headerStr[] = "=?UTF-8?Q?";
+ int need_to_encode = 0;
+ int i = 0;
+ unsigned char ch;
+
+ if ((source == NULL) ||
+ (target == NULL))
+ return -1;
+
+ while ((i < source->BufUsed) &&
+ (!IsEmptyStr (&source->buf[i])) &&
+ (need_to_encode == 0)) {
+ if (((unsigned char) source->buf[i] < 32) ||
+ ((unsigned char) source->buf[i] > 126)) {
+ need_to_encode = 1;
+ }
+ i++;
+ }
+
+ if (!need_to_encode) {
+ if (*target == NULL) {
+ *target = NewStrBufPlain(source->buf, source->BufUsed);
+ }
+ else {
+ FlushStrBuf(*target);
+ StrBufAppendBuf(*target, source, 0);
+ }
+ return (*target)->BufUsed;
+ }
+ if (*target == NULL)
+ *target = NewStrBufPlain(NULL, sizeof(headerStr) + source->BufUsed * 2);
+ else if (sizeof(headerStr) + source->BufUsed >= (*target)->BufSize)
+ IncreaseBuf(*target, sizeof(headerStr) + source->BufUsed, 0);
+ memcpy ((*target)->buf, headerStr, sizeof(headerStr) - 1);
+ (*target)->BufUsed = sizeof(headerStr) - 1;
+ for (i=0; (i < source->BufUsed); ++i) {
+ if ((*target)->BufUsed + 4 >= (*target)->BufSize)
+ IncreaseBuf(*target, 1, 0);
+ ch = (unsigned char) source->buf[i];
+ if ((ch < 32) || (ch > 126) || (ch == 61)) {
+ sprintf(&(*target)->buf[(*target)->BufUsed], "=%02X", ch);
+ (*target)->BufUsed += 3;
+ }
+ else {
+ (*target)->buf[(*target)->BufUsed] = ch;
+ (*target)->BufUsed++;
+ }
+ }
+
+ if ((*target)->BufUsed + 4 >= (*target)->BufSize)
+ IncreaseBuf(*target, 1, 0);
+
+ (*target)->buf[(*target)->BufUsed++] = '?';
+ (*target)->buf[(*target)->BufUsed++] = '=';
+ (*target)->buf[(*target)->BufUsed] = '\0';
+ return (*target)->BufUsed;;
+}
+
+
+
+static void AddRecipient(StrBuf *Target,
+ StrBuf *UserName,
+ StrBuf *EmailAddress,
+ StrBuf *EncBuf)
+{
+ int QuoteMe = 0;
+
+ if (StrLength(Target) > 0) StrBufAppendBufPlain(Target, HKEY(", "), 0);
+ if (strchr(ChrPtr(UserName), ',') != NULL) QuoteMe = 1;
+
+ if (QuoteMe) StrBufAppendBufPlain(Target, HKEY("\""), 0);
+ StrBufRFC2047encode(&EncBuf, UserName);
+ StrBufAppendBuf(Target, EncBuf, 0);
+ if (QuoteMe) StrBufAppendBufPlain(Target, HKEY("\" "), 0);
+ else StrBufAppendBufPlain(Target, HKEY(" "), 0);
+
+ if (StrLength(EmailAddress) > 0){
+ StrBufAppendBufPlain(Target, HKEY("<"), 0);
+ StrBufAppendBuf(Target, EmailAddress, 0); /* TODO: what about IDN???? */
+ StrBufAppendBufPlain(Target, HKEY(">"), 0);
+ }
+}
+
+
+/**
+ * \brief QP encode parts of an email TO/CC/BCC vector, and strip/filter invalid parts
+ * \param Recp Source list of email recipients
+ * \param UserName Temporary buffer for internal use; Please provide valid buffer.
+ * \param EmailAddress Temporary buffer for internal use; Please provide valid buffer.
+ * \param EncBuf Temporary buffer for internal use; Please provide valid buffer.
+ * \returns encoded & sanitized buffer with the contents of Recp; Caller owns this memory.
+ */
+StrBuf *StrBufSanitizeEmailRecipientVector(const StrBuf *Recp,
+ StrBuf *UserName,
+ StrBuf *EmailAddress,
+ StrBuf *EncBuf)
+{
+ StrBuf *Target;
+ int need_to_encode;
+
+ const char *pch, *pche;
+ const char *UserStart, *UserEnd, *EmailStart, *EmailEnd, *At;
+
+ if ((Recp == NULL) || (StrLength(Recp) == 0))
+ return NULL;
+
+ need_to_encode = 0;
+ pch = ChrPtr(Recp);
+ pche = pch + StrLength(Recp);
+
+ if (!CheckEncode(pch, -1, pche))
+ return NewStrBufDup(Recp);
+
+ Target = NewStrBufPlain(NULL, StrLength(Recp));
+
+ while ((pch != NULL) && (pch < pche))
+ {
+ int ColonOk = 0;
+
+ while (isspace(*pch)) pch++;
+ UserStart = UserEnd = EmailStart = EmailEnd = NULL;