Question

I'm using the Mailcore library for an iOS email client. I want to mark an email as viewed (ie set the IMAP SEEN flag on for the message) whenever someone views it.

This is how Mailcore indicates that a message has been read:

- (BOOL)isUnread {
    struct mail_flags *flags = myMessage->msg_flags;
    if (flags != NULL) {
        BOOL flag_seen = (flags->fl_flags & MAIL_FLAG_SEEN);
        return !flag_seen;
    }        
    return NO;
}

This is what I did to set a message as read:

- (void)setIsRead {
    struct mail_flags *flags = myMessage->msg_flags;
    flags->fl_flags = (flags->fl_flags | MAIL_FLAG_SEEN);
}

(I confirmed that it works at least in the same session.. ie if I call this message on an unread message, then call [self isUnread] it returns false)

My problem is that this doesn't impact the actual IMAP server. Ie if I view the same email in my gmail, it will appear unread still.

Also in the CTCoreMessage documentation:

CTCoreMessage is how you work with messages. The easiest way to instantiate a CTCoreMessage is to first setup a CTCoreAccount object and then get a CTCoreFolder object and then use it’s convenience method messageWithUID: to get a message object you can work with.

I did both of those things (on thing that may be worth mentioning is that I keep my IMAP connection alive all the time.. but I keep it idle when I'm not actively syncing or sending emails etc.. but before I call the [self setIsRead] above, I send it the IMAP done command).

So what is missing? My thoughts is that I'm just changing the local structure of the message that I've already fetched from the IMAP server.. but I'm not updating the server with the new information. How do I do that? In Mailcore the only way to interact with the server is via +sendMessage:server:username:password:port:connectionType:useAuth:error: but then this would be the same as sending an email.. which is definitely not what I want.

Ideas?

update: basically I just want to be able to issue the store IMAP command like so (I've confirmed it works on the Telnet command line):

tag store %message_number% flags \Seen
* %message_number% FETCH (FLAGS (\Seen))
tag OK Success
Was it helpful?

Solution

Author of MailCore here.

I recommend using the method setFlags:forMessage on CTCoreFolder as documented here: http://libmailcore.com/api/Classes/CTCoreFolder.html#//api/name/setFlags:forMessage:

What you have above will overwrite any existing flags. Instead get the current flags using flagsForMessage:flags and then using bitwise operators change the flag you'd like. Then set the flag on the server

OTHER TIPS

as it turns out.. the store command exists in libetpan.. here is my implementation:

- (void)setIsRead {
    struct mailimap_set *set;
    struct mailmessage *messageStruct = [self messageStruct];
    struct mailimap_flag_list*flist;
    struct mailimap_store_att_flags * store_flags;
    int err;

    set = mailimap_set_new_single(messageStruct->msg_index);

    flist = mailimap_flag_list_new_empty();
    mailimap_flag_list_add(flist,mailimap_flag_new_seen());
    // TODO: ensure that we're not overwriting original flags of message
    store_flags = mailimap_store_att_flags_new_set_flags(flist);

    err = mailimap_store([self imapSession], set, store_flags);

    mailimap_set_free(set);
    mailimap_store_att_flags_free(store_flags);

    if (err != MAILIMAP_NO_ERROR) {
        NSException *exception = [NSException
                                  exceptionWithName:CTUnknownError
                                  reason:[NSString stringWithFormat:@"Err num: %d", err]
                                  userInfo:nil];
        [exception raise];
    }
}

Have you seen the CTCoreFolder API for working with messages (including setting flags)?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top