Kurz5 - Kapitola8

17. června 2007 v 11:07 | http://www.sweb.cz/kurz_evt/ |  Programování pro WinCE

7.8 Dekódování hlavičky zprávy

Opět postup rozdělíme na dvě části. Dnes program téměř dokončíme a příště si zase rozebereme, co se v programu děje.
  1. Do třídy CMainFrame vložíme členskou funkci QPB64Decoder(CString vstup) s výstupem CString.
    // Pomocna funkce pro dekodovani quoted-printable nebo Base64 retezce
    // Prijima zakodovany retezec, vraci dekodovany retezec
    CString CMainFrame::QPB64Decoder(CString vstup)
    {
    int nZacatek,nKonec,i,delka; // pomocne ukazatele
    CString strPrac,vystup; // pracovni a vystupni retezec
    BOOL bQuoted=FALSE, bB64=FALSE; // priznaky pro typ retezce

    strPrac=vstup;
    // Zkusim zjistit jak je retezec kodovan
    if((nZacatek=strPrac.Find(_T("?Q?")))!= -1) bQuoted=TRUE;
    else if((nZacatek=strPrac.Find(_T("?q?")))!= -1) bQuoted=TRUE;
    else if((nZacatek=strPrac.Find(_T("?B?")))!= -1) bB64=TRUE;
    else if((nZacatek=strPrac.Find(_T("?b?")))!= -1) bB64=TRUE;
    // Nejprve oddelim informace o kodovani - znaky jako =?us-ascii?Q?......?=
    if(nZacatek != -1) {
    nZacatek+=3; // Ukazatel premistim o 3 znaky dal
    nKonec=strPrac.Find(_T("?="),nZacatek); // Pokusim se najit zaverecne znaky retezce
    if(nKonec != -1) strPrac=vstup.Mid(nZacatek,nKonec-nZacatek);
    }
    // Nyni provedu vlastni dekodovani pro Quoted-printable...
    delka=strPrac.GetLength();
    i=0;
    if(bQuoted) // Je-li QP kodovani, provedu dekodovani sam
    while (i<delka) {
    if(strPrac[i] != '=') vystup+=strPrac[i];
    else {
    vystup+=(TCHAR)(HexaKod(strPrac[i+1])*16 + HexaKod(strPrac[i+2]));
    i+=2;
    }
    i++;
    }
    // ... nebo BASE64
    if(bB64) { // Je-li Base64 kodovani, zavolam si na to jine
    // Pro dekodovani pouziju tridu Base64
    CBase64 coder;
    // a 2 pole pro jeji "nakrmeni"
    char chZdroj[256];
    unsigned char chCil[256];
    int kolik,zpracovano;

    kolik=strPrac.GetLength();
    // Pouziju a naplnim (a take pretypuju) pole znaku, ktere vyzaduje tride CBase64
    if(kolik>250) kolik=250;
    for(int j=0;j<kolik;j++) chZdroj[j]=(unsigned char)strPrac[j];
    zpracovano=250;
    coder.Decode(chZdroj,kolik,chCil,&zpracovano);
    vystup=chCil;
    }

    // Jestlize jsem neco dekodoval, zmenim ceske znaky na odpovidajici kodovani
    // Upravu provedu zamenou znaku ve vystupnim retezci (pouze predpokladam ISO8859-2 nebo Win1250 jine opomijim)
    if(bQuoted || bB64) {
    delka=vystup.GetLength();
    for(i=0;i<delka;i++)
    // Ceske znaky s hacky a carkami prekoduju z ISO8859-2 a Win1250 do Unicode
    switch (vystup[i]) {
    // Pri kodovani ISO8859-2 - Unicode se musi zamenit vse s hackem a ů
    case (TCHAR)0xCC : vystup.SetAt(i,(TCHAR)0x011A); break; // Ě
    case (TCHAR)0xEC : vystup.SetAt(i,(TCHAR)0x011B); break; // ě
    case (TCHAR)0xD9 : vystup.SetAt(i,(TCHAR)0x016E); break; // Ů
    case (TCHAR)0xF9 : vystup.SetAt(i,(TCHAR)0x016F); break; // ů
    case (TCHAR)0xC8 : vystup.SetAt(i,(TCHAR)0x010C); break; // Č
    case (TCHAR)0xE8 : vystup.SetAt(i,(TCHAR)0x010D); break; // č
    case (TCHAR)0xCF : vystup.SetAt(i,(TCHAR)0x010E); break; // Ď
    case (TCHAR)0xEF : vystup.SetAt(i,(TCHAR)0x010F); break; // ď
    case (TCHAR)0xD2 : vystup.SetAt(i,(TCHAR)0x0147); break; // Ň
    case (TCHAR)0xF2 : vystup.SetAt(i,(TCHAR)0x0148); break; // ň
    case (TCHAR)0xD8 : vystup.SetAt(i,(TCHAR)0x0158); break; // Ř
    case (TCHAR)0xF8 : vystup.SetAt(i,(TCHAR)0x0159); break; // ř
    case (TCHAR)0xA9 : vystup.SetAt(i,(TCHAR)0x0160); break; // Š
    case (TCHAR)0xB9 : vystup.SetAt(i,(TCHAR)0x0161); break; // š
    case (TCHAR)0xAB : vystup.SetAt(i,(TCHAR)0x0164); break; // Ť
    case (TCHAR)0xBB : vystup.SetAt(i,(TCHAR)0x0165); break; // ť
    case (TCHAR)0xAE : vystup.SetAt(i,(TCHAR)0x017D); break; // Ž
    case (TCHAR)0xBE : vystup.SetAt(i,(TCHAR)0x017E); break; // ž
    // Windows 1250 znakova sada - odlisne znaky od ISO8859-2
    case (TCHAR)0x8A : vystup.SetAt(i,(TCHAR)0x0160); break; // Š
    case (TCHAR)0x9A : vystup.SetAt(i,(TCHAR)0x0161); break; // š
    case (TCHAR)0x8D : vystup.SetAt(i,(TCHAR)0x0164); break; // Ť
    case (TCHAR)0x9D : vystup.SetAt(i,(TCHAR)0x0165); break; // ť
    case (TCHAR)0x8E : vystup.SetAt(i,(TCHAR)0x017D); break; // Ž
    case (TCHAR)0x9E : vystup.SetAt(i,(TCHAR)0x017E); break; // ž
    }
    }

    // Pokud jsem neobjevil zadne kodovani, vracim to, co jsem dostal beze zmeny
    if(!bQuoted && !bB64) return vstup;
    // ... jinak uz mam neco upraveneho
    return vystup;
    }
  2. Uvedený dekodér používá drobnou funkci HexaKod.
    TCHAR HexaKod(TCHAR zn)
    {
    TCHAR pom = zn - '0';
    if(pom < 10) return pom; else return (pom-(TCHAR)0x7) & (TCHAR)0xF;
    }
  3. Pro detekci B64 kódování je ve funkci využita třída CBase64. Tuto třídu je možné objevit také na stránkách P.J.Naughtera. Pokud ji neobjevíte, je zde. Vložte oba soubory do pracovního adresáře a přidejte oba do projektu. Nezapomeňte na hlavičku Base64.h na úvod souboru MainFrm.cpp.
  4. Jako druhou pomocnou funkci vložte "vybírač" e-mailové adresy.
    // Pomocna funkce pro vyber E-mailove adresy
    // Prijima retezec, vraci prvni E-mail adresu v retezci uzavrenou mezi <>
    CString CMainFrame::GetAdr(CString vstup)
    {
    int nLeft,nRight;
    CString vystup;

    // Nejprve zkusim najit uzaviraci zavorky adresy <...>
    nLeft=vstup.Find(_T('<'));
    nRight=vstup.Find(_T('>'));
    if((nLeft != -1) && (nRight != -1)) {
    // ano, nejake zavorky tu mam, vyberu to, co je uvnitr + obe zavorky
    vystup=vstup.Mid(nLeft,nRight-nLeft+1);
    }
    // Nyni provedu kontrolu jestli je tam '@' - bez nej by to nebyla adresa
    if(vystup.Find(_T('@')) == -1) vystup.Empty();
    return vystup;
    }
  5. Ve funkci OnConnect zapojte nové funkce do práce výměnou řádků:
      
    // Naplnim tri sloupce s E-maily odesilatelem, predmetem a adresou
    pom=QPB64Decoder(message.GetFrom());
    pView->GetListCtrl().InsertItem(i,pom,0);
    pom=QPB64Decoder(message.GetSubject());
    pView->GetListCtrl().SetItemText(i,1,pom);
    pom=GetAdr(message.GetReplyTo());
    pView->GetListCtrl().SetItemText(i,2,pom);
Zkuste program pustit a připojit se k nějakému E-mailu. Tak co, už je to čitelné? (Než začnete hledat chyby, zkuste se podívat, jestli někdo neposílá hlavičku zakódovanou v UTF-8 nebo něčem ještě jiném :-)

Co bychom si měli z této lekce zapamatovat?

  • Data při komunikaci pomocí POP3 mohou být (a obvykle jsou) kódována.
 

Buď první, kdo ohodnotí tento článek.

Nový komentář

Přihlásit se
  Ještě nemáte vlastní web? Můžete si jej zdarma založit na Blog.cz.