SendAndReceive OAuth2 hangs

Aug 23, 2013 at 12:13 PM
Hi Pavel,
I was wondering, why the system remains idle for a long time, after I have found out that following command doesn't work correctly.
First of all I have added some traceevent entries to check what was wrong:
    public bool SendAndReceive(string command, ref ArrayList sResultArray)
    {
        ts.TraceEvent(TraceEventType.Information, 2000, "SendAndReceive: " + command);
        bool result = true;
        CommandCount++;
        string text = string.Concat(new object[]
        {
            "IMAP00", 
            CommandCount, 
            " ", 
            command
        });
        ts.TraceEvent(TraceEventType.Information, 2000, "SendAndReceive: encoding text=" + text);
        byte[] bytes = Encoding.ASCII.GetBytes(text.ToCharArray());
        if (isDebug)
        {
            Console.WriteLine(text);
        }
        try
        {
            if (UseSSL)
            {
                ts.TraceEvent(TraceEventType.Information, 2000, "SendAndReceive: UseSSL");
                ImapSslStream.Write(bytes, 0, bytes.Length);
            }
            else
            {
                ts.TraceEvent(TraceEventType.Information, 2000, "SendAndReceive: not using UseSSL");
                ImapStream.Write(bytes, 0, bytes.Length);
            }
            bool flag = true;
            while (flag)
            {
                string text2 = UseSSL ? ImapSslStreamReader.ReadLine() : ImapStreamReader.ReadLine();
                ts.TraceEvent(TraceEventType.Information, 2000, "SendAndReceive: text2=" + text2);
                if (isDebug)
                {
                    Console.WriteLine(text2);
                }
                if (text2 != null)
                {
                    sResultArray.Add(text2);
                    if (text2.StartsWith("IMAP00" + CommandCount + " OK"))
                    {
                        flag = false;
                    }
                    else
                    {
                        if (text2.StartsWith("IMAP00" + CommandCount + " NO"))
                        {
                            flag = false;
                            result = false;
                        }
                        else
                        {
                            if (text2.StartsWith("IMAP00" + CommandCount + " BAD"))
                            {
                                flag = false;
                                result = false;
                            }
                            else
                            {
                                //if (text2.StartsWith("+ ") && !command.StartsWith("UID FETCH"))
                                //{
                                //    flag = false;
                                //}
                            }
                        }
                    }
                }
            }
        }
        catch (Exception)
        {
            result = false;
        }
        return result;
    }
And here are the result:
ImapX Information: 2000 : SendAndReceive: AUTHENTICATE XOAUTH2 "dXNlcj1zb2xpZC5jcm0BYXV0aD1CZWFyZXIgeuztvghjvOS5BSEVTNlpRaWdPSjlKV2R3N2hFQkF4azdZM2d2bEM0YVdDTENhSDAxaUxyZjNmbWFQUW5fTnRZCgEB"

ImapX Information: 2000 : SendAndReceive: encoding text=IMAP002 AUTHENTICATE XOAUTH2 "dXNlasagagasgsd1zb2xpZC5jcm0BYXV0aD1CZWFyZXIgeWEyOS5BSEVTNlpRaWdPSjlKV2R3N2hFQkF4azdZM2d2bEM0YVdDTENhSDAxaUxyZjNmbWFQUW5fTnRZCgEB"

ImapX Information: 2000 : SendAndReceive: UseSSL
ImapX Information: 2000 : SendAndReceive: text2=+ eyJzdasfasfdXMiOiI0MDAiLCJzY2hlbWVzIjoiQmVhcmVyIiwic2NvcGUiOiJodHRwczovL21haWwuZ29vZ2xlLmNvbS8ifQ==

As far as I understand the problem, it runs once the while(flag) loop and than maybe it just hangs on the line ImapSslStreamReader.ReadLine()


BTW I am using OAuth2LogIn to connect to GMail.

Thanks so much for your support !!
Coordinator
Aug 23, 2013 at 6:53 PM
Edited Aug 23, 2013 at 6:54 PM
Hi mzda,

thank you for your feedback! That the library was hanging on some requests was a known issue, but I already provided a fix for this. If you look at the code of SendAndReceive in the repository, you will see that it differs from the code you posted. There are also some changes in how authentication is done.

The code in the repository is more or less stable and will be part of the coming release. Just give it a try.

Best regards,

Pavel Azanov
Aug 24, 2013 at 3:40 PM
Hi Pavel,
Ok. Thanks a lot for your support. I will try to replace that code from the repo. Should I only replace this one or what else ?
Thanks. 

Mzda
Aug 26, 2013 at 8:54 AM
Hi Pavel,
unfortunately it still doesn't work:

ImapX Information: 2000 : Monday, August 26, 2013 10:53 AM;IBS_TraceSource.cs;TraceEvent;LineNo 30;SendAndReceive; Command=CAPABILITY
ImapX Information: 2000 : Monday, August 26, 2013 10:53 AM;IBS_TraceSource.cs;TraceEvent;LineNo 30;SendAndReceive; text=IMAPX1 CAPABILITY

ImapX Information: 2000 : Monday, August 26, 2013 10:53 AM;IBS_TraceSource.cs;TraceEvent;LineNo 30;SendAndReceive; loop; before Readline
ImapX Information: 2000 : Monday, August 26, 2013 10:53 AM;IBS_TraceSource.cs;TraceEvent;LineNo 30;SendAndReceive; loop; tmp=* CAPABILITY IMAP4rev1 UNSELECT IDLE NAMESPACE QUOTA ID XLIST CHILDREN X-GM-EXT-1 XYZZY SASL-IR AUTH=XOAUTH AUTH=XOAUTH2 AUTH=PLAIN AUTH=PLAIN-CLIENTTOKEN
ImapX Information: 2000 : Monday, August 26, 2013 10:53 AM;IBS_TraceSource.cs;TraceEvent;LineNo 30;SendAndReceive; loop; before Readline
ImapX Information: 2000 : Monday, August 26, 2013 10:53 AM;IBS_TraceSource.cs;TraceEvent;LineNo 30;SendAndReceive; loop; tmp=IMAPX1 OK Thats all she wrote! w17if9951860eei.18
ImapX Information: 2000 : Monday, August 26, 2013 10:53 AM;IBS_TraceSource.cs;TraceEvent;LineNo 30;user=myuser
ImapX Information: 2000 : Monday, August 26, 2013 10:53 AM;IBS_TraceSource.cs;TraceEvent;LineNo 30;auth=Bearer
ImapX Information: 2000 : Monday, August 26, 2013 10:53 AM;IBS_TraceSource.cs;TraceEvent;LineNo 30;token=ya29.AHES6ZQigOJ9JWdw7hEBAxk7Y3gvlC4aWCLCaH01iLrf3fmaPQn_NtY
ImapX Information: 2000 : Monday, August 26, 2013 10:53 AM;IBS_TraceSource.cs;TraceEvent;LineNo 30;Write System.Byte[]
ImapX Information: 2000 : Monday, August 26, 2013 10:53 AM;IBS_TraceSource.cs;TraceEvent;LineNo 30;Write System.Byte[]
ImapX Information: 2000 : Monday, August 26, 2013 10:53 AM;IBS_TraceSource.cs;TraceEvent;LineNo 30;Write System.Byte[]
ImapX Information: 2000 : Monday, August 26, 2013 10:53 AM;IBS_TraceSource.cs;TraceEvent;LineNo 30;SendAndReceive AUTHENTICATE XOAUTH2 "dXNlcj1zb2xpZC5jcm0BYXV0aD1CZWFyZXIgeWEyOS5BSEVTNlpRaWdPSjlKV2R3N2hFQkF4azdZM2d2bEM0YVdDTENhSDAxaUxyZjNmbWFQUW5fTnRZCgEB"
ImapX Information: 2000 : Monday, August 26, 2013 10:53 AM;IBS_TraceSource.cs;TraceEvent;LineNo 30;user=myuser
ImapX Information: 2000 : Monday, August 26, 2013 10:53 AM;IBS_TraceSource.cs;TraceEvent;LineNo 30;auth=Bearer
ImapX Information: 2000 : Monday, August 26, 2013 10:53 AM;IBS_TraceSource.cs;TraceEvent;LineNo 30;token=ya29.AHES6ZQigOJ9JWdw7hEBAxk7Y3gvlC4aWCLCaH01iLrf3fmaPQn_NtY
ImapX Information: 2000 : Monday, August 26, 2013 10:53 AM;IBS_TraceSource.cs;TraceEvent;LineNo 30;Write System.Byte[]
ImapX Information: 2000 : Monday, August 26, 2013 10:53 AM;IBS_TraceSource.cs;TraceEvent;LineNo 30;Write System.Byte[]
ImapX Information: 2000 : Monday, August 26, 2013 10:53 AM;IBS_TraceSource.cs;TraceEvent;LineNo 30;Write System.Byte[]
ImapX Information: 2000 : Monday, August 26, 2013 10:53 AM;IBS_TraceSource.cs;TraceEvent;LineNo 30;SendAndReceive; Command=AUTHENTICATE XOAUTH2 "dXNlcj1zb2xpZC5jcm0BYXV0aD1CZWFyZXIgeWEyOS5BSEVTNlpRaWdPSjlKV2R3N2hFQkF4azdZM2d2bEM0YVdDTENhSDAxaUxyZjNmbWFQUW5fTnRZCgEB"
ImapX Information: 2000 : Monday, August 26, 2013 10:53 AM;IBS_TraceSource.cs;TraceEvent;LineNo 30;SendAndReceive; text=IMAPX2 AUTHENTICATE XOAUTH2 "dXNlcj1zb2xpZC5jcm0BYXV0aD1CZWFyZXIgeWEyOS5BSEVTNlpRaWdPSjlKV2R3N2hFQkF4azdZM2d2bEM0YVdDTENhSDAxaUxyZjNmbWFQUW5fTnRZCgEB"

ImapX Information: 2000 : Monday, August 26, 2013 10:53 AM;IBS_TraceSource.cs;TraceEvent;LineNo 30;SendAndReceive; loop; before Readline
ImapX Information: 2000 : Monday, August 26, 2013 10:53 AM;IBS_TraceSource.cs;TraceEvent;LineNo 30;SendAndReceive; loop; tmp=+ eyJzdGF0dXMiOiI0MDAiLCJzY2hlbWVzIjoiQmVhcmVyIiwic2NvcGUiOiJodHRwczovL21haWwuZ29vZ2xlLmNvbS8ifQ==
ImapX Information: 2000 : Monday, August 26, 2013 10:53 AM;IBS_TraceSource.cs;TraceEvent;LineNo 30;SendAndReceive; loop; before Readline

it hangs on the last line.
Here is your traced code:
    public bool Login(IImapCredentials credentials)
    {
        Credentials = credentials;
        IList<string> data = new List<string>();
        ImapClient.ts.TraceEvent("SendAndReceive " + credentials.ToCommand(Capabilities));
        IsAuthenticated = SendAndReceive(credentials.ToCommand(Capabilities), ref data);
        ImapClient.ts.TraceEvent("SendAndReceive is finished");
        return IsAuthenticated;
    }


    private string PrepareOAuthCredentials(string login, string token)
    {
        ImapClient.ts.TraceEvent("user=" + login);
        byte[] userData = Encoding.UTF8.GetBytes("user=" + login);
        ImapClient.ts.TraceEvent("auth=Bearer ");
        byte[] tokenLabelData = Encoding.UTF8.GetBytes("auth=Bearer ");
        ImapClient.ts.TraceEvent("token=" + token);
        byte[] tokenData = Encoding.UTF8.GetBytes(token + "\n");

        using (var stream = new MemoryStream())
        {
            ImapClient.ts.TraceEvent("Write " + userData);
            stream.Write(userData, 0, userData.Length);
            stream.WriteByte(1);
            ImapClient.ts.TraceEvent("Write " + tokenLabelData);
            stream.Write(tokenLabelData, 0, tokenLabelData.Length);
            ImapClient.ts.TraceEvent("Write " + tokenData);
            stream.Write(tokenData, 0, tokenData.Length);
            stream.WriteByte(1);
            stream.WriteByte(1);
            return Convert.ToBase64String(stream.ToArray());
        }
    }


    public bool SendAndReceive(string command, ref IList<string> data)
    {
        ImapClient.ts.TraceEvent("SendAndReceive; Command=" + command); 

        const string tmpl = "IMAPX{0} {1}";
        _counter++;

        var parts = new Queue<string>(new Regex(@"\r\n").Split(command).Where(_ => !string.IsNullOrEmpty(_)));

        string text = string.Format(tmpl, _counter, parts.Dequeue().Trim()) + "\r\n";
        ImapClient.ts.TraceEvent("SendAndReceive; text=" + text); 
        byte[] bytes = Encoding.UTF8.GetBytes(text.ToCharArray());

        try
        {
            _ioStream.Write(bytes, 0, bytes.Length);

            while (true)
            {
                ImapClient.ts.TraceEvent("SendAndReceive; loop; before Readline"); 
                string tmp = _streamReader.ReadLine();
                ImapClient.ts.TraceEvent("SendAndReceive; loop; tmp=" + tmp); 

                if (IsDebug)
                    Console.WriteLine(tmp);

                data.Add(tmp);

                if (tmp.StartsWith("+ ") && parts.Count > 0)
                {
                    ImapClient.ts.TraceEvent("SendAndReceive; loop; tmp.StartsWith(\" + \") && parts.Count > 0");
                    bytes = Encoding.UTF8.GetBytes((parts.Dequeue().Trim() + "\r\n").ToCharArray());
                    _ioStream.Write(bytes, 0, bytes.Length);
                    continue;
                }

                if (tmp.StartsWith(string.Format(tmpl, _counter, ResponseType.Ok)))
                    return true;

                if (tmp.StartsWith(string.Format(tmpl, _counter, ResponseType.PreAuth)))
                    return true;

                if (tmp.StartsWith(string.Format(tmpl, _counter, ResponseType.NO)) ||
                    tmp.StartsWith(string.Format(tmpl, _counter, ResponseType.Bad)))
                    return false;
            }
        }
        catch (AuthenticationException ex)
        {
            throw;
        }
        catch (Exception ex)
        {
            ex.ToString();
        }

        return false;
    }
Coordinator
Aug 26, 2013 at 10:04 AM
Hi mzda,

thank you for your tests, have you tried compiling the sample application from sample code? I tested OAuth2 on GMail using it, and it works just fine. I'll try it with a couple more accounts.
Aug 28, 2013 at 6:49 AM
Hi Pavel,
I have not tried the sapmle code yet, but after I have tried another library for the same purpose, I realized that the problem was the access token is not valid anymore.
I think you should somehow change the sendandreceive function, so it wont come tu such situation, where the code is waiting for the streamreader.readline.
Coordinator
Aug 28, 2013 at 10:05 AM
Hi mzda,

you're right, I will add a check that will allow to cancel the operation before it goes into an infinite loop, waiting for a response from server.