00001 // 00002 // Copyright (c) 2009-2009 HIIT and Tero Hasu 00003 // Copyright (c) 2007-2009 Google Inc. 00004 // Copyright (c) 2006-2007 Jaiku Ltd. 00005 // Copyright (c) 2002-2006 Mika Raento and Renaud Petit 00006 // 00007 // This software is licensed at your choice under either 1 or 2 below. 00008 // 00009 // 1. MIT License 00010 // 00011 // Permission is hereby granted, free of charge, to any person obtaining a copy 00012 // of this software and associated documentation files (the "Software"), to deal 00013 // in the Software without restriction, including without limitation the rights 00014 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 00015 // copies of the Software, and to permit persons to whom the Software is 00016 // furnished to do so, subject to the following conditions: 00017 // 00018 // The above copyright notice and this permission notice shall be included in 00019 // all copies or substantial portions of the Software. 00020 // 00021 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00022 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00023 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00024 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00025 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00026 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 00027 // THE SOFTWARE. 00028 // 00029 // 2. Gnu General Public license 2.0 00030 // 00031 // This program is free software; you can redistribute it and/or 00032 // modify it under the terms of the GNU General Public License 00033 // as published by the Free Software Foundation; either version 2 00034 // of the License, or (at your option) any later version. 00035 // 00036 // This program is distributed in the hope that it will be useful, 00037 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00038 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00039 // GNU General Public License for more details. 00040 // 00041 // You should have received a copy of the GNU General Public License 00042 // along with this program; if not, write to the Free Software 00043 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00044 // 00045 00046 /* 00047 !concept {:name => "Observing SMS events", 00048 :desc => "Detecting and getting information about incoming and outgoing SMS messages."} 00049 */ 00050 00051 #include "ut_sms_epoc.hpp" 00052 00053 #include "er_errors.h" 00054 #include "jaiku_compat.hpp" 00055 #include "symbian_auto_ptr.hpp" 00056 #include "utils_cl2.h" 00057 00058 #include <mtclreg.h> // for CClientMtmRegistry 00059 #include <msvids.h> // for Message type IDs 00060 #include <smscmds.h> 00061 #include <smuthdr.h> 00062 #include <smutset.h> 00063 #include <msvuids.h> 00064 #include <txtrich.h> 00065 #include <smsclnt.h> 00066 #include <mtmdef.h> 00067 #include <gsmupdu.h> 00068 #include <mmsconst.h> 00069 #include <mmsclient.h> 00070 00071 #include <rsendas.h> 00072 #include <rsendasmessage.h> 00073 00074 // -------------------------------------------------- 00075 // 00076 // -------------------------------------------------- 00077 00078 void i_handle_received_sms::handle_reception(const TMsvId& entry_id, 00079 const TMsvId& folder_id, 00080 TUid aMtmUid, 00081 CBaseMtm* aMtm) 00082 { 00083 if (aMtmUid == KUidMsgTypeSMS) { 00084 CSmsClientMtm* smsMtm = STATIC_CAST(CSmsClientMtm*, aMtm); 00085 handle_reception(entry_id, folder_id, 00086 smsMtm->SmsHeader().FromAddress(), 00087 // Body returns a value of type CRichText&. The 00088 // value is empty for non-message contexts. The 0 00089 // argument to Read is the starting position, and 00090 // this only returns the first message fragment. 00091 smsMtm->Body()); 00092 } 00093 } 00094 00095 void i_handle_received_sms::handle_sending(const TMsvId& entry_id, 00096 TUid aMtmUid, CBaseMtm* aMtm) 00097 { 00098 if (aMtmUid == KUidMsgTypeSMS) { 00099 CSmsClientMtm* smsMtm = STATIC_CAST(CSmsClientMtm*, aMtm); 00100 handle_sending(entry_id, 00101 smsMtm->SmsHeader().FromAddress(), 00102 smsMtm->Body()); 00103 } 00104 } 00105 00106 // -------------------------------------------------- 00107 // 00108 // -------------------------------------------------- 00109 00110 // xxx The callback implementation needs fixing so that things will work if the callee does a "delete" on us. So there must be only one callback, and it must be the last thing that affects internal state in the handler. 00111 00112 CSmsEventNotifier* CSmsEventNotifier::NewL() 00113 { 00114 CSmsEventNotifier* obj = new (ELeave) CSmsEventNotifier(); 00115 CleanupStack::PushL(obj); 00116 obj->ConstructL(); 00117 CleanupStack::Pop(obj); 00118 return obj; 00119 } 00120 00121 CSmsEventNotifier::CSmsEventNotifier() 00122 { 00123 CALLSTACKITEM_N(_CL("CSmsEventNotifier"), _CL("CSmsEventNotifier")); 00124 00125 } 00126 00127 CSmsEventNotifier::~CSmsEventNotifier() 00128 { 00129 CALLSTACKITEM_N(_CL("CSmsEventNotifier"), _CL("~CSmsEventNotifier")); 00130 00131 delete iReceiveMtm; 00132 delete iMMSMtm; 00133 delete iReceiveMtmReg; 00134 delete iReceiveSession; 00135 } 00136 00137 void CSmsEventNotifier::ConstructL() 00138 { 00139 CALLSTACKITEM_N(_CL("CSmsEventNotifier"), _CL("ConstructL")); 00140 00141 #if 1 00142 iReceiveSession = CMsvSession::OpenAsObserverL(*this); 00143 #else 00144 iReceiveSession = CMsvSession::OpenSyncL(*this); 00145 #endif 00146 00147 iReceiveMtmReg = CClientMtmRegistry::NewL(*iReceiveSession); 00148 // iReceiveMtm = iReceiveMtmReg->NewMtmL(KUidMsgTypeSMS); 00149 // iMMSMtm = iReceiveMtmReg->NewMtmL(KUidMsgTypeMultimedia); 00150 } 00151 00152 void CSmsEventNotifier::SetHandler(i_handle_received_sms* handler) 00153 { 00154 CALLSTACKITEM_N(_CL("CSmsEventNotifier"), _CL("AddHandler")); 00155 00156 iHandler = handler; 00157 } 00158 00159 // See msvapi.h for the enum TMsvSessionEvent values. 00160 // 00161 // What will happen if we leave here? Do not know, but we won't. 00162 void CSmsEventNotifier::HandleSessionEventL(TMsvSessionEvent aEvent, 00163 TAny* aArg1, TAny* aArg2, TAny* aArg3) 00164 { 00165 CALLSTACKITEM_N(_CL("CSmsEventNotifier"), _CL("HandleSessionEventL")); 00166 //logg("TMsvSessionEvent %d", (int)aEvent); 00167 TRAPD(errCode, DoHandleSessionEventL(aEvent, aArg1, aArg2, aArg3)); 00168 if (errCode) 00169 HandleErrorL(errCode); 00170 } 00171 00172 void CSmsEventNotifier::DoHandleSessionEventL(TMsvSessionEvent aEvent, 00173 TAny* aArg1, TAny* aArg2, TAny* aArg3) 00174 { 00175 DELETE_Z(iMMSMtm); 00176 DELETE_Z(iReceiveMtm); 00177 00178 switch(aEvent) { 00179 case EMsvEntriesCreated: 00180 { 00181 if (!aArg1 || !aArg2 ) return; 00182 CMsvEntrySelection* entries=(CMsvEntrySelection *)aArg1; 00183 TMsvId id=*(TMsvId*)aArg2; 00184 if (id == KMsvGlobalInBoxIndexEntryId) { 00185 for (int i=0; i< entries->Count(); i++) { 00186 HandleReceivedL(entries->At(i), id); 00187 } 00188 } 00189 } 00190 break; 00191 00192 case EMsvEntriesMoved: // this event is given when message entries are moved 00193 { 00194 // An entry has been moved to another parent 00195 // We are interested messages that have been moved to Sent folder 00196 if (!aArg1 || !aArg2 || !aArg3 ) return; 00197 00198 TMsvId* toEntryId; 00199 TMsvId* fromEntryId; 00200 toEntryId = static_cast<TMsvId*>(aArg2); 00201 fromEntryId = static_cast<TMsvId*>(aArg3); 00202 00203 // We take the moved entries into a selection 00204 CMsvEntrySelection* entries = static_cast<CMsvEntrySelection*>(aArg1); 00205 00206 // the entry has been moved into Sent folder 00207 if ( *toEntryId == KMsvSentEntryId ) 00208 { 00209 // Process each created entry, one at a time. 00210 for(TInt i = 0; i < entries->Count(); i++) 00211 { 00212 HandleSentL(entries->At(i)); 00213 } 00214 } 00215 } 00216 break; 00217 00218 // Apparently all clients should respond to these events. 00219 case EMsvCloseSession: 00220 case EMsvServerTerminated: 00221 { 00222 if (iHandler) iHandler->handle_close(); 00223 } 00224 break; 00225 00226 default: 00227 break; 00228 } 00229 } 00230 00231 void CSmsEventNotifier::HandleErrorL(TInt aError) 00232 { 00233 CALLSTACKITEM_N(_CL("CSmsEventNotifier"), _CL("HandleErrorL")); 00234 00235 if (iHandler) iHandler->handle_error(aError); 00236 } 00237 00238 // May also return KNullUid to indicate failure. 00239 TUid CSmsEventNotifier::loadmessageL(const TMsvId& entry_id, TMsvEntry& entry) 00240 { 00241 CALLSTACKITEM_N(_CL("CSmsEventNotifier"), _CL("loadmessageL")); 00242 00243 TInt err; 00244 00245 e_auto_ptr<CMsvEntry> realentry(0); 00246 CC_TRAP(err, realentry.reset(iReceiveSession->GetEntryL(entry_id)) ); 00247 if (err != KErrNone) 00248 { 00249 return KNullUid; 00250 } 00251 entry=realentry->Entry(); 00252 00253 if (entry.iMtm != KUidMsgTypeSMS && entry.iMtm != KUidMsgTypeMultimedia) 00254 { 00255 // Not an SMS or MMS. 00256 return KNullUid; 00257 } 00258 00259 CBaseMtm* mtm=0; 00260 // SetCurrentEntryL takes ownership of the CMsvEntry 00261 TMsvPartList validationFlags(KMsvMessagePartDescription|KMsvMessagePartOriginator); 00262 if (entry.iMtm == KUidMsgTypeSMS) { 00263 if (iReceiveMtm==0) iReceiveMtm = iReceiveMtmReg->NewMtmL(KUidMsgTypeSMS); 00264 mtm = iReceiveMtm; 00265 validationFlags |= KMsvMessagePartBody; 00266 } else { 00267 if (iMMSMtm==0) iMMSMtm = iReceiveMtmReg->NewMtmL(KUidMsgTypeMultimedia); 00268 mtm = iMMSMtm; 00269 } 00270 CC_TRAP(err, mtm->SetCurrentEntryL(realentry.get())); 00271 realentry.release(); 00272 if (err!=KErrNone) 00273 { 00274 return KNullUid; 00275 } 00276 if (mtm->ValidateMessage(validationFlags != 0)) 00277 { 00278 // Not validated! 00279 return KNullUid; 00280 } 00281 00282 // The message loading sometimes fails with KErrAccessDenied - the 00283 // message server is busy. Just retry loading. 00284 TInt retry_count=0; 00285 const TInt MAX_RETRIES=5; 00286 while (retry_count<MAX_RETRIES) 00287 { 00288 CC_TRAP(err, mtm->LoadMessageL()); 00289 if (err==KErrAccessDenied || err==KErrInUse) { 00290 retry_count++; 00291 User::After(TTimeIntervalMicroSeconds32(100*1000)); //100 ms 00292 } else if (err==-1) { 00293 // can ignore 00294 return KNullUid; 00295 } else if (err != KErrNone) { 00296 return KNullUid; 00297 } else { 00298 break; 00299 } 00300 } 00301 if (retry_count==MAX_RETRIES) { 00302 return KNullUid; 00303 } 00304 return entry.iMtm; 00305 } 00306 00307 void CSmsEventNotifier::HandleReceivedL(const TMsvId& entry_id, 00308 const TMsvId& folder_id) 00309 { 00310 CALLSTACKITEM_N(_CL("CSmsEventNotifier"), _CL("HandleReceivedL")); 00311 00312 TMsvEntry entry; 00313 TUid mtmuid=loadmessageL(entry_id, entry); 00314 CBaseMtm* mtm = 0; 00315 if (mtmuid == KUidMsgTypeSMS ) { 00316 if (iReceiveMtm==0) iReceiveMtm = iReceiveMtmReg->NewMtmL(KUidMsgTypeSMS); 00317 mtm=iReceiveMtm; 00318 } else if ( mtmuid== KUidMsgTypeMultimedia ) { 00319 if (iMMSMtm==0) iMMSMtm = iReceiveMtmReg->NewMtmL(KUidMsgTypeMultimedia); 00320 mtm=iMMSMtm; 00321 } else { 00322 return; 00323 } 00324 00325 if (iHandler) iHandler->handle_reception(entry_id, folder_id, mtmuid, mtm); 00326 } 00327 00328 void CSmsEventNotifier::HandleSentL(const TMsvId& entry_id) 00329 { 00330 CALLSTACKITEM_N(_CL("CSmsEventNotifier"), _CL("HandleSentL")); 00331 00332 TMsvEntry entry; 00333 TUid mtmuid=loadmessageL(entry_id, entry); 00334 00335 CBaseMtm* mtm = 0; 00336 if (mtmuid == KUidMsgTypeSMS ) { 00337 if (iReceiveMtm==0) iReceiveMtm = iReceiveMtmReg->NewMtmL(KUidMsgTypeSMS); 00338 mtm=iReceiveMtm; 00339 } else if ( mtmuid== KUidMsgTypeMultimedia ) { 00340 if (iMMSMtm==0) iMMSMtm = iReceiveMtmReg->NewMtmL(KUidMsgTypeMultimedia); 00341 mtm=iMMSMtm; 00342 } else { 00343 logt("sent: not an sms or mms"); 00344 return; 00345 } 00346 00347 if (iHandler) iHandler->handle_sending(entry_id, mtmuid, mtm); 00348 }
ContextLogger2—ContextLogger2 Logger Daemon Internals—Generated on Mon May 2 13:49:57 2011 by Doxygen 1.6.1