void *smtp_challenge (void *s,unsigned long *len) { char tmp[MAILTMPLEN]; void *ret = NIL; SENDSTREAM *stream = (SENDSTREAM *) s; if ((stream->replycode == SMTPAUTHREADY) && !(ret = rfc822_base64 ((unsigned char *) stream->reply + 4, strlen (stream->reply + 4),len))) { sprintf (tmp,"SMTP SERVER BUG (invalid challenge): %.80s",stream->reply+4); mm_log (tmp,ERROR); } return ret; }
static Variant HHVM_FUNCTION(imap_base64, const String& text) { unsigned long newlength; char *decode = (char *)rfc822_base64((unsigned char *) text.data(), text.length(), &newlength); if (decode == NULL) { return false; } String ret = String(decode, newlength, CopyString); fs_give((void**) &decode); return ret; }
FeriteVariable *create_ferite_content_object( FeriteScript *script, MAILSTREAM *stream, BODY *body, int msgno, char *sec ) { if( body != NULL ) { FeriteVariable *object = NULL,*v = NULL; FeriteNamespaceBucket *nsb = NULL; char *object_name = NULL; object_name = ( body->type == TYPEMULTIPART ) ? "Mail.MessageMultiPart" : "Mail.MessagePart" ; nsb = ferite_find_namespace( script, script->mainns, object_name , FENS_CLS ); if( nsb == NULL ) return NULL; object = ferite_build_object( script, (FeriteClass *)nsb->data ); if( object == NULL ) return NULL; v = fe_new_lng("type",body->type); ferite_object_set_var(script, VAO(object), "type", v); output_printf(OUTPUT_DEBUG,"module.mail: setting type %d", body->type); if( body->subtype ) { v = fe_new_str( "subtype", body->subtype, 0, FE_CHARSET_DEFAULT ); ferite_object_set_var( script, VAO(object), "subtype", v ); } if( body->type == TYPEMULTIPART ) { PART *part = NULL; int i = 0; char sec2[200]; FeriteVariable *ret = NULL, *parts = NULL; parts = ferite_hash_get(script,VAO(object)->variables->variables,"parts"); part = body->nested.part; while( part ) { i++; if( sec ) { snprintf(sec2,200,"%s.%d",sec,i); } else { snprintf(sec2,200,"%d",i); } ret = create_ferite_content_object( script, stream, &part->body, msgno, sec2 ); ferite_uarray_add( script, VAUA(parts), ret , NULL, FE_ARRAY_ADD_AT_END ); part = part->next; } v = fe_new_lng("nparts", i); ferite_object_set_var(script, VAO(object), "nparts", v ); } else { long len = 0,len2 = 0; unsigned char *buf = NULL, *buf2 = NULL; SIZEDTEXT src, dest; FeriteVariable *v = NULL; PARAMETER *param = NULL; int i = 0; if( sec == NULL ) sec = "1"; buf = mail_fetchbody( stream, msgno, sec, &len ); switch(body->encoding){ case ENCQUOTEDPRINTABLE: if( debug_cmail_module ) output_printf(OUTPUT_DEBUG,"module.mail: Decoding from encoded quotable"); buf2 = rfc822_qprint(buf,len,&len2); break; case ENCBASE64: if( debug_cmail_module ) output_printf(OUTPUT_DEBUG,"module.mail: Decoding from base64"); buf2=rfc822_base64(buf,len,&len2); break; default: buf2=buf; len2=len; } if( debug_cmail_module ) { output_printf(OUTPUT_DEBUG,"module.mail: id: %s, description: %s", body->id, body->description); output_printf(OUTPUT_DEBUG,"module.mail: block type: %d.%s", body->type, body->subtype); } if( body->parameter ) /* Try and get the content type correctly */ { PARAMETER *ptr = body->parameter; while( ptr != NULL ) { if( caseless_compare( ptr->attribute, "charset" ) ) { if( debug_cmail_module ) output_printf(OUTPUT_DEBUG,"module.mail: Found content type for block: %s", ptr->value); v = fe_new_str("charset", ptr->value, 0, FE_CHARSET_DEFAULT); ferite_object_set_var(script, VAO(object), "charset", v); } ptr = ptr->next; } } v = fe_new_bin_str("content", buf2, len2, FE_CHARSET_DEFAULT ); ferite_object_set_var(script, VAO(object), "content", v ); v = fe_new_lng("encoding", body->encoding ); ferite_object_set_var(script, VAO(object), "encoding", v ); if( body->id ) { v = fe_new_str("ID", body->id, strlen(body->id), FE_CHARSET_DEFAULT); ferite_object_set_var(script, VAO(object), "ID", v); } if( body->disposition.type && strcasecmp(body->disposition.type, "attachment") == 0) { param = body->disposition.parameter; while(param){ if( param->attribute && ((strcasecmp(param->attribute,"filename") == 0) || (strcasecmp(param->attribute,"name") == 0) || (strcasecmp(param->attribute,"name*") == 0) || (strcasecmp(param->attribute,"filename*") == 0) )) { v = fe_new_str("filename", param->value, 0, FE_CHARSET_DEFAULT ); ferite_object_set_var(script, VAO(object), "filename", v ); break; } param=param->next; } } /* If filename was not found in Content-Disposition header search for it among the parameters */ if( strcmp(VAS(ferite_object_get_var(script, VAO(object), "filename"))->data, "") == 0 ) { param = body->parameter; while(param){ if( param->attribute && ((strcasecmp(param->attribute,"filename") == 0) || (strcasecmp(param->attribute,"name") == 0))) { v = fe_new_str("filename", param->value, 0, FE_CHARSET_DEFAULT ); ferite_object_set_var(script, VAO(object), "filename", v ); break; } param = param->next; } } } return object; } return NULL; }
/* See RFC 2047 for the description of the encodings used in the mail headers. Briefly, "encoded words" can be inserted which have the form of encoded-word = "=?" charset "?" encoding "?" encoded-text "?=" where charset and encoding can't contain space, control chars or "specials" and encoded-text can't contain spaces nor "?". NB: don't be confused by 2 meanings of encoding here: it is both the charset encoding for us and also QP/Base64 encoding for RFC 2047 */ static String DecodeHeaderOnce(const String& in, wxFontEncoding *pEncoding) { // we don't enforce the sanity checks on charset and encoding - should we? // const char *specials = "()<>@,;:\\\"[].?="; // there can be words in different encodings inside the same header so this // variable doesn't really make sense but in practice only one encoding will // be used in the entire header wxFontEncoding encodingHeader = wxFONTENCODING_SYSTEM; // if the header starts with an encoded word, preceding whitespace must be // ignored, so the flag must be set to true initially bool maybeBetweenEncodedWords = true; String out, space; // we can't define a valid "last" iterator below for empty string if ( in.empty() ) return String(); out.reserve(in.length()); for ( wxString::const_iterator p = in.begin(), end = in.end(), last = in.end() - 1; p != end; ++p ) { if ( *p == '=' && p != last && *(p + 1) == '?' ) { // found encoded word // save the start of it const wxString::const_iterator encWordStart = p++; // get the charset String csName; for ( ++p; p != end && *p != '?'; ++p ) // initial "++" to skip '?' { csName += *p; } if ( p == end ) { wxLogDebug(_T("Invalid encoded word syntax in '%s': missing charset."), in.c_str()); out += wxString(encWordStart, end); break; } // pass false to prevent asking the user from here: we can be called // during non-interactive operations and popping up a dialog for an // unknown charset can be inappropriate const wxFontEncoding encodingWord = wxFontMapperBase::Get()-> CharsetToEncoding(csName, false); if ( encodingWord == wxFONTENCODING_SYSTEM ) { wxLogDebug(_T("Unrecognized charset name \"%s\""), csName.mb_str()); } // this is not a problem in Unicode build #if !wxUSE_UNICODE if ( encodingHeader != wxFONTENCODING_SYSTEM && encodingHeader != encodingWord ) { // this is a bug (well, missing feature) in ANSI build of Mahogany wxLogDebug(_T("This header contains encoded words with different ") _T("encodings and won't be rendered correctly.")); } #endif // !wxUSE_UNICODE encodingHeader = encodingWord; // get the encoding in RFC 2047 sense enum { Encoding_Unknown, Encoding_Base64, Encoding_QuotedPrintable } enc2047 = Encoding_Unknown; ++p; // skip '?' if ( *(p + 1) == '?' ) { if ( *p == 'B' || *p == 'b' ) enc2047 = Encoding_Base64; else if ( *p == 'Q' || *p == 'q' ) enc2047 = Encoding_QuotedPrintable; } //else: multi letter encoding unrecognized if ( enc2047 == Encoding_Unknown ) { wxLogDebug(_T("Unrecognized header encoding in '%s'."), in.c_str()); // scan until the end of the encoded word const size_t posEncWordStart = p - in.begin(); const size_t posEncWordEnd = in.find("?=", p - in.begin()); if ( posEncWordEnd == wxString::npos ) { wxLogDebug(_T("Missing encoded word end marker in '%s'."), in.c_str()); out += wxString(encWordStart, end); break; } // +1 to skip '?' of "?=" (don't skip '=', this will be accounted // for by p increment in the loop statement) p += posEncWordEnd - posEncWordStart + 1; // leave this word undecoded out += wxString(encWordStart, p + 1); continue; } p += 2; // skip "Q?" or "B?" // get the encoded text bool hasUnderscore = false; const wxString::const_iterator encTextStart = p; while ( p != last && (*p != '?' || *(p + 1) != '=') ) { // this is needed for QP hack below if ( *p == '_' ) hasUnderscore = true; ++p; } if ( p == last ) { wxLogDebug(_T("Missing encoded word end marker in '%s'."), in.c_str()); out += wxString(encWordStart, end); break; } // convert the encoded word to char[] buffer for c-client wxCharBuffer encWord(wxString(encTextStart, p).To8BitData()); // skip '=' following '?' ++p; String textDecoded; if ( encWord ) { const unsigned long lenEncWord = strlen(encWord); // now decode the text using c-client functions unsigned long len; void *text; if ( enc2047 == Encoding_Base64 ) { text = rfc822_base64(UCHAR_CCAST(encWord), lenEncWord, &len); } else // QP { // cclient rfc822_qprint() behaves correctly and leaves '_' in the // QP encoded text because this is what RFC says, however many // broken clients replace spaces with underscores and so we undo it // here -- in this case it's better to be user-friendly than // standard-conforming if ( hasUnderscore ) { for ( char *pc = encWord.data(); *pc; ++pc ) { if ( *pc == '_' ) *pc = ' '; } } text = rfc822_qprint(UCHAR_CCAST(encWord), lenEncWord, &len); } if ( text ) { const char * const ctext = static_cast<char *>(text); if ( encodingWord == wxFONTENCODING_DEFAULT ) { // CharsetToEncoding() returns this for US-ASCII but // wxCSConv() doesn't accept it textDecoded = wxString::FromAscii(ctext, len); } else // real conversion needed { textDecoded = wxString(ctext, wxCSConv(encodingWord), len); } fs_give(&text); } } if ( textDecoded.empty() ) { // if decoding failed it is probably better to show undecoded // text than nothing at all textDecoded = wxString(encWordStart, p + 1); } // normally we leave the (8 bit) string as is and remember its // encoding so that we may choose the font for displaying it // correctly, but in case of UTF-7/8 we really need to transform it // here as we don't have any UTF-7/8 fonts, so we should display a // different string #if !wxUSE_UNICODE if ( encodingHeader == wxFONTENCODING_UTF7 || encodingHeader == wxFONTENCODING_UTF8 ) { encodingHeader = ConvertUTFToMB(&textDecoded, encodingHeader); } #endif // !wxUSE_UNICODE out += textDecoded; // forget the space before this encoded word, it must be ignored space.clear(); maybeBetweenEncodedWords = true; } else if ( maybeBetweenEncodedWords && (*p == ' ' || *p == '\r' || *p == '\n') ) { // spaces separating the encoded words must be ignored according // to section 6.2 of the RFC 2047, so we don't output them immediately // but delay until we know that what follows is not an encoded word space += *p; } else // just another normal char { // if we got any delayed whitespace (see above), flush it now if ( !space.empty() ) { out += space; space.clear(); } out += *p; maybeBetweenEncodedWords = false; } } if ( pEncoding ) *pEncoding = encodingHeader; return out; }