Menu

More Gmail problems (with fixes)

Help
2008-12-29
2013-04-26
  • Vincent Finn

    Vincent Finn - 2008-12-29

    Hi,

    Thanks for fixing the connection side of things, now that is working I started using the dll to examine my Gmail account and hit a few issues.

    The first is that Gmail seems to use different return strings than the ones you are expecting.
    FetchNotOk is "BAD FETCH", and FetchComplete is "OK Success".

    The other problem is that if you call Connection.Read() when there is nothing to receive it'll hang.

    I have put in fixes for these things into ImapCommand.cs, I'll just post teh functions I have changed since the file is quite big.

    1) I have added a patOkSuccess const and test against it as well as patFetchComplete, this works but the regular expression may not be the best one to use.

    2) Added BAD to the expression for patFetchNotOk.

    3) Changed ParseMessages() not to need to call Connection.Read() at the end of the do.while().
    I changed this function quite a bit because I couldn't quite get my head around it the way it was, the only important bits are the test for patOkSuccess and removing the call to Connection.Read().

      Hope this is of use to you, Vin

            #region private variables
            const string patFetchComplete = @"^kw\d+\WOK\W([Ff][Ee][Tt][Cc][Hh]\W|)[Cc][Oo][Mm][Pp][Ll][Ee][Tt][Ee]";
            const string patOkSuccess = @"kw\d+\WOK [Ss][Uu][Cc][Cc][Ee][Ss][Ss]$";
            const string patFetchNotOk = @"^kw\d+\W(NO|BAD)";
            ImapConnect _connection;
            #endregion

    ...

            public void Expunge()
            {
                if (!(Connection.ConnectionState == ConnectionState.Open))
                    NoOpenConnection();
                Connection.Write("EXPUNGE\r\n");

                string response;
                do
                {
                    response = Connection.Read();
                } while (!(response.EndsWith("))") || Regex.IsMatch(response, patFetchComplete) || Regex.IsMatch(response, patFetchNotOk) ||
                    Regex.IsMatch(response, patOkSuccess)));
            }

    ...

            private void ParseMessages(ref ImapMailbox Mailbox)
            {
                List<string> responses = new List<string>();
                string response = string.Empty;
                if (Mailbox.Messages == null)
                    Mailbox.Messages = new List<ImapMailboxMessage>();
                do
                {
                    response = Connection.Read();
                    responses.Add(response);
                } while (!(response.EndsWith("))") || Regex.IsMatch(response, patFetchComplete) || Regex.IsMatch(response, patFetchNotOk) ||
                    Regex.IsMatch(response, patOkSuccess)));

                foreach (string currentResponse in responses)
                {
                    response = currentResponse;
                    if (!response.StartsWith("*")) continue;

                    ImapMailboxMessage Message = new ImapMailboxMessage();
                    Message.Flags = new ImapMessageFlags();
                    Message.Addresses = new ImapAddressCollection();
                    Match match;
                    if ((match = Regex.Match(response, @"\* (\d*)")).Success)
                        Message.ID = Convert.ToInt32(match.Groups[1].ToString());
                    if ((match = Regex.Match(response, @"\(FLAGS \(([^\)]*)\)")).Success)
                        Message.Flags.ParseFlags(match.Groups[1].ToString());
                    if ((match = Regex.Match(response, @"INTERNALDATE ""([^""]+)""")).Success)
                        Message.Received = DateTime.Parse(match.Groups[1].ToString());
                    if ((match = Regex.Match(response, @"RFC822.SIZE (\d+)")).Success)
                        Message.Size = Convert.ToInt32(match.Groups[1].ToString());
                    if ((match = Regex.Match(response, @"ENVELOPE")).Success)
                        response = response.Remove(0, match.Index + match.Length);
                    if ((match = Regex.Match(response, @"\(""(?:\w{3}\, )?([^""]+)""")).Success)
                    {
                        Match subMatch;
                        subMatch = Regex.Match(match.Groups[1].ToString(), @"([\-\+]\d{4}.*|NIL.*)"); //(-\d{4}|-\d{4}[^""]+|NIL)
                        DateTime d;
                        DateTime.TryParse(match.Groups[1].ToString().Remove(subMatch.Index), out d);
                        Message.Sent = d;
                        Message.TimeZone = subMatch.Groups[1].ToString();
                        response = response.Remove(0, match.Index + match.Length);
                    }
                    string TOKEN;
                    int TOKEN_OFFSET = 0;
                    if (response.Contains("(("))
                        TOKEN = "((";
                    else
                    {
                        TOKEN = "\&quot; NIL";
                        TOKEN_OFFSET = 2;
                    }
                    Message.Subject = response.Substring(0, response.IndexOf(TOKEN) + TOKEN_OFFSET).Trim();
                    if (Message.Subject == "NIL")
                        Message.Subject = null;
                    else if ((match = Regex.Match(Message.Subject, "^\&quot;(.*)\&quot;$")).Success)
                        Message.Subject = match.Groups[1].ToString();
                    Message.Subject = ImapDecode.Decode(Message.Subject);
                    response = response.Remove(0, response.Substring(0, response.IndexOf("((")).Length);

                    //if ((match = Regex.Match(response, @"(""[^""]*"" \(\(|NIL)")).Success)
                    //{
                    //    Message.Subject = match.Groups[1].ToString();
                    //    if (Message.Subject == "NIL")
                    //        Message.Subject = null;
                    //    else if (Message.Subject.StartsWith("\&quot;"))
                    //        Message.Subject = Message.Subject.Substring(1, Message.Subject.Length -5);
                    //    response = response.Remove(0, match.Index + match.Length - 3);
                    //}
                    if ((match = Regex.Match(response, @"""<([^>]+)>""\)\)")).Success)
                    {
                        Message.MessageID = match.Groups[1].ToString();
                        response = response.Remove(match.Index).Trim();
                    }
                    if (response.EndsWith("NIL"))
                        response = response.Remove(response.Length - 3);
                    else {
                        match = Regex.Match(response, @"""<([^>]+)>""");
                        Message.Reference = match.Groups[1].ToString();
                    }
                    try
                    {
                        Message.Addresses = Message.Addresses.ParseAddresses(response);
                    }
                    catch (Exception ex)
                    {
                        Message.Errors = response + ex.ToString();
                    }
                    Mailbox.Messages.Add(Message);

                    //response = string.Empty;
                    //do
                    //{
                    //    response += Connection.Read();
                    //} while (!(response.EndsWith("))") || Regex.IsMatch(response, patFetchComplete) || Regex.IsMatch(response, patFetchNotOk)));

                    //match = Regex.Match(response, @"\(FLAGS \(([\w\\]+)\) INTERNALDATE ""([^""]+)"" RFC822\.SIZE (\d+) ENVELOPE \(""([^""]+)"" ""([^""]+)"" \(\(NIL NIL ""([^""]+""\)\)");
                }
            }

    ...

            private string ParseBodyPart(Imap.BodyPartEncoding encoding, Encoding en)
            {
                string response;
                StringBuilder sb = new StringBuilder("");
                do
                {
                    response = Connection.Read();
                    if (Regex.IsMatch(response, patFetchComplete) || Regex.IsMatch(response, patOkSuccess))
                        break;
                    if (encoding == Imap.BodyPartEncoding.BASE64)
                        sb.Append(response);
                    else if (encoding == Imap.BodyPartEncoding.QUOTEDPRINTABLE)
                        if (response.EndsWith("=") || response.EndsWith(")"))
                            sb.Append(response.Substring(0, response.Length - 1));
                        else
                            sb.AppendLine(response);
                    else
                        sb.AppendLine(response);
                } while (true);
                //} while (!(response.EndsWith("==") || response == ")"));
                if (sb.ToString().Trim().EndsWith(")"))
                    sb = sb.Remove(sb.ToString().LastIndexOf(")"), 1);
                if (encoding != BodyPartEncoding.BASE64)
                    return ImapDecode.Decode(sb.ToString(), en);
                return sb.ToString();
            }

     
    • Keith Kikta

      Keith Kikta - 2009-01-22

      I like what you did with the parse messages. I think I am gonna implement it except that I found that some servers send more than one line per message part. The issue is if the string is too long the break it into two lines so I will have to modify it and test otherwise i think what you have is a bit more readable and easier to understand.

      Keith

       
    • Keith Kikta

      Keith Kikta - 2009-03-11

      Vincent,
      I got the new code into source but havent created the new library I am hoping to have enough time to do a list command in the next couple days before I do the next release. Anyway I wanted to see if you could test it out. I think what I've got should work well.

       
      • Vincent Finn

        Vincent Finn - 2009-03-15

        Hi,

        Got the tar ball down and gave it a run through against Gmail.

        I did a select and fetch then got the subject, body and attachments of a few mails and then deleted the mails.

        Everything worked perfectly :o)

          Thanks for that, Vin

         

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.