Work at SourceForge, help us to make it a better place! We have an immediate need for a Support Technician in our San Francisco or Denver office.

Close

How to synchronize?

Help
Michael
2012-06-28
2013-09-06
  • Michael
    Michael
    2012-06-28

    Hi,

    I am using vmime to connect to an IMAP server, download the messages from a specific folder, and store them using maildir. This is working well.

    Now, i am trying to check for new messages on the server, and download only the new messages. I know i could do that using the SEEN/UNSEEN flags, but the problem is, that another client i'm using could have already changed these flags before.

    I also have plans to improve my application, with things like deleting messages, etc. I have found an RFC that specifies everything that i should do (http://www.faqs.org/rfcs/rfc4549.html), but i am wondering if someone has already implemented that, or something similar.

    I couldn't find anything in vmime that handles this local/remote synchronization. Does that feature exist? If not, what do you recommend me to do?

    Thanks!
    Michael

     
  • Hello Michael!

    There is no synchronization facility in VMime, yet. This is one of the planned improvements, but it requires a lot of time to develop something enough generic to be integrated into the library.

    For now, you may develop a simple synchronization system, develop it yourself by keeping track of already downloaded message IDs, then downloading new ones.

    If you plan to work on it, your contributions are welcome!

    Vincent

     
  • Michael
    Michael
    2012-06-29

    Thanks for your answer! I'll try implementing something using message IDs.

    In fact, i'm having a problem related to that: i can't get the IDs!

    I can get other fields in the header with calls like this:

    hdr->Sender()->generate().c_str()
    

    But the messageId call doesn't return a value, and throws an exception telling "Field not found". The strange thing is that the Message-ID header exists in the message, and has a value.

    I'm currently trying to get the id using the following code (found it here in the forum):

    std::ostringstream oss_message_id;
    vmime::utility::outputStreamAdapter ossAdapter_message_id(oss_message_id);
    const vmime::messageId m_id = *hdr->MessageId()->getValue().dynamicCast <const vmime::messageId>();
    m_id.generate(ossAdapter_message_id, vmime::lineLengthLimits::infinite, 0, NULL );
    std::cout << "ID: " << oss_message_id.str() << std::endl;
    

    "hdr" is a "vmime::ref <const vmime::header> hdr" object.

    I have tried some variations n that code, but get the same result.

    Do you have an idea of what could be wrong? Thanks a lot!

     
  • Michael
    Michael
    2012-06-29

    I have also tried the getUniqueId method, and it returns a blank string.

     
  • Hello,

    The right UID to use is the one returned by vmime::net::message::getUniqueId().
    It should not be empty, as all IMAP servers must support this.

    Could you please send me a full working example of your code? (connection/message fetching/…)
    Please be sure to remove any login/password from it.

    Vincent

     
  • Michael
    Michael
    2012-06-29

    Ahh, nevermind… FOund it.

    I was missing the

    vmime::net::folder::FETCH_UID
    

    flag when calling

    fetchMessages
    

    .

    It is working now.

    Thanks again!

     
  • Hello. Is there a way to get a message based on UID instead of a message number? Also, it would be nice to get the UID subsequent to another one.

     
  • Hello!

    There is no way to get message by UID for now.

    There is also a problem with IMAPFolder::getMessage(), as message sequence numbers can be reassigned during a session (eg. if a message is removed from the mailbox).

    I will try to work on this issue this weekend!

    Vincent

     
  • Thanks. No idea why half of your message is struck out but it sounds really good if you could look into this :-) Relying on message sequence numbers for getMessage() is indeed not safe even within a session. AFAIK, UIDs can at least be assumed to not change within a session but there are some rare cases when they change between sessions, in which case the UIDVALIDITY should change.

     
  • Hi!

    I have committed revision "a68cebf12a", which contains these new functions in vmime::net::folder:

    virtual ref <message> getMessageByUID(const message::uid& uid) = 0;
    virtual std::vector <ref <message> > getMessagesByUID(const std::vector <message::uid>& uids) = 0;
    

    As for message numbers, VMime actually maintains them up-to-date by incrementing/decrementing sequence numbers when messages are added/deleted, so that should not cause any problem (as long as nobody access to the same mailbox while a session is open in VMime).

    Vincent

     
  • Great!! I will try it out. Is it possible to iterate through the messages using UIDs? That would be great for synchronization as one could save the highest UID of the previous session and then later check for new ones with UIDs higher than that.

    By the way, I noticed some annoying compiler warnings in the git tree. parserInputStreamAdapter.hpp lines 85 and 104.I guess you need to cast that 0?

    return (readBytes == 1 ? buffer : static_cast<value_type>(0));

     
  • The following function is available on vmime::net::folder to retrieve messages with UIDs higher than a specified one:

    virtual std::vector <int> getMessageNumbersStartingOnUID(const message::uid& uid) = 0;
    

    As for the warning, I fixed it, thanks!

    Vincent

     
  • Thanks. I'm eager to try this out so I tried to merge the git tree into my local repository. I hope I didn't do anything wrong. A new issue emerged: I can no longer extract a text part of my message without the header. Should this work?

    (partial code)

    parsedMsg = msg->getParsedMessage();
    vmime::messageParser mp(parsedMsg);
    const vmime::textPart& part = *mp.getTextPartAt(i);
    const vmime::textPart& tp = dynamic_cast<const vmime::textPart&>(part);
    std::stringstream messagestream;
    vmime::utility::outputStreamAdapter out(messagestream);
    vmime::utility::charsetFilteredOutputStream fout(tp.getCharset(), vmime::charset("utf-8"), out);
    tp.getText()->extract(fout);

     
  • That's excellent. It works like it should now. Thanks.

    Now back to the synch stuff…

     
  • Uhm…seems to me like there are still cases when part extraction fails and all of them are empty. I'm not sure in which cases it happens though

     
  • Hello!

    Did you try to enable IMAP logging to see what's going on in the exchanges between client and server?

    Vincent

     
  • No, I will try that that. I thought the problem was in part extraction since I can extract the full message just fine with msg->extract()

     
  • It may also be that either VMime sends a bad command to the IMAP server (or gets a bad response from it). It may help to find out in which case this problem occurs.

     
  • OK, so what should I enable to get a log? VMIME_DEBUG in IMAPConnection.cpp?

     
  • Uncomment the following line in vmime/net/imap/IMAPParser.hpp:

    #define DEBUG_RESPONSE 1
    
     
  • Plenty of debug output but I don't see anything that looks apparently wrong…

     
  • Well, unless I'm completely blind it seems to me like extraction is only working in case there is exactly one plain text part. In case there is an html part involved, extraction doesn't work neither for that part nor for the plain text (in case it exists). Does that work for you?

     
  • tremolo72
    tremolo72
    2013-09-06

    I am having difficulties using status() to pull down new messages...I am getting "Object not fetched" exceptions when I try to parse. Do I have to use fetchMessage() or is this not yet implemented??