Questions about wxSMTP and SMTP protocol Topic is solved

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
Sunsawe
Experienced Solver
Experienced Solver
Posts: 54
Joined: Tue Jan 30, 2007 5:04 pm

Questions about wxSMTP and SMTP protocol

Post by Sunsawe »

Hi all,

I tried to implement myself a little smtp client. It was for me a good way to start with wxWidgets and also to study a little bit the SMTP protocol.

I used stmp.gmail.com as server for my test. I can communicate with it but when i tried to send a message (so when i send a MAIL FROM... message), it replied that i
Must issue a STARTTLS command first
.

But when i sent a STARTTLS message, it replied that the command is not recognized!! :shock:
Does someone know about the smtp protocol and can tell me what i have to do with this STARTTLS please? i found some stuff about that on the Internet but except description of what it is supposed to do... nothing.
A concrete example of communication between client and server could be fine. :D

On the other hand, it's fine to explore, but i also have to continue on a other project. So i could probably use wxSMTP for this part.
But... all the links that i found are about wxSMTP 1.1 or 1.2 and the creator indicates that he does not maintain this anymore...
Is somebody else doing it?
Does wxSMTP manage with STARTTLS?
Is there any concrete documentation (didn't find it)?
How to compile the library under VS2005? ( :oops: sorry... but i really didn't succeed...)

ThankS
FlyingIsFun1217
Super wx Problem Solver
Super wx Problem Solver
Posts: 497
Joined: Mon Nov 06, 2006 9:58 pm

Post by FlyingIsFun1217 »

Have you tried it with any other SMTP servers?

FlyingIsFun1217 :)
Sunsawe
Experienced Solver
Experienced Solver
Posts: 54
Joined: Tue Jan 30, 2007 5:04 pm

Post by Sunsawe »

Actually.... yes and no...

Yes, because, when i had this message coming from this server, i tried with others. I noticed that most of them specify in the EHLO's response that they use AUTH LOGIN or whatever.

No, because i didn't find another one using STARTTLS. Thus, i could not compare their behaviors.
Sunsawe
Experienced Solver
Experienced Solver
Posts: 54
Joined: Tue Jan 30, 2007 5:04 pm

Post by Sunsawe »

no ideas...?
upCASE
Moderator
Moderator
Posts: 3176
Joined: Mon Aug 30, 2004 6:55 am
Location: Germany, Cologne

Re: Questions about wxSMTP and SMTP protocol

Post by upCASE »

Hi!
Sunsawe wrote:But when i sent a STARTTLS message, it replied that the command is not recognized!! :shock:
Hmmm...
When I start a standard session with
EHLO
and then STARTTLS, I get a OK.
Sunsawe wrote:Is somebody else doing it?
I guess not.
Sunsawe wrote:Does wxSMTP manage with STARTTLS?
Nope, it doesn't.
Sunsawe wrote:Is there any concrete documentation (didn't find it)?
Did you read and search the relevant RFCs? :)

I'd suggest that for testing the whole thing first, use a different mail provider and implement AUTH LOGIN. It's quite simple to do and most providers allow it.
OS: OpenSuSE, Ubuntu, Win XP Pro
wx: svn
Compiler: gcc 4.5.1, VC 2008, eVC 4

"If it was hard to write it should be hard to read..." - the unknown coder
"Try not! Do. Or do not. There is no try." - Yoda
Sunsawe
Experienced Solver
Experienced Solver
Posts: 54
Joined: Tue Jan 30, 2007 5:04 pm

Post by Sunsawe »

I tried to implement Plain and Cram-MD5 authentication... (succeeded with Login)

I read the rfc but no way to figure out what to do..

With Plain:
It's not supposed to be so difficult as it is just about sending the "username\0username\0password" in base64 to the server.

But each time i tried, it failed!!! i noticed that the chain is almost never totally encoded. The software stops to encode as soon as it reaches the first \0. I tried with ^@ or \000 like i found on some website but it still failed (evenif the chain was totally encoded these times).
Is my base64 a bad class? does someone have a good one? should i put something special in the string to get it encoded? Is there a base64 class in wxWidget?

With Cram-md5:
when i tried to decode the base64 challenge sent by the server, i obtained... nothing. I created the digest with it (many manipulation because all these md5 things are in pure C... ) and when i tried to create a wxString with the digest, my wxString is empty!
And i'm using the cast method that i found on the wiki.
Is there any md5 class in wxWidget?
Is there supposed to be something between the base64 username and the digest in the reply to the server?

Did anybody try this before? succeed? can help me please?
Can you give a good website about that? i can't find one! everything is about simple smtp without authentication.

please help :cry:
upCASE
Moderator
Moderator
Posts: 3176
Joined: Mon Aug 30, 2004 6:55 am
Location: Germany, Cologne

Post by upCASE »

Hi!

It's quite normal that processing of a string stops at \0. This is a string terminator and what one would expect. Your base64 class should accept a length parameter to have it process the entire byte array.
BTW: You don't send "username\0username\0password", but only "\0username\0password" for plain logins. I just tried that on my server and it gave no problems.
There is no direct base64 support, but wxSMTP has a wxBase64 class that works perfectly for me (http://www.wxwidgets.org/wiki/index.php/WxSMTP), but any C implementation should do as well.

I'm not sure about cram-md5 as I never used that, but it shouldn't be that hard to do. Have a look here http://wxchecksums.sourceforge.net/mainpage_en.html. It includes an md5 class.
This http://www.net-track.ch/opensource/cmd5/ might be usefull as well.

Did you try "auth login"? Plain and login are the most common procedures, apart from having them in combination with "POP-before-SMTP".
OS: OpenSuSE, Ubuntu, Win XP Pro
wx: svn
Compiler: gcc 4.5.1, VC 2008, eVC 4

"If it was hard to write it should be hard to read..." - the unknown coder
"Try not! Do. Or do not. There is no try." - Yoda
Sunsawe
Experienced Solver
Experienced Solver
Posts: 54
Joined: Tue Jan 30, 2007 5:04 pm

Post by Sunsawe »

Hi,

Thanks for your help. I succeeded to implement AUTH LOGIN
it works fine.

Now, based on what you said, i'm trying to integrate first the wxBase64 class to my project (for the PLAIN) then i'll try again Cram-md5.

So how can i transform a wxString to a 'const wxUint8 *' as it's needed by the Encode method of the class?

I have some compile errors for the class:

Code: Select all

\wxbase64.cpp(62) : error C2308: concatenating mismatched strings
        Concatenating wide "ABCDEFGHIJKLMNOPQRSTUVWXYZ" with narrow "abcdefghijklmnopqrstuvwxyz"
\wxbase64.cpp(62) : error C2308: concatenating mismatched strings
        Concatenating wide "ABCDEFGHIJKLMNOPQRSTUVWXYZ" with narrow "0123456789+/"
\wxbase64.cpp(71) : error C2664: 'wxString::wxString(int)' : cannot convert parameter 1 from 'const char [3]' to 'int'
        There is no context in which this conversion is possible
how can i solve that?

Again thanks
upCASE
Moderator
Moderator
Posts: 3176
Joined: Mon Aug 30, 2004 6:55 am
Location: Germany, Cologne

Post by upCASE »

Hi!
Glad that at least auth works now.
For plain you can use something like this:

Code: Select all

wxString s = wxBase64::Encode((wxUint8*)"\0myloginname\0myVERY123SeCreTePaSS",34);
If you use wxStrings simply concatenate them adding the two \0 add set the length like

Code: Select all

int length = login.Length() + pass.Length() + 2;
OS: OpenSuSE, Ubuntu, Win XP Pro
wx: svn
Compiler: gcc 4.5.1, VC 2008, eVC 4

"If it was hard to write it should be hard to read..." - the unknown coder
"Try not! Do. Or do not. There is no try." - Yoda
Sunsawe
Experienced Solver
Experienced Solver
Posts: 54
Joined: Tue Jan 30, 2007 5:04 pm

Post by Sunsawe »

I solved the compil errors ( i think...). Don't know why, in the class, the code was like that:

Code: Select all

*static wxString     cvt = _T("ABCDEFGHIJKLMNOPQRSTUVWXYZ"

                        // 22223333333333444444444455
                        // 67890123456789012345678901
                          "abcdefghijklmnopqrstuvwxyz"

                        // 555555556666
                        // 234567890123
                          "0123456789+/");
So i changed it to:

Code: Select all

static wxString     cvt = _T("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
and that :

Code: Select all

wxString cr("\x00d\x00a");
into that :

Code: Select all

wxString cr(wxT("\x00d\x00a"));
then, i tried.

this is the code that i'm using:

Code: Select all

wxString toEncode = wxString(wxT("\0")).Append(Login).Append(wxString(wxT("\0"))).Append(Pass);
	wxString encodedMsg = wxBase64::Encode((wxUint8*)toEncode.data(),toEncode.Length());
Where Login and Pass are two wxString.

But i noticed with the debugger that the "\0" are not in toEncode.
So i tried to create a wxUint array to do it by this way:

Code: Select all

	wxUint8 * tab = new wxUint8[(Login.Length()+Pass.Length()+2)];
But if i can do tab[0]='\0', i don't know how to copy Login.data() into it...

:oops:
Sunsawe
Experienced Solver
Experienced Solver
Posts: 54
Joined: Tue Jan 30, 2007 5:04 pm

Post by Sunsawe »

Well, after some days, i succeeded with Plain and Cram-md5.

Didn't get yet the STARTTLS thing yet, but i'll keep on trying.
Thanks
upCASE
Moderator
Moderator
Posts: 3176
Joined: Mon Aug 30, 2004 6:55 am
Location: Germany, Cologne

Post by upCASE »

Sunsawe wrote:

Code: Select all

wxString toEncode = wxString(wxT("\0")).Append(Login).Append(wxString(wxT("\0"))).Append(Pass);
	wxString encodedMsg = wxBase64::Encode((wxUint8*)toEncode.data(),toEncode.Length());
Where Login and Pass are two wxString.

But i noticed with the debugger that the "\0" are not in toEncode.
So i tried to create a wxUint array to do it by this way:

Code: Select all

	wxUint8 * tab = new wxUint8[(Login.Length()+Pass.Length()+2)];
But if i can do tab[0]='\0', i don't know how to copy Login.data() into it...
Well, I guess the debugger would interpret a string starting with \0 as a zero length string, thus it might not show up correctly.
I'm not even sure that the first approach works, as Length() might return 0 as well for the given reason.

Using the array you could simply memcpy or strncpy your data to it.
Like

Code: Select all

tab[0] = '\0';
strncpy(&tab[1],(char*)login.c_str(),login.Length());
tab[login.Length()+1] = '\0';
strncpy(&tab[login.Length+2],(char*)pass.c_str(),pass.Length());
Not that nice, but should work. Another option to try is your string based solution, but sum up the length manually, don't rely on Length().
OS: OpenSuSE, Ubuntu, Win XP Pro
wx: svn
Compiler: gcc 4.5.1, VC 2008, eVC 4

"If it was hard to write it should be hard to read..." - the unknown coder
"Try not! Do. Or do not. There is no try." - Yoda
Post Reply