/* * MailCore * * Copyright (C) 2007 - Matt Ronge * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the MailCore project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #import #import "CTCoreMessage.h" #import "CTCoreFolder.h" #import "MailCoreTypes.h" #import "CTCoreAddress.h" #import "CTMIMEFactory.h" #import "CTMIME_MessagePart.h" #import "CTMIME_TextPart.h" #import "CTMIME_MultiPart.h" #import "CTMIME_SinglePart.h" #import "CTBareAttachment.h" #import "CTMIME_HtmlPart.h" #import "MailCoreUtilities.h" @implementation CTCoreMessage @synthesize mime=myParsedMIME, lastError, parentFolder; - (id)init { self = [super init]; if (self) { struct mailimf_fields *fields = mailimf_fields_new_empty(); myFields = mailimf_single_fields_new(fields); mailimf_fields_free(fields); } return self; } - (id)initWithMessageStruct:(struct mailmessage *)message { self = [super init]; if (self) { assert(message != NULL); myMessage = message; myFields = mailimf_single_fields_new(message->msg_fields); } return self; } - (id)initWithFileAtPath:(NSString *)path { return [self initWithString:[NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:NULL]]; } - (id)initWithString:(NSString *)msgData { struct mailmessage *msg = data_message_init((char *)[msgData cStringUsingEncoding:NSUTF8StringEncoding], [msgData lengthOfBytesUsingEncoding:NSUTF8StringEncoding]); int err; struct mailmime *dummyMime; /* mailmessage_get_bodystructure will fill the mailmessage struct for us */ err = mailmessage_get_bodystructure(msg, &dummyMime); if (err != MAIL_NO_ERROR) { return nil; } return [self initWithMessageStruct:msg]; } - (void)dealloc { if (myMessage != NULL) { mailmessage_flush(myMessage); mailmessage_free(myMessage); } if (myFields != NULL) { mailimf_single_fields_free(myFields); } self.lastError = nil; self.parentFolder = nil; [myParsedMIME release]; [super dealloc]; } - (NSError *)lastError { return lastError; } - (BOOL)hasBodyStructure { if (myParsedMIME == nil) { return NO; } return YES; } - (BOOL)fetchBodyStructure { if (myMessage == NULL) { return NO; } int err; struct mailmime *dummyMime; //Retrieve message mime and message field err = mailmessage_get_bodystructure(myMessage, &dummyMime); if (err != MAIL_NO_ERROR) { self.lastError = MailCoreCreateErrorFromIMAPCode(err); return NO; } CTMIME *oldMIME = myParsedMIME; myParsedMIME = [[CTMIMEFactory createMIMEWithMIMEStruct:[self messageStruct]->msg_mime forMessage:[self messageStruct]] retain]; [oldMIME release]; return YES; } - (void)setBodyStructure:(struct mailmime *)mime { CTMIME *oldMIME = myParsedMIME; myMessage->msg_mime = mime; myParsedMIME = [[CTMIMEFactory createMIMEWithMIMEStruct:[self messageStruct]->msg_mime forMessage:[self messageStruct]] retain]; [oldMIME release]; } - (void)setFields:(struct mailimf_fields *)fields { if (myFields != NULL) mailimf_single_fields_free(myFields); myFields = mailimf_single_fields_new(fields); } - (NSString *)body { if (myFields == NULL || myParsedMIME == nil) { [self fetchBodyStructure]; } NSMutableString *result = [NSMutableString string]; BOOL success = [self _buildUpBodyText:myParsedMIME result:result]; if (!success) { return nil; } return result; } - (BOOL)hasHtmlBody:(CTMIME *)mime { if ([mime isKindOfClass:[CTMIME_MessagePart class]]) { return [self hasHtmlBody:[mime content]]; } else if ([mime isKindOfClass:[CTMIME_TextPart class]]) { if ([[mime.contentType lowercaseString] rangeOfString:@"text/html"].location != NSNotFound) { return YES; } } else if ([mime isKindOfClass:[CTMIME_MultiPart class]]) { return YES; } return NO; } - (BOOL)hasHtmlBody { CTMIME* mime = myParsedMIME; return [self hasHtmlBody:mime]; } - (NSString *)htmlBody { if (myFields == NULL || myParsedMIME == nil) { [self fetchBodyStructure]; } NSMutableString *result = [NSMutableString string]; BOOL success = [self _buildUpHtmlBodyText:myParsedMIME result:result]; if (!success) { return nil; } return result; } - (NSString *)bodyPreferringPlainText:(BOOL *)isHTML { NSString *body = [self body]; *isHTML = NO; if ([body length] == 0) { body = [self htmlBody]; *isHTML = YES; } return body; } - (BOOL)_buildUpBodyText:(CTMIME *)mime result:(NSMutableString *)result { if (mime == nil) return NO; if ([mime isKindOfClass:[CTMIME_MessagePart class]]) { return [self _buildUpBodyText:[mime content] result:result]; } else if ([mime isKindOfClass:[CTMIME_TextPart class]]) { if ([[mime.contentType lowercaseString] rangeOfString:@"text/plain"].location != NSNotFound) { BOOL success = [(CTMIME_TextPart *)mime fetchPart]; if (!success) { return NO; } NSString* y = [mime content]; if(y == nil) { return NO; } [result appendString:y]; } } else if ([mime isKindOfClass:[CTMIME_MultiPart class]]) { //TODO need to take into account the different kinds of multipart NSEnumerator *enumer = [[mime content] objectEnumerator]; CTMIME *subpart; while ((subpart = [enumer nextObject])) { BOOL success = [self _buildUpBodyText:subpart result:result]; if (!success) { return NO; } } } return YES; } - (BOOL)_buildUpHtmlBodyText:(CTMIME *)mime result:(NSMutableString *)result { if (mime == nil) return NO; if ([mime isKindOfClass:[CTMIME_MessagePart class]]) { return [self _buildUpHtmlBodyText:[mime content] result:result]; } else if ([mime isKindOfClass:[CTMIME_TextPart class]]) { if ([[mime.contentType lowercaseString] rangeOfString:@"text/html"].location != NSNotFound) { BOOL success = [(CTMIME_TextPart *)mime fetchPart]; if (!success) { return NO; } NSString* y = [mime content]; if(y == nil) { return NO; } [result appendString:y]; } } else if ([mime isKindOfClass:[CTMIME_MultiPart class]]) { //TODO need to take into account the different kinds of multipart NSEnumerator *enumer = [[mime content] objectEnumerator]; CTMIME *subpart; while ((subpart = [enumer nextObject])) { BOOL success = [self _buildUpHtmlBodyText:subpart result:result]; if (!success) { return NO; } } } return YES; } - (void) setHTMLBody:(NSString*)htmlString textBody:(NSString*)plainString { /* * Message structure: * * [ msg root ] * --> multipart/alternative (Body) * -----> text * -----> html */ // Body (multipart/alternative) CTMIME_MultiPart* bodyMultipart = [CTMIME_MultiPart mimeMultiPart]; bodyMultipart.contentType = @"multipart/alternative"; CTMIME_TextPart* bodyTextPart = [CTMIME_TextPart mimeTextPartWithString:plainString]; CTMIME_HtmlPart* bodyHtmlPart = [CTMIME_HtmlPart mimeTextPartWithString:htmlString]; [bodyMultipart addMIMEPart: bodyTextPart ]; [bodyMultipart addMIMEPart: bodyHtmlPart ]; // Root CTMIME_MessagePart* messagePartRoot = [CTMIME_MessagePart mimeMessagePartWithContent:bodyMultipart]; [myParsedMIME release]; myParsedMIME = [messagePartRoot retain]; } - (void)setBody:(NSString *)body { CTMIME *oldMIME = myParsedMIME; CTMIME_TextPart *text = [CTMIME_TextPart mimeTextPartWithString:body]; // If myParsedMIME is already a multi-part mime, just add it. otherwise replace it. //TODO: If setBody is called multiple times it will add text parts multiple times. Instead // it should find the existing text part (if there is one) and replace it if ([myParsedMIME isKindOfClass:[CTMIME_MultiPart class]]) { [(CTMIME_MultiPart *)myParsedMIME addMIMEPart:text]; } else { CTMIME_MessagePart *messagePart = [CTMIME_MessagePart mimeMessagePartWithContent:text]; myParsedMIME = [messagePart retain]; [oldMIME release]; } } - (void)setHTMLBody:(NSString *)body{ CTMIME *oldMIME = myParsedMIME; CTMIME_HtmlPart *text = [CTMIME_HtmlPart mimeTextPartWithString:body]; CTMIME_MessagePart *messagePart = [CTMIME_MessagePart mimeMessagePartWithContent:text]; myParsedMIME = [messagePart retain]; [oldMIME release]; } - (NSArray *)attachments { NSMutableArray *attachments = [NSMutableArray array]; CTMIME_Enumerator *enumerator = [myParsedMIME mimeEnumerator]; CTMIME *mime; while ((mime = [enumerator nextObject])) { if ([mime isKindOfClass:[CTMIME_SinglePart class]]) { CTMIME_SinglePart *singlePart = (CTMIME_SinglePart *)mime; if (singlePart.attached) { CTBareAttachment *attach = [[CTBareAttachment alloc] initWithMIMESinglePart:singlePart]; [attachments addObject:attach]; [attach release]; } } } return attachments; } - (void)addAttachment:(CTCoreAttachment *)attachment { CTMIME_MultiPart *multi; CTMIME_MessagePart *msg; if ([myParsedMIME isKindOfClass:[CTMIME_MessagePart class]]) { msg = (CTMIME_MessagePart *)myParsedMIME; CTMIME *sub = [msg content]; // Creat new multimime part if needed if ([sub isKindOfClass:[CTMIME_MultiPart class]]) { // Assuming this is the body if ([sub.contentType isEqualToString:@"multipart/alternative"]) { /* * Transform the following * message structure: * * [ msg root ] * --> multipart/alternative * -----> text * -----> html * * into: * * [ MessagePart Root ] * --> multipart/mixed * -----> attachments * -----> multipart/alternative * --------> text * --------> html */ CTMIME_MultiPart* multipartMixed = [CTMIME_MultiPart mimeMultiPart]; [multipartMixed addMIMEPart:sub]; multi = multipartMixed; [msg setContent:multipartMixed]; } else multi = (CTMIME_MultiPart *)sub; } else { multi = [CTMIME_MultiPart mimeMultiPart]; [multi addMIMEPart:sub]; [msg setContent:multi]; } // add new SinglePart which encodes the attachment in base64 CTMIME_SinglePart *attpart = [CTMIME_SinglePart mimeSinglePartWithData:[attachment data]]; attpart.contentType = [attachment contentType]; attpart.filename = [attachment filename]; [multi addMIMEPart:attpart]; } } - (NSString *)subject { if (myFields->fld_subject == NULL) return nil; NSString *decodedSubject = MailCoreDecodeMIMEPhrase(myFields->fld_subject->sbj_value); if (decodedSubject == nil) return nil; return decodedSubject; } - (void)setSubject:(NSString *)subject { struct mailimf_subject *subjectStruct; subjectStruct = mailimf_subject_new(strdup([subject cStringUsingEncoding:NSUTF8StringEncoding])); if (myFields->fld_subject != NULL) mailimf_subject_free(myFields->fld_subject); myFields->fld_subject = subjectStruct; } - (struct mailimf_date_time*)libetpanDateTime { if(!myFields || !myFields->fld_orig_date || !myFields->fld_orig_date->dt_date_time) return NULL; return myFields->fld_orig_date->dt_date_time; } - (NSTimeZone*)senderTimeZone { struct mailimf_date_time *d; if((d = [self libetpanDateTime]) == NULL) return nil; NSInteger timezoneOffsetInSeconds = 3600*d->dt_zone/100; return [NSTimeZone timeZoneForSecondsFromGMT:timezoneOffsetInSeconds]; } - (NSDate *)senderDate { if ( myFields->fld_orig_date == NULL) { return nil; } else { struct mailimf_date_time *d; if ((d = [self libetpanDateTime]) == NULL) return nil; NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; calendar.timeZone = [self senderTimeZone]; NSDateComponents *comps = [[NSDateComponents alloc] init]; [comps setYear:d->dt_year]; [comps setMonth:d->dt_month]; [comps setDay:d->dt_day]; [comps setHour:d->dt_hour]; [comps setMinute:d->dt_min]; [comps setSecond:d->dt_sec]; NSDate *messageDate = [calendar dateFromComponents:comps]; [comps release]; [calendar release]; return messageDate; } } - (BOOL)isUnread { return ![self isFlagSet:MAIL_FLAG_SEEN withDefault:YES]; } - (BOOL)isDeleted { return [self isFlagSet:MAIL_FLAG_DELETED withDefault:NO]; } - (BOOL)isStarred { return [self isFlagSet:MAIL_FLAG_FLAGGED withDefault:NO]; } - (BOOL)isFlagSet:(NSUInteger)flag withDefault:(BOOL)def { struct mail_flags *flags = myMessage ? myMessage->msg_flags : NULL; return flags == NULL ? def : flags->fl_flags & flag; } - (BOOL)isNew { struct mail_flags *flags = myMessage ? myMessage->msg_flags : NULL; if (flags != NULL) { BOOL flag_seen = (flags->fl_flags & MAIL_FLAG_SEEN); BOOL flag_new = (flags->fl_flags & MAIL_FLAG_NEW); return !flag_seen && flag_new; } return NO; } - (NSString *)messageId { if (myFields->fld_message_id != NULL) { char *value = myFields->fld_message_id->mid_value; return [NSString stringWithCString:value encoding:NSUTF8StringEncoding]; } return nil; } - (NSUInteger)uid { if (myMessage && myMessage->msg_uid) { NSString *uidString = [[NSString alloc] initWithCString:myMessage->msg_uid encoding:NSASCIIStringEncoding]; NSUInteger uid = (NSUInteger)[[[uidString componentsSeparatedByString:@"-"] objectAtIndex:1] intValue]; [uidString release]; return uid; } return 0; } - (NSUInteger)messageSize { return [self messageStruct]->msg_size; } - (NSUInteger)flags { if (myMessage != NULL && myMessage->msg_flags != NULL) { return myMessage->msg_flags->fl_flags; } return 0; } - (NSArray *)extionsionFlags { if (myMessage != NULL && myMessage->msg_flags != NULL) { return MailCoreStringArrayFromClist(myMessage->msg_flags->fl_extension); } return nil; } - (NSUInteger)sequenceNumber { return mySequenceNumber; } - (void)setSequenceNumber:(NSUInteger)sequenceNumber { mySequenceNumber = sequenceNumber; } - (NSSet *)from { if (myFields->fld_from == NULL) return nil; return [self _addressListFromMailboxList:myFields->fld_from->frm_mb_list]; } - (void)setFrom:(NSSet *)addresses { struct mailimf_mailbox_list *imf = [self _mailboxListFromAddressList:addresses]; if (myFields->fld_from != NULL) mailimf_from_free(myFields->fld_from); myFields->fld_from = mailimf_from_new(imf); } - (CTCoreAddress *)sender { if (myFields->fld_sender == NULL) return nil; return [self _addressFromMailbox:myFields->fld_sender->snd_mb]; } - (NSSet *)to { if (myFields->fld_to == NULL) return nil; else return [self _addressListFromIMFAddressList:myFields->fld_to->to_addr_list]; } - (void)setTo:(NSSet *)addresses { struct mailimf_address_list *imf = [self _IMFAddressListFromAddresssList:addresses]; if (!imf) { return; } if (myFields->fld_to != NULL) { mailimf_address_list_free(myFields->fld_to->to_addr_list); myFields->fld_to->to_addr_list = imf; } else myFields->fld_to = mailimf_to_new(imf); } - (NSArray *)inReplyTo { if (myFields->fld_in_reply_to == NULL) return nil; else return MailCoreStringArrayFromClist(myFields->fld_in_reply_to->mid_list); } - (void)setInReplyTo:(NSArray *)messageIds { struct mailimf_in_reply_to *imf = mailimf_in_reply_to_new(MailCoreClistFromStringArray(messageIds)); if (myFields->fld_in_reply_to != NULL) { mailimf_in_reply_to_free(myFields->fld_in_reply_to); myFields->fld_in_reply_to = imf; } else myFields->fld_in_reply_to = imf; } - (NSArray *)references { if (myFields->fld_references == NULL) return nil; else return MailCoreStringArrayFromClist(myFields->fld_references->mid_list); } - (void)setReferences:(NSArray *)messageIds { struct mailimf_references *imf = mailimf_references_new(MailCoreClistFromStringArray(messageIds)); if (myFields->fld_references != NULL) { mailimf_references_free(myFields->fld_references); myFields->fld_references = imf; } else myFields->fld_references = imf; } - (NSSet *)cc { if (myFields->fld_cc == NULL) return nil; else return [self _addressListFromIMFAddressList:myFields->fld_cc->cc_addr_list]; } - (void)setCc:(NSSet *)addresses { struct mailimf_address_list *imf = [self _IMFAddressListFromAddresssList:addresses]; if (!imf) { return; } if (myFields->fld_cc != NULL) { mailimf_address_list_free(myFields->fld_cc->cc_addr_list); myFields->fld_cc->cc_addr_list = imf; } else myFields->fld_cc = mailimf_cc_new(imf); } - (NSSet *)bcc { if (myFields->fld_bcc == NULL) return nil; else return [self _addressListFromIMFAddressList:myFields->fld_bcc->bcc_addr_list]; } - (void)setBcc:(NSSet *)addresses { struct mailimf_address_list *imf = [self _IMFAddressListFromAddresssList:addresses]; if (!imf) { return; } if (myFields->fld_bcc != NULL) { mailimf_address_list_free(myFields->fld_bcc->bcc_addr_list); myFields->fld_bcc->bcc_addr_list = imf; } else myFields->fld_bcc = mailimf_bcc_new(imf); } - (NSSet *)replyTo { if (myFields->fld_reply_to == NULL) return nil; else return [self _addressListFromIMFAddressList:myFields->fld_reply_to->rt_addr_list]; } - (void)setReplyTo:(NSSet *)addresses { struct mailimf_address_list *imf = [self _IMFAddressListFromAddresssList:addresses]; if (!imf) { return; } if (myFields->fld_reply_to != NULL) { mailimf_address_list_free(myFields->fld_reply_to->rt_addr_list); myFields->fld_reply_to->rt_addr_list = imf; } else myFields->fld_reply_to = mailimf_reply_to_new(imf); } - (NSString *)render { CTMIME *msgPart = myParsedMIME; if ([myParsedMIME isKindOfClass:[CTMIME_MessagePart class]]) { /* It's a message part, so let's set it's fields */ struct mailimf_fields *fields; struct mailimf_mailbox *sender = (myFields->fld_sender != NULL) ? (myFields->fld_sender->snd_mb) : NULL; struct mailimf_mailbox_list *from = (myFields->fld_from != NULL) ? (myFields->fld_from->frm_mb_list) : NULL; struct mailimf_address_list *replyTo = (myFields->fld_reply_to != NULL) ? (myFields->fld_reply_to->rt_addr_list) : NULL; struct mailimf_address_list *to = (myFields->fld_to != NULL) ? (myFields->fld_to->to_addr_list) : NULL; struct mailimf_address_list *cc = (myFields->fld_cc != NULL) ? (myFields->fld_cc->cc_addr_list) : NULL; struct mailimf_address_list *bcc = (myFields->fld_bcc != NULL) ? (myFields->fld_bcc->bcc_addr_list) : NULL; clist *inReplyTo = (myFields->fld_in_reply_to != NULL) ? (myFields->fld_in_reply_to->mid_list) : NULL; clist *references = (myFields->fld_references != NULL) ? (myFields->fld_references->mid_list) : NULL; char *subject = (myFields->fld_subject != NULL) ? (myFields->fld_subject->sbj_value) : NULL; fields = mailimf_fields_new_with_data(from, sender, replyTo, to, cc, bcc, inReplyTo, references, subject); if (self->mailPriority != 0) { char * xPriorityValue; char * rfcPriorityValue; switch (self->mailPriority) { case CTCoreMessageUrgentPriority: { xPriorityValue = "1"; rfcPriorityValue = "urgent"; break; } case CTCoreMessageNormalPriority: { xPriorityValue = "3"; rfcPriorityValue = "normal"; break; } case CTCoreMessageNonUrgentPriority: { xPriorityValue = "5"; rfcPriorityValue = "non-urgent"; break; } default: break; } struct mailimf_optional_field * priority = mailimf_optional_field_new("X-Priority", xPriorityValue); struct mailimf_field * priorityField = mailimf_field_new(MAILIMF_FIELD_OPTIONAL_FIELD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, priority); mailimf_fields_add(fields, priorityField); priority = mailimf_optional_field_new("Priority", rfcPriorityValue); priorityField = mailimf_field_new(MAILIMF_FIELD_OPTIONAL_FIELD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, priority); mailimf_fields_add(fields, priorityField); } //TODO uh oh, when this get freed it frees stuff in the CTCoreMessage //TODO Need to make sure that fields gets freed somewhere [(CTMIME_MessagePart *)msgPart setIMFFields:fields]; } return [myParsedMIME render]; } - (NSData *)messageAsEmlx { NSString *msgContent = [[self rfc822] stringByReplacingOccurrencesOfString:@"\r\n" withString:@"\n"]; NSData *msgContentAsData = [msgContent dataUsingEncoding:NSUTF8StringEncoding]; NSMutableData *emlx = [NSMutableData data]; [emlx appendData:[[NSString stringWithFormat:@"%-10d\n", (uint32_t)msgContentAsData.length] dataUsingEncoding:NSUTF8StringEncoding]]; [emlx appendData:msgContentAsData]; struct mail_flags *flagsStruct = myMessage ? myMessage->msg_flags : NULL; uint64_t flags = 0; if (flagsStruct != NULL) { BOOL seen = (flagsStruct->fl_flags & CTFlagSeen) > 0; flags |= seen << 0; BOOL answered = (flagsStruct->fl_flags & CTFlagAnswered) > 0; flags |= answered << 2; BOOL flagged = (flagsStruct->fl_flags & CTFlagFlagged) > 0; flags |= flagged << 4; BOOL forwarded = (flagsStruct->fl_flags & CTFlagForwarded) > 0; flags |= forwarded << 8; } NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; [dictionary setValue:[NSNumber numberWithDouble:[[self senderDate] timeIntervalSince1970]] forKey:@"date-sent"]; [dictionary setValue:[NSNumber numberWithUnsignedLongLong:flags] forKey:@"flags"]; [dictionary setValue:[self subject] forKey:@"subject"]; NSError *error; NSData *propertyList = [NSPropertyListSerialization dataWithPropertyList:dictionary format:NSPropertyListXMLFormat_v1_0 options:0 error:&error]; [emlx appendData:propertyList]; return emlx; } - (NSString *)rfc822 { char *result = NULL; NSString *nsresult; int r = mailimap_fetch_rfc822([self imapSession], [self sequenceNumber], &result); if (r == MAIL_NO_ERROR) { nsresult = [[NSString alloc] initWithCString:result encoding:NSUTF8StringEncoding]; } else { self.lastError = MailCoreCreateErrorFromIMAPCode(r); return nil; } mailimap_msg_att_rfc822_free(result); return [nsresult autorelease]; } - (NSString *)rfc822Header { char *result = NULL; NSString *nsresult; int r = mailimap_fetch_rfc822_header([self imapSession], [self sequenceNumber], &result); if (r == MAIL_NO_ERROR) { nsresult = [[NSString alloc] initWithCString:result encoding:NSUTF8StringEncoding]; } else { self.lastError = MailCoreCreateErrorFromIMAPCode(r); return nil; } mailimap_msg_att_rfc822_free(result); return [nsresult autorelease]; } - (void)setMailPriority:(CTCoreMessagePriority)priority { mailPriority = priority; } - (struct mailmessage *)messageStruct { return myMessage; } - (mailimap *)imapSession; { struct imap_cached_session_state_data * cached_data; struct imap_session_state_data * data; mailsession *session = [self messageStruct]->msg_session; if (strcasecmp(session->sess_driver->sess_name, "imap-cached") == 0) { cached_data = session->sess_data; session = cached_data->imap_ancestor; } data = session->sess_data; return data->imap_session; } - (CTCoreAddress *)_addressFromMailbox:(struct mailimf_mailbox *)mailbox; { CTCoreAddress *address = [CTCoreAddress address]; if (mailbox == NULL) { return address; } if (mailbox->mb_display_name != NULL) { NSString *decodedName = MailCoreDecodeMIMEPhrase(mailbox->mb_display_name); if (decodedName == nil) { decodedName = @""; } [address setName:decodedName]; } if (mailbox->mb_addr_spec != NULL) { [address setEmail:[NSString stringWithCString:mailbox->mb_addr_spec encoding:NSUTF8StringEncoding]]; } return address; } - (NSSet *)_addressListFromMailboxList:(struct mailimf_mailbox_list *)mailboxList; { clist *list; clistiter * iter; struct mailimf_mailbox *address; NSMutableSet *addressSet = [NSMutableSet set]; if (mailboxList == NULL) return addressSet; list = mailboxList->mb_list; for(iter = clist_begin(list); iter != NULL; iter = clist_next(iter)) { address = clist_content(iter); [addressSet addObject:[self _addressFromMailbox:address]]; } return addressSet; } - (struct mailimf_mailbox_list *)_mailboxListFromAddressList:(NSSet *)addresses { struct mailimf_mailbox_list *imfList = mailimf_mailbox_list_new_empty(); NSEnumerator *objEnum = [addresses objectEnumerator]; CTCoreAddress *address; int err; const char *addressName; const char *addressEmail; while((address = [objEnum nextObject])) { addressName = [[address name] cStringUsingEncoding:NSUTF8StringEncoding]; addressEmail = [[address email] cStringUsingEncoding:NSUTF8StringEncoding]; err = mailimf_mailbox_list_add_mb(imfList, strdup(addressName), strdup(addressEmail)); assert(err == 0); } return imfList; } - (NSSet *)_addressListFromIMFAddressList:(struct mailimf_address_list *)imfList { clist *list; clistiter * iter; struct mailimf_address *address; NSMutableSet *addressSet = [NSMutableSet set]; if (imfList == NULL) return addressSet; list = imfList->ad_list; for(iter = clist_begin(list); iter != NULL; iter = clist_next(iter)) { address = clist_content(iter); /* Check to see if it's a solo address a group */ if (address->ad_type == MAILIMF_ADDRESS_MAILBOX) { [addressSet addObject:[self _addressFromMailbox:address->ad_data.ad_mailbox]]; } else { if (address->ad_data.ad_group->grp_mb_list != NULL) [addressSet unionSet:[self _addressListFromMailboxList:address->ad_data.ad_group->grp_mb_list]]; } } return addressSet; } - (struct mailimf_address_list *)_IMFAddressListFromAddresssList:(NSSet *)addresses { if (!addresses) { return NULL; } struct mailimf_address_list *imfList = mailimf_address_list_new_empty(); NSEnumerator *objEnum = [addresses objectEnumerator]; CTCoreAddress *address; int err; const char *addressName; const char *addressEmail; while((address = [objEnum nextObject])) { addressName = [[address name] cStringUsingEncoding:NSUTF8StringEncoding]; addressEmail = [[address email] cStringUsingEncoding:NSUTF8StringEncoding]; err = mailimf_address_list_add_mb(imfList, strdup(addressName), strdup(addressEmail)); assert(err == 0); } return imfList; } @end