|
1 /* |
|
2 * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: Utility class for fetching email. |
|
15 * |
|
16 */ |
|
17 |
|
18 #include "qtemailfetcher.h" |
|
19 #include <csearchdocument.h> |
|
20 #include <cpixmaindefs.h> |
|
21 //#include <QThread> //If we happen to use QThread::yieldCurrentThread() |
|
22 |
|
23 //Symbian specific details; picked up from cemailplugin.cpp. |
|
24 //Refactor it to cpixmaindefs.h |
|
25 _LIT(KMsgBaseAppClassGeneric, "root msg email"); |
|
26 |
|
27 _LIT(KMsgSubject, "Subject"); |
|
28 _LIT(KMsgRecipients, "Recipients"); |
|
29 _LIT(KMsgBody, "Body"); |
|
30 _LIT(KMimeTypeField, CPIX_MIMETYPE_FIELD); |
|
31 _LIT(KMimeTypeMsg, "Messages"); |
|
32 |
|
33 //------------------------------------------------------------------------------ |
|
34 QEmailFetcher::QEmailFetcher( MEmailItemObserver& aObserver ) |
|
35 :iEmailObserver( aObserver ), |
|
36 iEmailEventNotifier( NULL ), |
|
37 iEmailService( NULL ), |
|
38 iMailBoxListings( NULL ), |
|
39 iMailFolderList( NULL ), |
|
40 iEnvelopeListing( NULL ) |
|
41 { |
|
42 } |
|
43 |
|
44 //------------------------------------------------------------------------------ |
|
45 QEmailFetcher::~QEmailFetcher() |
|
46 { |
|
47 delete iEmailEventNotifier; |
|
48 delete iEmailService; |
|
49 delete iMailBoxListings; |
|
50 delete iMailFolderList; |
|
51 } |
|
52 |
|
53 //------------------------------------------------------------------------------ |
|
54 QEmailFetcher* QEmailFetcher::newInstance( MEmailItemObserver& aObserver ){ |
|
55 QEmailFetcher* emailFetcher = NULL; |
|
56 |
|
57 //Leak free init. |
|
58 try{ |
|
59 QEmailFetcher* emailFetcher = new QEmailFetcher( aObserver ); |
|
60 //Uncomment 'this' once the actual APIs are ready. |
|
61 emailFetcher->iEmailService = new NmEmailService( emailFetcher ); |
|
62 emailFetcher->iEmailEventNotifier = new NmEventNotifier( emailFetcher ); |
|
63 emailFetcher->iMailBoxListings = new NmMailboxListing( emailFetcher ); |
|
64 }catch(...){ //cleanup. |
|
65 delete emailFetcher; |
|
66 delete emailFetcher->iEmailService; |
|
67 delete emailFetcher->iEmailEventNotifier; |
|
68 delete emailFetcher->iMailBoxListings; |
|
69 emailFetcher->iEmailService = NULL; |
|
70 emailFetcher->iEmailEventNotifier = NULL; |
|
71 emailFetcher->iMailBoxListings = NULL; |
|
72 throw; //rethrow the exception to caller. |
|
73 } |
|
74 initialize( emailFetcher ); //Do the rest of the init. |
|
75 return emailFetcher; //returns only if not null. |
|
76 } |
|
77 |
|
78 //------------------------------------------------------------------------------ |
|
79 void QEmailFetcher::initialize( QEmailFetcher* aThis ){ |
|
80 //The use of 'aThis' is because the current function is static. |
|
81 connect( aThis->iEmailService, SIGNAL(initialized(bool)), |
|
82 aThis, SLOT(emailServiceIntialized(bool)) ); |
|
83 aThis->iEmailService->initialise(); |
|
84 aThis->connect( aThis->iEmailEventNotifier, |
|
85 SIGNAL(messageEvent(MessageEvent, quint64, quint64, QList<quint64>)), |
|
86 aThis, |
|
87 SLOT(handleMessageEvent(MessageEvent, quint64, quint64, QList<quint64>)) ); |
|
88 } |
|
89 |
|
90 //------------------------------------------------------------------------------ |
|
91 void QEmailFetcher::emailServiceIntialized(bool aAllOk){ |
|
92 if( aAllOk ){ |
|
93 connect( iMailBoxListings, SIGNAL(mailboxesListed(int)), this, SLOT(handleMailboxesListed(int)) ); |
|
94 } |
|
95 } |
|
96 |
|
97 //------------------------------------------------------------------------------ |
|
98 void QEmailFetcher::StartHarvesting(){ |
|
99 iMailBoxListings->start(); |
|
100 } |
|
101 |
|
102 //------------------------------------------------------------------------------ |
|
103 namespace { |
|
104 |
|
105 // Taken from qt/src/corelib/kernel/qcore_symbian_p.cpp, as recomended in |
|
106 // http://qt.nokia.com/files/pdf/whitepaper-using-qt-and-symbian-c-together, page 34. |
|
107 // URL last accessed on April 6th, 2010. |
|
108 |
|
109 // Returned TPtrC is valid as long as the given parameter is valid and unmodified |
|
110 static inline TPtrC qt_QString2TPtrC( const QString& string ) |
|
111 { |
|
112 return TPtrC16(static_cast<const TUint16*>(string.utf16()), string.length()); |
|
113 } |
|
114 |
|
115 //------------------------------------------------------------------------------ |
|
116 // TODO Remove this code if qt_QString2TPtrC works. |
|
117 // TODO If this function is used, remember to release memory. |
|
118 // Ownership with caller. |
|
119 //HBufC* qt_QString2HBufC(const QString& aString) |
|
120 //{ |
|
121 // HBufC *buffer; |
|
122 //#ifdef QT_NO_UNICODE |
|
123 // TPtrC8 ptr(reinterpret_cast<const TUint8*>(aString.toLocal8Bit().constData())); |
|
124 //#else |
|
125 // TPtrC16 ptr(qt_QString2TPtrC(aString)); |
|
126 //#endif |
|
127 // buffer = q_check_ptr(HBufC::New(ptr.Length())); |
|
128 // buffer->Des().Copy(ptr); |
|
129 // return buffer; |
|
130 //} |
|
131 |
|
132 //------------------------------------------------------------------------------ |
|
133 //Private free function creates CSearchDocument from EMailMessageEnvelope. |
|
134 CSearchDocument* getSearchDocument( const NmMessageEnvelope& aEnvelope ){ |
|
135 QList<NmEmailAddress> toList; |
|
136 //Need to cast away const-ness since the get method is unfortunately not const. |
|
137 const_cast<NmMessageEnvelope&>(aEnvelope).getToRecipients( toList ); |
|
138 |
|
139 //We need ALL the recipients in a SINGLE field. |
|
140 QString recipients = ""; |
|
141 for( int i=0; i<toList.length(); i++ ) |
|
142 recipients += toList.at( i ).displayName() + " "; //or should we get address? |
|
143 |
|
144 NmMessageBody body; |
|
145 //Cast away const-ness since the get method is unfortunately not const. |
|
146 //Returns void. Cannot check for success/failure. |
|
147 const_cast<NmMessageEnvelope&>(aEnvelope).getPlainTextBody( body ); |
|
148 QString msgBody = body.content(); |
|
149 |
|
150 CSearchDocument* doc = 0; |
|
151 QT_TRAP_THROWING( |
|
152 //Use qt_Qstring2TPtrC since we are working with <b>const</b> EmailMessageEnvelope. |
|
153 doc = CSearchDocument::NewL( qt_QString2TPtrC( QString().setNum( aEnvelope.id() ) ), |
|
154 KMsgBaseAppClassGeneric ); |
|
155 doc->AddFieldL( KMimeTypeField, KMimeTypeMsg, CDocumentField::EStoreYes | CDocumentField::EIndexUnTokenized); |
|
156 doc->AddFieldL( KMsgSubject, qt_QString2TPtrC( aEnvelope.subject() ), CDocumentField::EStoreYes | CDocumentField::EIndexTokenized ); |
|
157 doc->AddFieldL( KMsgRecipients, qt_QString2TPtrC( recipients ), CDocumentField::EStoreYes | CDocumentField::EIndexTokenized ); |
|
158 doc->AddFieldL( KMsgBody, qt_QString2TPtrC( msgBody ), CDocumentField::EStoreYes | CDocumentField::EIndexTokenized ); |
|
159 //TODO: What should go in here? |
|
160 doc->AddExcerptL( KNullDesC ); |
|
161 ); |
|
162 return doc; |
|
163 } |
|
164 } //anonymous namespace |
|
165 |
|
166 //------------------------------------------------------------------------------ |
|
167 //Options to make async (like other plugins' Asynchronizer): |
|
168 //1. Use http://doc.trolltech.com/4.6/qtimer.html and connect timeout() signal to something? |
|
169 //Downside: |
|
170 //Have to save the state of the function and resume. Achievable via static members. |
|
171 //Remeber to reset counters. |
|
172 //2. Use timer; unlike above, have handleMailboxesListed() simply trigger a |
|
173 //Timer controlled function. |
|
174 //3. Use QThread::currentThread()->yieldCurrentThread(); |
|
175 //Downside: Not tested. |
|
176 //4. As recommended by the email API documentation, use SingleShotTimer: |
|
177 //QTimer::singleShot(nsecs,nmFolderListing,SLOT(start()); |
|
178 // |
|
179 //Recommendation: Use option 4. |
|
180 |
|
181 void QEmailFetcher::handleMailboxesListed(int aCount){ |
|
182 QList<NmMailbox> mailBoxes; |
|
183 if( aCount>0 && iMailBoxListings->getMailboxes( mailBoxes ) ){ |
|
184 for( int i=0; i<aCount; i++ ){ |
|
185 //Already set to NULL in constructor, so safe to call delete first time. |
|
186 delete iMailFolderList; iMailFolderList = NULL; |
|
187 iMailFolderList = new NmFolderListing( this, mailBoxes.at( i ).id() ); |
|
188 connect( iMailFolderList, SIGNAL(foldersListed()), this, SLOT(mailFoldersListed()) ); |
|
189 const int waitForSeconds = 30; //TODO Move this constant out of here if needed elsewhere |
|
190 QTimer::singleShot( waitForSeconds, iMailFolderList, SLOT( start()) ); |
|
191 } |
|
192 } |
|
193 } |
|
194 |
|
195 //------------------------------------------------------------------------------ |
|
196 void QEmailFetcher::mailFoldersListed(int aCount){ |
|
197 if( aCount == NmFolderListing::FolderListingFailed ) return; //silently. |
|
198 QList<NmFolder> folders; |
|
199 if ( aCount && iMailFolderList->getFolders( folders ) ) { |
|
200 for( int i=0; i<aCount; i++ ){ |
|
201 //Already set to NULL in constructor, so safe to call delete first time. |
|
202 delete iEnvelopeListing; iEnvelopeListing = NULL; |
|
203 iEnvelopeListing = new NmEnvelopeListing( this, folders.at( i ).id(), 0 ); |
|
204 connect(iEnvelopeListing, SIGNAL(envelopesListed(int)),this,SLOT(processMessages(int))); |
|
205 iEnvelopeListing->start(); |
|
206 } |
|
207 } |
|
208 } |
|
209 |
|
210 //------------------------------------------------------------------------------ |
|
211 void QEmailFetcher::processMessages(int aCount){ |
|
212 if( aCount == NmMailboxListing::MailboxListingFailed ) return; //silently. |
|
213 QList<NmMessageEnvelope> envelopes; |
|
214 if ( aCount > 0 && iEnvelopeListing->getEnvelopes(envelopes) ) { |
|
215 for( int i=0; i<envelopes.count(); i++ ) { |
|
216 const NmMessageEnvelope &envelope = envelopes.at( i ); |
|
217 //Create document and call back observer. |
|
218 QT_TRAP_THROWING( iEmailObserver.HandleDocumentL( getSearchDocument( envelope ), ECPixAddAction ) ); |
|
219 } |
|
220 } |
|
221 } |
|
222 |
|
223 //------------------------------------------------------------------------------ |
|
224 void QEmailFetcher::handleMessageEvent( const MessageEvent aEvent, quint64 aMailboxId, quint64 aFolderId, QList<quint64> aMessageList){ |
|
225 NmMessageEnvelope envelope; |
|
226 const int messageCount = aMessageList.count(); |
|
227 if( messageCount>0 ){ |
|
228 if( aEvent == MessageCreated || aEvent == MessageChanged ){ |
|
229 for( int i=0; i<messageCount; i++ ){ |
|
230 if( iEmailService->getEnvelope( aMailboxId, aFolderId, aMessageList.at( i ), envelope ) ){ |
|
231 QT_TRAP_THROWING( |
|
232 iEmailObserver.HandleDocumentL( getSearchDocument( envelope ), |
|
233 //Doing this simply avoids *duplicate* code for update action. |
|
234 aEvent == MessageCreated ? ECPixAddAction : ECPixUpdateAction ) ); |
|
235 } |
|
236 } |
|
237 } |
|
238 else if( aEvent == MessageDeleted ) { |
|
239 //TODO We can do better. For delete, we dont have to create full document. Just the ID should be enough. |
|
240 //We can have another function called getPartialSearchDocument so deletes will be faster. |
|
241 for( int i=0; i<messageCount; i++ ){ |
|
242 if( iEmailService->getEnvelope( aMailboxId, aFolderId, aMessageList.at( i ), envelope ) ){ |
|
243 QT_TRAP_THROWING( |
|
244 iEmailObserver.HandleDocumentL( getSearchDocument( envelope ), ECPixRemoveAction ) ); |
|
245 } |
|
246 } |
|
247 } |
|
248 } |
|
249 } |