|
1 /* |
|
2 * Copyright (c) 2002-2009 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: |
|
15 * binary encoding of a multimedia message |
|
16 * |
|
17 */ |
|
18 |
|
19 |
|
20 |
|
21 //#define CONTENT_DISPOSITION_TEST |
|
22 |
|
23 // INCLUDE FILES |
|
24 #include <e32std.h> |
|
25 #include <apparc.h> |
|
26 #include <s32mem.h> |
|
27 #include <msventry.h> |
|
28 #include <utf.h> |
|
29 #include <e32math.h> |
|
30 #include <msvids.h> |
|
31 #include <escapeutils.h> |
|
32 #include <badesca.h> |
|
33 #include <mmsvattachmentmanager.h> |
|
34 #include <mmsvattachmentmanagersync.h> |
|
35 #include <cmsvmimeheaders.h> |
|
36 #include <imcvcodc.h> |
|
37 |
|
38 #include <msgtextutils.h> |
|
39 #include <msvstore.h> |
|
40 #include <charconv.h> |
|
41 |
|
42 #include <centralrepository.h> // link against centralrepository.lib |
|
43 #include "MmsEnginePrivateCRKeys.h" |
|
44 |
|
45 #include "mmsheaders.h" |
|
46 #include "mmsconst.h" |
|
47 #include "mmscodec.h" |
|
48 #include "mmsencode.h" |
|
49 #include "mmsservercommon.h" |
|
50 #include "mmssession.h" |
|
51 #include "mmsgenutils.h" |
|
52 #include "mmserrors.h" |
|
53 #include "mmsentrywrapper.h" |
|
54 #include "mmsmmboxmessageheaders.h" |
|
55 #include "mmsmmboxviewheaders.h" |
|
56 #include "mmssendingchain.h" |
|
57 |
|
58 const TInt KMmsExtra = 1024; // extra memory left for others |
|
59 const TInt KMmsShortIntegerLimit127 = 127; // limit for short integer length |
|
60 const TInt KMmsOneByteLimit = 0x100; |
|
61 const TInt KMmsTwoByteLimit = 0x10000; |
|
62 const TInt KMmsThreeByteLimit = 0x1000000; |
|
63 const TInt KMms2 = 2; |
|
64 const TInt KMms3 = 3; |
|
65 const TInt KMms4 = 4; |
|
66 const TInt KMms5 = 5; |
|
67 const TInt KMms7 = 7; |
|
68 const TInt KMms8 = 8; |
|
69 const TInt KMms24 = 24; // shift of three half bytes |
|
70 const TInt KMms30 = 30; // upper limit for short length encoding |
|
71 const TUint8 KMms0x80 = 0x80; // 128 |
|
72 const TUint8 KMms0x7F = 0x7F; // 127 |
|
73 const TUint8 KMms0xFF = 0xFF; |
|
74 const TInt KMmsMaxCidLength = 18; |
|
75 // max filename length according to MMS conformance specs |
|
76 const TInt KMmsMaxFileNameLength = 40; |
|
77 // if 40 bytes are encoded in base 64, the result is 56 bytes |
|
78 // (two bytes of padding are needed to make the number divisible by 3) |
|
79 const TInt KMaxEncodingLength = 56; |
|
80 // Maximum length of output buffer needed for encoding the filename |
|
81 // Max 56 bytes for actual encoding and 12 bytes for character set (utf8) |
|
82 // and encoding scheme indicator 68 for final result, but we allocate |
|
83 // the maximum Mime header length to be sure everything fits. |
|
84 const TInt KMaxNameBufferLength = 75; |
|
85 const TInt KMmsEncodingExtraLength = 12; |
|
86 const TInt KMmsPreambleLength = 10; |
|
87 _LIT8( KMmsQuotedPreamble, "=?utf-8?Q?" ); |
|
88 _LIT8( KMmsBase64Preamble, "=?utf-8?B?" ); |
|
89 _LIT8( KMmsEncodingTrailer, "?=" ); |
|
90 const TInt KMmsIntUnderscore = 0x5F; // underscore |
|
91 |
|
92 |
|
93 enum TMmsMachineStates |
|
94 { |
|
95 EMmsIdle, |
|
96 EMmsEncodingHeaders, |
|
97 EMmsEncodingAttachments, |
|
98 EMmsFinished |
|
99 }; |
|
100 |
|
101 // These are the stages for chunked encoding. |
|
102 // The chunked encoding is synchronous, so the stages are different |
|
103 // from the machine states. |
|
104 enum TMmsChunkedEncodingStages |
|
105 { |
|
106 EMmsHeaders, |
|
107 EMmsAttachmentHeaders, |
|
108 EMmsAttachmentData |
|
109 }; |
|
110 |
|
111 // ==================== LOCAL FUNCTIONS ==================== |
|
112 |
|
113 // ================= MEMBER FUNCTIONS ======================= |
|
114 |
|
115 // --------------------------------------------------------------------------- |
|
116 // C++ default constructor can NOT contain any code, that |
|
117 // might leave. |
|
118 // |
|
119 // All member variables are automatically zeroed in the constructor |
|
120 // of a class derived from CBase. |
|
121 // Priority is set slightly above standard (1 instead of 0) to make sure |
|
122 // that message is sent as soon as possible (user input has priority 10). |
|
123 // Variables related to chunked encoding are initialized to indicate |
|
124 // one complete chunk only. |
|
125 // --------------------------------------------------------------------------- |
|
126 // |
|
127 CMmsEncode::CMmsEncode() |
|
128 :CMsgActive ( KMmsActiveObjectPriority ), |
|
129 iState ( EMmsIdle ), |
|
130 iOverallDataSize ( -1 ), |
|
131 iLastChunk ( ETrue ), |
|
132 iOnlyOneChunk( ETrue ) |
|
133 { |
|
134 } |
|
135 |
|
136 // --------------------------------------------------------------------------- |
|
137 // Symbian OS default constructor can leave. |
|
138 // --------------------------------------------------------------------------- |
|
139 // |
|
140 void CMmsEncode::ConstructL( RFs& aFs ) |
|
141 { |
|
142 iFs = aFs; |
|
143 CActiveScheduler::Add( this ); |
|
144 } |
|
145 |
|
146 // --------------------------------------------------------------------------- |
|
147 // Two-phased constructor. |
|
148 // --------------------------------------------------------------------------- |
|
149 // |
|
150 EXPORT_C CMmsEncode* CMmsEncode::NewL( RFs& aFs ) |
|
151 { |
|
152 CMmsEncode* self = new ( ELeave ) CMmsEncode; |
|
153 |
|
154 CleanupStack::PushL( self ); |
|
155 self->ConstructL( aFs ); |
|
156 CleanupStack::Pop( self ); |
|
157 |
|
158 return self; |
|
159 } |
|
160 |
|
161 |
|
162 // --------------------------------------------------------------------------- |
|
163 // Destructor |
|
164 // --------------------------------------------------------------------------- |
|
165 // |
|
166 CMmsEncode::~CMmsEncode() |
|
167 { |
|
168 |
|
169 Cancel(); |
|
170 |
|
171 if ( iFileOpen ) |
|
172 { |
|
173 iAttachFile.Close(); |
|
174 iFileOpen = EFalse; |
|
175 } |
|
176 |
|
177 // Do not delete pointers that were presents from the caller. |
|
178 // The caller still owns that data |
|
179 delete iMimeHeaders; // this is ours too. |
|
180 |
|
181 } |
|
182 |
|
183 // --------------------------------------------------------- |
|
184 // |
|
185 // --------------------------------------------------------- |
|
186 // |
|
187 EXPORT_C void CMmsEncode::StartL( |
|
188 MMmsEntryWrapper& aEntryWrapper, |
|
189 CMmsHeaders& aMmsHeaders, |
|
190 CBufFlat& aEncodeBuffer, |
|
191 TRequestStatus& aStatus ) |
|
192 { |
|
193 |
|
194 // This is the entry point for encoding all PDUs that contain both headers |
|
195 // and data. |
|
196 // For normal use the only PDUs in this category would be M-send.req and |
|
197 // M-MBox-Upload.req, but for testing purposes the following PDUs may |
|
198 // also be handled using this entry point: |
|
199 // M-retrieve.conf (for testing purposes) |
|
200 // M-Mbox-View.conf (for testing purposes) |
|
201 // M-Mbox-Descr (for testing purposes) |
|
202 |
|
203 // Old asynchronous encoding is retained. |
|
204 // Reset sets all chunk-related variables to indicate one chunk which is the last one |
|
205 Reset(); |
|
206 |
|
207 iEntryWrapper = &aEntryWrapper; |
|
208 iMmsHeaders = &aMmsHeaders; |
|
209 iEncodeBuffer = &aEncodeBuffer; |
|
210 |
|
211 if ( iMimeHeaders ) |
|
212 { |
|
213 iMimeHeaders->Reset(); |
|
214 } |
|
215 else |
|
216 { |
|
217 iMimeHeaders = CMsvMimeHeaders::NewL(); |
|
218 } |
|
219 |
|
220 // We need to know the message entry ID |
|
221 // The wrapper originally points to the message entry |
|
222 |
|
223 TMsvEntry indexEntry; |
|
224 iError = iEntryWrapper->GetIndexEntry( indexEntry ); |
|
225 iCurrentMessageId = indexEntry.Id(); |
|
226 |
|
227 CMsvStore* store = iEntryWrapper->ReadStoreL(); |
|
228 CleanupStack::PushL( store ); |
|
229 |
|
230 // Only new attachment structure is supported |
|
231 MMsvAttachmentManager& attachMan = store->AttachmentManagerL(); |
|
232 iNumberOfAttachments = attachMan.AttachmentCount(); |
|
233 |
|
234 CleanupStack::PopAndDestroy( store ); |
|
235 |
|
236 Queue( aStatus ); |
|
237 |
|
238 iStatus = KRequestPending; |
|
239 SetActive(); |
|
240 // Pretend that we called an asynchronous service |
|
241 // in order to get into the state machine loop |
|
242 TRequestStatus* status = &iStatus; |
|
243 User::RequestComplete( status, iError ); |
|
244 |
|
245 } |
|
246 |
|
247 // --------------------------------------------------------- |
|
248 // |
|
249 // --------------------------------------------------------- |
|
250 // |
|
251 EXPORT_C void CMmsEncode::EncodeHeadersL( |
|
252 CMmsHeaders& aMmsHeaders, |
|
253 CBufFlat& aEncodeBuffer ) |
|
254 { |
|
255 // This function is used to encode all PDUs that contain only headers, |
|
256 // not data. Some are responses sent to MMSC, some are requests that |
|
257 // contain headers only. |
|
258 // Nothing is read from storage, everything to be encoded is contained |
|
259 // in the headers. |
|
260 // No active object is invoked, this is a synchronous function |
|
261 |
|
262 // Old one-chunk encoding is retained for encoding headers only. |
|
263 // Reset sets all chunk-related variables to indicate one chunk which is the last one |
|
264 Reset(); // also sets iError to KErrNone |
|
265 |
|
266 iMmsHeaders = &aMmsHeaders; |
|
267 iEncodeBuffer = &aEncodeBuffer; |
|
268 |
|
269 // start from the beginning |
|
270 iPosition = 0; |
|
271 // we discard old contents of the buffer in case we must expand it |
|
272 iEncodeBuffer->Reset(); |
|
273 |
|
274 // We are a bit greedy here so that we don't need |
|
275 // to change the code if there is a minor change in the specs. |
|
276 iEncodeBuffer->ResizeL( iMmsHeaders->Size() + KMMSBufferExtra ); |
|
277 |
|
278 // encode message depending on type |
|
279 // these are all types that contain headers only, never data |
|
280 switch ( iMmsHeaders->MessageType() ) |
|
281 { |
|
282 case KMmsMessageTypeMNotifyRespInd: |
|
283 EncodeNotifyResponse(); |
|
284 break; |
|
285 case KMmsMessageTypeAcknowledgeInd: |
|
286 EncodeAcknowledgeIndication(); |
|
287 break; |
|
288 case KMmsMessageTypeMNotificationInd: |
|
289 EncodeMmsNotificationL(); |
|
290 break; |
|
291 case KMmsMessageTypeForwardReq: |
|
292 EncodeForwardRequestL(); |
|
293 break; |
|
294 case KMmsMessageTypeReadRecInd: |
|
295 EncodeReadReplyL(); |
|
296 break; |
|
297 case KMmsMessageTypeMboxStoreReq: |
|
298 EncodeMMBoxStoreRequestL(); |
|
299 break; |
|
300 case KMmsMessageTypeMboxViewReq: |
|
301 // This may contain keywords. Reserve some extra space |
|
302 EncodeMMBoxViewRequestL(); |
|
303 break; |
|
304 case KMmsMessageTypeMBoxDeleteReq: |
|
305 case KMmsMessageTypeDeleteReq: |
|
306 EncodeDeleteRequestL(); |
|
307 break; |
|
308 case KMmsMessageTypeCancelConf: |
|
309 EncodeCancelResponse(); |
|
310 break; |
|
311 case KMmsMessageTypeReadOrigInd: |
|
312 // This is for testing purposes. |
|
313 // identical to ReadRecInd except for PDU type |
|
314 // This would be the PDU sent to originator by MMSC |
|
315 EncodeReadReplyL(); |
|
316 break; |
|
317 case KMmsMessageTypeMSendConf: |
|
318 // for testing purposes |
|
319 EncodeSendConfirmationL(); |
|
320 break; |
|
321 case KMmsMessageTypeDeliveryInd: |
|
322 // for testing purposes |
|
323 EncodeDeliveryReportL(); |
|
324 break; |
|
325 case KMmsMessageTypeForwardConf: |
|
326 // for testing purposes |
|
327 EncodeForwardConfirmationL(); |
|
328 break; |
|
329 case KMmsMessageTypeMboxStoreConf: |
|
330 // for testing purposes |
|
331 EncodeMMBoxStoreConfirmationL(); |
|
332 break; |
|
333 case KMmsMessageTypeMBoxUploadConf: |
|
334 // for testing purposes |
|
335 EncodeMMBoxUploadConfirmationL(); |
|
336 break; |
|
337 case KMmsMessageTypeMBoxDeleteConf: |
|
338 case KMmsMessageTypeDeleteConf: |
|
339 // for testing purposes |
|
340 EncodeDeleteConfirmationL(); |
|
341 break; |
|
342 case KMmsMessageTypeCancelReq: |
|
343 // for testing purposes |
|
344 EncodeCancelRequest(); |
|
345 break; |
|
346 #ifdef __WINS__ |
|
347 case KMmsMessageTypeMSendReq: |
|
348 EncodeSendRequestHeadersL(); |
|
349 break; |
|
350 case KMmsMessageTypeMBoxUploadReq: |
|
351 // This type has attachments and headers |
|
352 // This function encodes headers only |
|
353 EncodeMMBoxUploadRequestL(); |
|
354 break; |
|
355 case KMmsMessageTypeMRetrieveConf: |
|
356 // for test purposes |
|
357 EncodeRetrieveConfirmationL(); |
|
358 break; |
|
359 case KMmsMessageTypeMboxViewConf: |
|
360 // for test purposes |
|
361 EncodeMMBoxViewConfirmationL(); |
|
362 break; |
|
363 case KMmsMessageTypeMBoxDescr: |
|
364 // for test purposes |
|
365 EncodeMMBoxDescriptionL(); |
|
366 break; |
|
367 #endif |
|
368 default: |
|
369 // Illegal message type. |
|
370 iEncodeBuffer->Reset(); |
|
371 iPosition = 0; |
|
372 break; |
|
373 } |
|
374 |
|
375 // Remove slack to keep garbage out from the end of the file |
|
376 iEncodeBuffer->ResizeL( iPosition ); |
|
377 // Dump the buffer contents into file if requested |
|
378 Dump(); |
|
379 |
|
380 iOverallDataSize = iEncodeBuffer->Size(); |
|
381 |
|
382 } |
|
383 |
|
384 // --------------------------------------------------------- |
|
385 // |
|
386 // --------------------------------------------------------- |
|
387 // |
|
388 EXPORT_C void CMmsEncode::StartChunkedL( |
|
389 MMmsEntryWrapper& aEntryWrapper, |
|
390 CMmsHeaders& aMmsHeaders, |
|
391 CBufFlat& aEncodeBuffer, |
|
392 TRequestStatus& aStatus ) |
|
393 { |
|
394 |
|
395 // This is the entry point for chunked encoding all PDUs that contain both headers |
|
396 // and data. |
|
397 |
|
398 // Reset sets all chunk-related variables to indicate one chunk which is the last one |
|
399 #ifndef _NO_MMSS_LOGGING_ |
|
400 TMmsLogger::Log( _L("CMmsEncode: Start chunked") ); |
|
401 #endif |
|
402 Reset(); // also sets iError to KErrNone |
|
403 iDataSupplierStage = EMmsHeaders; |
|
404 |
|
405 iEntryWrapper = &aEntryWrapper; |
|
406 iMmsHeaders = &aMmsHeaders; |
|
407 iEncodeBuffer = &aEncodeBuffer; |
|
408 |
|
409 if ( iMimeHeaders ) |
|
410 { |
|
411 iMimeHeaders->Reset(); |
|
412 } |
|
413 else |
|
414 { |
|
415 iMimeHeaders = CMsvMimeHeaders::NewL(); |
|
416 } |
|
417 |
|
418 // We need to know the message entry ID |
|
419 // The wrapper originally points to the message entry |
|
420 |
|
421 TMsvEntry indexEntry; |
|
422 iError = iEntryWrapper->GetIndexEntry( indexEntry ); |
|
423 iCurrentMessageId = indexEntry.Id(); |
|
424 |
|
425 // Encode headers to the buffer |
|
426 // The rest will follow when next data chunk is requested. |
|
427 EncodeHeadersChunkedL(); |
|
428 |
|
429 aStatus=KRequestPending; |
|
430 TRequestStatus* status = &aStatus; |
|
431 User::RequestComplete( status, iError ); |
|
432 } |
|
433 |
|
434 |
|
435 // --------------------------------------------------------- |
|
436 // From class MMmsCodecDataSupplier |
|
437 // |
|
438 // --------------------------------------------------------- |
|
439 // |
|
440 TInt CMmsEncode::GetNextDataPart( TPtrC8& aDataPart, TBool& aLastDataChunk ) |
|
441 { |
|
442 TInt error = KErrNone; |
|
443 if ( !iEncodeBuffer || iEncodeBuffer->Size() == 0 ) |
|
444 { |
|
445 // called out of context or no message data available |
|
446 error = KErrNotFound; |
|
447 } |
|
448 else |
|
449 { |
|
450 aDataPart.Set( iEncodeBuffer->BackPtr( iPosition ) ); |
|
451 } |
|
452 aLastDataChunk = iLastChunk; |
|
453 |
|
454 return error; |
|
455 } |
|
456 |
|
457 // --------------------------------------------------------- |
|
458 // From class MMmsCodecDataSupplier |
|
459 // |
|
460 // --------------------------------------------------------- |
|
461 // |
|
462 TInt CMmsEncode::ReleaseData() |
|
463 { |
|
464 if ( iOnlyOneChunk ) |
|
465 { |
|
466 // if we have only one chunk we always point to the beginning |
|
467 // the buffer gets cleared when all data has been handled |
|
468 return KErrNone; |
|
469 } |
|
470 |
|
471 iPosition = 0; |
|
472 |
|
473 // encode next data part into the buffer |
|
474 |
|
475 if ( iDataSupplierStage == EMmsAttachmentHeaders && iNumberOfAttachments == 0 ) |
|
476 { |
|
477 iLastChunk = ETrue; |
|
478 iDataSupplierStage = EMmsHeaders; |
|
479 } |
|
480 else if ( iDataSupplierStage == EMmsAttachmentHeaders ) |
|
481 { |
|
482 #ifndef _NO_MMSS_LOGGING_ |
|
483 TMmsLogger::Log( _L("- data supplier stage: Attachment headers") ); |
|
484 #endif |
|
485 iError = iEntryWrapper->SetCurrentEntry( iCurrentMessageId ); |
|
486 if ( iError != KErrNone ) |
|
487 { |
|
488 return iError; |
|
489 } |
|
490 |
|
491 iCurrentFileSize = 0; |
|
492 CMsvStore* store = NULL; |
|
493 TRAP( iError, |
|
494 { |
|
495 store = iEntryWrapper->ReadStoreL(); |
|
496 CleanupStack::PushL( store ); |
|
497 MMsvAttachmentManager& attachMan = store->AttachmentManagerL(); |
|
498 iCurrentFileSize = EncodeHeadersAndGetFileL( attachMan ); |
|
499 CleanupStack::PopAndDestroy( store ); |
|
500 }); |
|
501 if ( iError != KErrNone ) |
|
502 { |
|
503 return iError; |
|
504 } |
|
505 |
|
506 // Now we have the attachment headers in our buffer. |
|
507 // If there is room, put data there, too |
|
508 |
|
509 if ( iBufferSize - iPosition >= iCurrentFileSize ) |
|
510 { |
|
511 #ifndef _NO_MMSS_LOGGING_ |
|
512 TMmsLogger::Log( _L("- enough room left in buffer for attachment data") ); |
|
513 #endif |
|
514 EncodeAttachmentData( iAttachFile, iCurrentFileSize ); |
|
515 iPosition += iCurrentFileSize; |
|
516 iAttachFile.Close(); |
|
517 iFileOpen = EFalse; |
|
518 iCurrentAttachment++; |
|
519 if ( iCurrentAttachment >= iNumberOfAttachments ) |
|
520 { |
|
521 iLastChunk = ETrue; |
|
522 iDataSupplierStage = EMmsHeaders; |
|
523 } |
|
524 else |
|
525 { |
|
526 // one attachment finished - move to next one |
|
527 iDataSupplierStage = EMmsAttachmentHeaders; |
|
528 } |
|
529 } |
|
530 else |
|
531 { |
|
532 iDataSupplierStage = EMmsAttachmentData; |
|
533 } |
|
534 } |
|
535 else if ( iDataSupplierStage == EMmsAttachmentData ) |
|
536 { |
|
537 #ifndef _NO_MMSS_LOGGING_ |
|
538 TMmsLogger::Log( _L("- data supplier stage: Attachment data") ); |
|
539 #endif |
|
540 // Add as much attachment data as possible. |
|
541 // Attachment file is now open, check position |
|
542 TInt filePosition = 0; |
|
543 iError = iAttachFile.Seek( ESeekCurrent, filePosition ); |
|
544 if ( iError != KErrNone ) |
|
545 { |
|
546 return iError; |
|
547 } |
|
548 TInt dataLeft = iCurrentFileSize - filePosition; |
|
549 TInt roomLeft = iBufferSize - iPosition; |
|
550 if ( roomLeft >= dataLeft ) |
|
551 { |
|
552 EncodeAttachmentData( iAttachFile, dataLeft ); |
|
553 iPosition += dataLeft; |
|
554 iAttachFile.Close(); |
|
555 iFileOpen = EFalse; |
|
556 iCurrentAttachment++; |
|
557 if ( iCurrentAttachment >= iNumberOfAttachments ) |
|
558 { |
|
559 iLastChunk = ETrue; |
|
560 iDataSupplierStage = EMmsHeaders; |
|
561 } |
|
562 else |
|
563 { |
|
564 // one attachment finished - move to next one |
|
565 iDataSupplierStage = EMmsAttachmentHeaders; |
|
566 } |
|
567 } |
|
568 else |
|
569 { |
|
570 // we have more data than fits into buffer |
|
571 EncodeAttachmentData( iAttachFile, roomLeft ); |
|
572 iPosition += roomLeft; |
|
573 // We don't close the file because we still have data. |
|
574 // We stay in EMmsAttachmentHeaders state |
|
575 } |
|
576 } |
|
577 else |
|
578 { |
|
579 // do nothing, keep LINT happy |
|
580 } |
|
581 #ifndef _NO_MMSS_LOGGING_ |
|
582 if ( iDataSupplierStage == EMmsHeaders ) |
|
583 { |
|
584 TMmsLogger::Log( _L("- last chunk released") ); |
|
585 TMmsLogger::Log( _L("- data supplier stage: MMS headers") ); |
|
586 } |
|
587 #endif |
|
588 // If we have reached the end and have been asked to release data |
|
589 // we have nothing left to do. |
|
590 |
|
591 // dump what we got into file - if needed |
|
592 if ( iPosition > 0 ) |
|
593 { |
|
594 DumpAppend(); |
|
595 } |
|
596 return iError; |
|
597 } |
|
598 |
|
599 // --------------------------------------------------------- |
|
600 // From class MMmsCodecDataSupplier |
|
601 // |
|
602 // --------------------------------------------------------- |
|
603 // |
|
604 TInt CMmsEncode::OverallDataSize() |
|
605 { |
|
606 // If we have encoded all data, iOverallDataSize contains the |
|
607 // actual amount of data. |
|
608 // If we are doing chunked encoding, it contains -1. |
|
609 return iOverallDataSize; |
|
610 } |
|
611 |
|
612 |
|
613 // --------------------------------------------------------- |
|
614 // From class MMmsCodecDataSupplier |
|
615 // |
|
616 // --------------------------------------------------------- |
|
617 // |
|
618 TInt CMmsEncode::ResetSupplier() |
|
619 { |
|
620 #ifndef _NO_MMSS_LOGGING_ |
|
621 TMmsLogger::Log( _L("CMmsEncode: ResetSupplier") ); |
|
622 #endif |
|
623 if ( iOnlyOneChunk ) |
|
624 { |
|
625 // if we have only one chunk we always point to the beginning |
|
626 // the buffer gets cleared when all data has been handled |
|
627 return KErrNone; |
|
628 } |
|
629 |
|
630 // start data from the beginning |
|
631 iError = KErrNone; |
|
632 iDataSupplierStage = EMmsHeaders; |
|
633 TRAP( iError, EncodeHeadersChunkedL() ); |
|
634 |
|
635 return iError; |
|
636 } |
|
637 |
|
638 // --------------------------------------------------------- |
|
639 // From class CMsgActive |
|
640 // |
|
641 // --------------------------------------------------------- |
|
642 // |
|
643 void CMmsEncode::DoRunL() |
|
644 { |
|
645 |
|
646 // This routine takes the state machine through the states |
|
647 // until an error is encountered or the cycle completes. |
|
648 |
|
649 if ( iError != KErrNone ) |
|
650 { |
|
651 // We encountered an error, and cannot continue |
|
652 // For the time being we just give up without trying |
|
653 // to do any decent cleanup. |
|
654 iStatus = iError; |
|
655 // If we return from DoRunL without becoming active again, |
|
656 // RunL completes. |
|
657 return; |
|
658 } |
|
659 |
|
660 if ( iState != EMmsFinished ) |
|
661 { |
|
662 SelectNextState(); |
|
663 // If appropriate, ChangeStateL makes us active again |
|
664 ChangeStateL(); |
|
665 } |
|
666 else |
|
667 { |
|
668 // We are done, we must become idle again |
|
669 FinishL(); |
|
670 iStatus = iError; |
|
671 // If we return from DoRunL without becoming active again, |
|
672 // RunL completes. |
|
673 } |
|
674 // As we are using standard Mentact RunL, we must leave |
|
675 // if we have encountered an error, and do not want to continue |
|
676 |
|
677 if ( iError != KErrNone && !IsActive() ) |
|
678 { |
|
679 iPosition = 0; |
|
680 FinishL(); |
|
681 User::Leave( iError ); |
|
682 } |
|
683 } |
|
684 |
|
685 // --------------------------------------------------------- |
|
686 // From class CMsgActive |
|
687 // |
|
688 // --------------------------------------------------------- |
|
689 // |
|
690 void CMmsEncode::DoComplete( TInt& /* aStatus */ ) |
|
691 { |
|
692 // We are exiting the loop - we say we are idle now |
|
693 iState = EMmsIdle; |
|
694 } |
|
695 |
|
696 // --------------------------------------------------------- |
|
697 // |
|
698 // --------------------------------------------------------- |
|
699 // |
|
700 void CMmsEncode::SelectNextState() |
|
701 { |
|
702 |
|
703 // If appropriate, the functions called within the switch statement |
|
704 // will make us active again. If all is done, the asynchronous request |
|
705 // will complete |
|
706 |
|
707 switch ( iState ) |
|
708 { |
|
709 case EMmsIdle: |
|
710 // start the loop |
|
711 iState = EMmsEncodingHeaders; |
|
712 break; |
|
713 case EMmsEncodingHeaders: |
|
714 if ( iNumberOfAttachments > 0 ) |
|
715 { |
|
716 iState = EMmsEncodingAttachments; |
|
717 } |
|
718 else |
|
719 { |
|
720 iState = EMmsFinished; |
|
721 } |
|
722 break; |
|
723 case EMmsEncodingAttachments: |
|
724 // if there are more attachments, don't change state |
|
725 if ( iCurrentAttachment >= iNumberOfAttachments ) |
|
726 { |
|
727 iState = EMmsFinished; |
|
728 } |
|
729 break; |
|
730 case EMmsFinished: |
|
731 // No more states |
|
732 iState = EMmsIdle; |
|
733 break; |
|
734 default: |
|
735 // Illegal state |
|
736 break; |
|
737 } |
|
738 } |
|
739 |
|
740 // --------------------------------------------------------- |
|
741 // |
|
742 // --------------------------------------------------------- |
|
743 // |
|
744 void CMmsEncode::ChangeStateL() |
|
745 { |
|
746 switch ( iState ) |
|
747 { |
|
748 case EMmsEncodingHeaders: |
|
749 EncodeHeadersL(); |
|
750 break; |
|
751 case EMmsEncodingAttachments: |
|
752 EncodeAttachmentL(); |
|
753 iCurrentAttachment++; |
|
754 break; |
|
755 case EMmsFinished: |
|
756 FinishL(); |
|
757 break; |
|
758 default: |
|
759 // Should not be here anymore |
|
760 break; |
|
761 } |
|
762 } |
|
763 |
|
764 // --------------------------------------------------------- |
|
765 // |
|
766 // --------------------------------------------------------- |
|
767 // |
|
768 void CMmsEncode::Reset() |
|
769 { |
|
770 // close open file in case operation has ended with error |
|
771 // and the attachment file is still open |
|
772 if ( iFileOpen ) |
|
773 { |
|
774 iAttachFile.Close(); |
|
775 iFileOpen = EFalse; |
|
776 } |
|
777 |
|
778 iNumberOfAttachments = 0; |
|
779 iCurrentAttachment = 0; |
|
780 iError = KErrNone; |
|
781 iCurrentMessageId = KMsvNullIndexEntryId; |
|
782 iOverallDataSize = -1; |
|
783 iLastChunk = ETrue; |
|
784 iOnlyOneChunk = ETrue; |
|
785 } |
|
786 |
|
787 // --------------------------------------------------------- |
|
788 // |
|
789 // --------------------------------------------------------- |
|
790 // |
|
791 void CMmsEncode::EncodeHeadersL() |
|
792 { |
|
793 |
|
794 // start from the beginning |
|
795 iPosition = 0; |
|
796 // we discard old contents of the buffer in case we must expand it |
|
797 iEncodeBuffer->Reset(); |
|
798 |
|
799 // calculate space needed and resize buffer |
|
800 TInt size = 0; |
|
801 size += iMmsHeaders->Size(); |
|
802 |
|
803 User::LeaveIfError( iEntryWrapper->SetCurrentEntry( iCurrentMessageId ) ); |
|
804 CMsvStore* store = iEntryWrapper->ReadStoreL(); |
|
805 CleanupStack::PushL( store ); |
|
806 // AttachmentsSize function asks actual size from files |
|
807 // in case the info in CMsvAttachment is not up to date. |
|
808 // This function leaves if the attachment file is not found. |
|
809 // A message cannot be sent if it refers to attachment files that no |
|
810 // longer exist. |
|
811 size += iEntryWrapper->AttachmentsSizeL( *store ); |
|
812 CleanupStack::PopAndDestroy( store ); |
|
813 store = NULL; |
|
814 |
|
815 size += KMMSBufferExtra; // this is just an estimate of header size... |
|
816 // extra needed if lots of attachments. |
|
817 size += KMMSAttachmentExtra * iNumberOfAttachments; |
|
818 TMemoryInfoV1Buf memory; |
|
819 UserHal::MemoryInfo( memory ); |
|
820 TInt available = memory().iFreeRamInBytes; |
|
821 // check that buffer fits, leave a little memory for others too. |
|
822 if ( size > ( available - KMmsExtra ) ) |
|
823 { |
|
824 // message is too big - don't even try |
|
825 iError = KMmsErrorMessageTooBig; |
|
826 } |
|
827 |
|
828 if ( iError == KErrNone ) |
|
829 { |
|
830 iEncodeBuffer->ResizeL( size ); |
|
831 EncodeRequestHeadersL(); |
|
832 } |
|
833 |
|
834 iStatus = KRequestPending; |
|
835 SetActive(); |
|
836 |
|
837 // We complete ourselves. |
|
838 TRequestStatus* status = &iStatus; |
|
839 User::RequestComplete( status, iError ); |
|
840 |
|
841 } |
|
842 |
|
843 // --------------------------------------------------------- |
|
844 // |
|
845 // --------------------------------------------------------- |
|
846 // |
|
847 void CMmsEncode::EncodeHeadersChunkedL() |
|
848 { |
|
849 // The first step of chunked encoding |
|
850 #ifndef _NO_MMSS_LOGGING_ |
|
851 TMmsLogger::Log( _L("CMmsEncode::EncodeHeadersChunkedL:: start") ); |
|
852 #endif /* _NO_MMSS_LOGGING_ */ |
|
853 User::LeaveIfError( iEntryWrapper->SetCurrentEntry( iCurrentMessageId ) ); |
|
854 |
|
855 /* Korean req: 415-5434 |
|
856 * Get the target encoding MIB enum from cenrep and encode MMS text objects using corresponding conversion plugins |
|
857 */ |
|
858 TInt temp; |
|
859 iTargetEncodingType = 0; |
|
860 CRepository* repository = CRepository::NewLC( KUidMmsServerMtm ); |
|
861 if ( repository->Get( KMmsEncodingType, temp ) == KErrNone ) |
|
862 { |
|
863 iTargetEncodingType = temp; |
|
864 } |
|
865 CleanupStack::PopAndDestroy( repository ); |
|
866 #ifndef _NO_MMSS_LOGGING_ |
|
867 TMmsLogger::Log( _L("CMmsEncode::EncodeHeadersChunkedL:: target encoding type: %d"), iTargetEncodingType ); |
|
868 #endif /* _NO_MMSS_LOGGING_ */ |
|
869 |
|
870 if( iTargetEncodingType != 0 ) |
|
871 { |
|
872 TRAPD( err, PreProcessAttachmentDataL() ); |
|
873 |
|
874 #ifndef _NO_MMSS_LOGGING_ |
|
875 /* if any error, korean specific encoding failed, But this should not stop from sending MMS using |
|
876 * existing default encoding. Hence just log the error and continue in any case |
|
877 */ |
|
878 if( err != KErrNone ) |
|
879 { |
|
880 TMmsLogger::Log( _L("CMmsEncode::EncodeHeadersChunkedL:: PreProcessAttachmentDataL error: %d"), err ); |
|
881 } |
|
882 #endif /* _NO_MMSS_LOGGING_ */ |
|
883 } |
|
884 |
|
885 //Open store for read-only purpose |
|
886 CMsvStore* store = iEntryWrapper->ReadStoreL(); |
|
887 CleanupStack::PushL( store ); |
|
888 |
|
889 // Only new attachment structure is supported |
|
890 MMsvAttachmentManager& attachMan = store->AttachmentManagerL(); |
|
891 iNumberOfAttachments = attachMan.AttachmentCount(); |
|
892 |
|
893 TInt size = 0; |
|
894 size += iMmsHeaders->Size(); |
|
895 size += KMMSBufferExtra; // this is just an estimate of header size... |
|
896 // The buffer must be at least big enough to hold all headers |
|
897 iBufferSize = Max( KMmsChunkedBufferSize, size ); |
|
898 |
|
899 // extra needed if lots of attachments. |
|
900 // AttachmentsSize function asks actual size from files |
|
901 // in case the info in CMsvAttachment is not up to date. |
|
902 // This function leaves if the attachment file is not found. |
|
903 // A message cannot be sent if it refers to attachment files that no |
|
904 // longer exist. |
|
905 size += iEntryWrapper->AttachmentsSizeL( *store ); |
|
906 size += KMMSAttachmentExtra * iNumberOfAttachments; |
|
907 CleanupStack::PopAndDestroy( store ); |
|
908 store = NULL; |
|
909 |
|
910 if ( iBufferSize > size ) |
|
911 { |
|
912 // Our message is small enough to be sent in one chunk. |
|
913 // It does not make sense to send the message in small chunks |
|
914 // it the total is only a few kilobytes |
|
915 iBufferSize = size; |
|
916 iOnlyOneChunk = ETrue; |
|
917 iLastChunk = ETrue; |
|
918 } |
|
919 else |
|
920 { |
|
921 // we need several chunks |
|
922 iOnlyOneChunk = EFalse; |
|
923 iLastChunk = EFalse; |
|
924 } |
|
925 |
|
926 // start from the beginning |
|
927 iPosition = 0; |
|
928 iEncodeBuffer->Reset(); |
|
929 // This leaves if unable to resize. |
|
930 // We try to keep our buffer small enough so that this does not leave. |
|
931 iEncodeBuffer->ResizeL( iBufferSize ); |
|
932 #ifndef _NO_MMSS_LOGGING_ |
|
933 TMmsLogger::Log( _L("CMmsEncode::EncodeHeadersChunkedL:: MMS buff Size(Approx): %d"), iBufferSize ); |
|
934 #endif /* _NO_MMSS_LOGGING_ */ // The message is small enough to be sent as one chunk |
|
935 |
|
936 EncodeRequestHeadersL(); |
|
937 |
|
938 TInt i = 0; |
|
939 if ( iOnlyOneChunk ) |
|
940 { |
|
941 #ifndef _NO_MMSS_LOGGING_ |
|
942 TMmsLogger::Log( _L("CMmsEncode::EncodeHeadersChunkedL:: only one chunk") ); |
|
943 #endif /* _NO_MMSS_LOGGING_ */ // The message is small enough to be sent as one chunk |
|
944 for ( i = 0; ( i < iNumberOfAttachments ) && ( iError == KErrNone ); ++i ) |
|
945 { |
|
946 iCurrentAttachment = i; |
|
947 // encode attachments, too, as we have decided that our message |
|
948 // is small enough to fit into the buffer as one chunk |
|
949 // DoEncodeAttachment always encodes iCurrentAttachment |
|
950 // and updates buffer position as needed. |
|
951 DoEncodeAttachmentL(); |
|
952 // If something goes wrong, DoEncodeAttachmentL() sets iError, |
|
953 // and StartChunkedL will complete the caller with error. |
|
954 } |
|
955 iEncodeBuffer->ResizeL( iPosition ); |
|
956 iOverallDataSize = iEncodeBuffer->Size(); |
|
957 } |
|
958 else |
|
959 { |
|
960 #ifndef _NO_MMSS_LOGGING_ |
|
961 TMmsLogger::Log( _L("CMmsEncode::EncodeHeadersChunkedL:: Multiple chunks") ); |
|
962 #endif /* _NO_MMSS_LOGGING_ */ // The message is small enough to be sent as one chunk |
|
963 // chunked sending - but it should be possible to calculate data size |
|
964 iOverallDataSize = iPosition; // This is the amount taken by headers |
|
965 // The message is small enough to be sent as one chunk |
|
966 for ( i = 0; ( i < iNumberOfAttachments ) && ( iError == KErrNone ); ++i ) |
|
967 { |
|
968 iCurrentAttachment = i; |
|
969 // encode attachments, too, as we have decided that our message |
|
970 // is small enough to fit into the buffer as one chunk |
|
971 // DoEncodeAttachment always encodes iCurrentAttachment |
|
972 // and updates buffer position as needed. |
|
973 iOverallDataSize += DoGetAttachmentEncodingLengthL(); |
|
974 // If something goes wrong, DoEncodeAttachmentL() sets iError, |
|
975 // and StartChunkedL will complete the caller with error. |
|
976 } |
|
977 iCurrentAttachment = 0; |
|
978 iDataSupplierStage = EMmsAttachmentHeaders; |
|
979 if ( iError != KErrNone ) |
|
980 { |
|
981 iOverallDataSize = -1; |
|
982 } |
|
983 } |
|
984 |
|
985 // Dump headers. More data will follow |
|
986 Dump(); |
|
987 #ifndef _NO_MMSS_LOGGING_ |
|
988 TMmsLogger::Log( _L("CMmsEncode::EncodeHeadersChunkedL:: end") ); |
|
989 #endif /* _NO_MMSS_LOGGING_ */ // The message is small enough to be sent as one chunk |
|
990 } |
|
991 |
|
992 // --------------------------------------------------------- |
|
993 // |
|
994 // --------------------------------------------------------- |
|
995 // |
|
996 void CMmsEncode::EncodeAttachmentL() |
|
997 { |
|
998 |
|
999 DoEncodeAttachmentL(); |
|
1000 |
|
1001 if ( iError != KErrNone ) |
|
1002 { |
|
1003 // If we return without becoming active again, RunL completes |
|
1004 // we cannot send this message, because we cannot access attachments |
|
1005 return; |
|
1006 } |
|
1007 |
|
1008 iStatus = KRequestPending; |
|
1009 SetActive(); |
|
1010 |
|
1011 // Now we indicate we already did it. |
|
1012 TRequestStatus* status = &iStatus; |
|
1013 User::RequestComplete( status, iError ); |
|
1014 |
|
1015 } |
|
1016 |
|
1017 // --------------------------------------------------------- |
|
1018 // |
|
1019 // --------------------------------------------------------- |
|
1020 // |
|
1021 void CMmsEncode::DoEncodeAttachmentL() |
|
1022 { |
|
1023 |
|
1024 // Encode one part |
|
1025 // We must calculate length of headers and content type |
|
1026 |
|
1027 User::LeaveIfError( iEntryWrapper->SetCurrentEntry( iCurrentMessageId ) ); |
|
1028 |
|
1029 CMsvStore* store = iEntryWrapper->ReadStoreL(); |
|
1030 CleanupStack::PushL( store ); |
|
1031 MMsvAttachmentManager& attachMan = store->AttachmentManagerL(); |
|
1032 |
|
1033 TInt size = 0; |
|
1034 size = EncodeHeadersAndGetFileL( attachMan ); |
|
1035 if ( iError != KErrNone ) |
|
1036 { |
|
1037 CleanupStack::PopAndDestroy( store ); |
|
1038 return; |
|
1039 } |
|
1040 |
|
1041 // The data read function will not leave |
|
1042 EncodeAttachmentData( iAttachFile, size ); |
|
1043 iPosition += size; |
|
1044 iAttachFile.Close(); |
|
1045 |
|
1046 CleanupStack::PopAndDestroy( store ); |
|
1047 |
|
1048 } |
|
1049 |
|
1050 // --------------------------------------------------------- |
|
1051 // |
|
1052 // --------------------------------------------------------- |
|
1053 // |
|
1054 TInt CMmsEncode::DoGetAttachmentEncodingLengthL() |
|
1055 { |
|
1056 |
|
1057 // calculate length of headers and content type |
|
1058 |
|
1059 User::LeaveIfError( iEntryWrapper->SetCurrentEntry( iCurrentMessageId ) ); |
|
1060 |
|
1061 CMsvStore* store = iEntryWrapper->ReadStoreL(); |
|
1062 CleanupStack::PushL( store ); |
|
1063 MMsvAttachmentManager& attachMan = store->AttachmentManagerL(); |
|
1064 |
|
1065 TInt size = 0; |
|
1066 size = GetHeadersAndFileSizeL( attachMan ); |
|
1067 CleanupStack::PopAndDestroy( store ); |
|
1068 return size; |
|
1069 |
|
1070 } |
|
1071 |
|
1072 // --------------------------------------------------------- |
|
1073 // |
|
1074 // --------------------------------------------------------- |
|
1075 // |
|
1076 TInt CMmsEncode::EncodeHeadersAndGetFileL( MMsvAttachmentManager& aAttachMan ) |
|
1077 { |
|
1078 |
|
1079 CMsvAttachment* attachmentInfo = NULL; |
|
1080 attachmentInfo = aAttachMan.GetAttachmentInfoL( iCurrentAttachment ); |
|
1081 CleanupStack::PushL( attachmentInfo ); |
|
1082 |
|
1083 iMimeHeaders->RestoreL( *attachmentInfo ); |
|
1084 |
|
1085 // We don't trust the info, we ask the file itself |
|
1086 // Someone outside the messaging system may have changed the file |
|
1087 // without changing the attachment info |
|
1088 TInt size = 0; |
|
1089 if ( iFileOpen ) |
|
1090 { |
|
1091 // close file in case we have been reset while the file is still open |
|
1092 iAttachFile.Close(); |
|
1093 iFileOpen = EFalse; |
|
1094 } |
|
1095 iAttachFile = aAttachMan.GetAttachmentFileL( iCurrentAttachment ); |
|
1096 iError = iAttachFile.Size( size ); |
|
1097 iAttachFile.Close(); |
|
1098 |
|
1099 if ( iError != KErrNone ) |
|
1100 { |
|
1101 CleanupStack::PopAndDestroy( attachmentInfo ); |
|
1102 return size; |
|
1103 } |
|
1104 |
|
1105 // calculate the length of the headers |
|
1106 TBool foundName = EFalse; |
|
1107 TUint contentTypeSize = 0; |
|
1108 TInt8 contentType = -1; // indicate not found |
|
1109 TPtrC8 contentTypeString; |
|
1110 |
|
1111 TUint headerSize = 0; |
|
1112 |
|
1113 HBufC8* buf8 = CalculateAttachmentHeaderLengthL( |
|
1114 *attachmentInfo, |
|
1115 headerSize, |
|
1116 foundName, |
|
1117 contentTypeSize, |
|
1118 contentType, |
|
1119 contentTypeString ); |
|
1120 |
|
1121 CleanupStack::PushL( buf8 ); |
|
1122 |
|
1123 // We have calculated the header length, now we can encode: |
|
1124 |
|
1125 TPtrC8 nameString; |
|
1126 if ( !foundName && buf8 ) |
|
1127 { |
|
1128 nameString.Set( buf8->Des() ); |
|
1129 } |
|
1130 |
|
1131 EncodeAttachmentHeadersL( |
|
1132 size, |
|
1133 headerSize, |
|
1134 foundName, |
|
1135 contentTypeSize, |
|
1136 contentType, |
|
1137 contentTypeString, |
|
1138 nameString ); |
|
1139 |
|
1140 // now we have put the name all over, we can destroy the buffer |
|
1141 CleanupStack::PopAndDestroy( buf8 ); |
|
1142 buf8 = NULL; |
|
1143 CleanupStack::PopAndDestroy( attachmentInfo ); |
|
1144 attachmentInfo = NULL; |
|
1145 |
|
1146 // Now just write all the data octets |
|
1147 iAttachFile = aAttachMan.GetAttachmentFileL( iCurrentAttachment ); |
|
1148 iFileOpen = ETrue; |
|
1149 |
|
1150 return size; |
|
1151 } |
|
1152 |
|
1153 // --------------------------------------------------------- |
|
1154 // |
|
1155 // --------------------------------------------------------- |
|
1156 // |
|
1157 TInt CMmsEncode::GetHeadersAndFileSizeL( MMsvAttachmentManager& aAttachMan ) |
|
1158 { |
|
1159 |
|
1160 CMsvAttachment* attachmentInfo = NULL; |
|
1161 attachmentInfo = aAttachMan.GetAttachmentInfoL( iCurrentAttachment ); |
|
1162 CleanupStack::PushL( attachmentInfo ); |
|
1163 |
|
1164 iMimeHeaders->RestoreL( *attachmentInfo ); |
|
1165 |
|
1166 // We don't trust the info, we ask the file itself |
|
1167 // Someone outside the messaging system may have changed the file |
|
1168 // without changing the attachment info |
|
1169 TInt size = 0; |
|
1170 if ( iFileOpen ) |
|
1171 { |
|
1172 // close file in case we have been reset while the file is still open |
|
1173 iAttachFile.Close(); |
|
1174 iFileOpen = EFalse; |
|
1175 } |
|
1176 iAttachFile = aAttachMan.GetAttachmentFileL( iCurrentAttachment ); |
|
1177 iError = iAttachFile.Size( size ); |
|
1178 iAttachFile.Close(); |
|
1179 |
|
1180 if ( iError != KErrNone ) |
|
1181 { |
|
1182 CleanupStack::PopAndDestroy( attachmentInfo ); |
|
1183 return 0; |
|
1184 } |
|
1185 |
|
1186 // calculate the length of the headers |
|
1187 TBool foundName = EFalse; |
|
1188 TUint contentTypeSize = 0; |
|
1189 TInt8 contentType = -1; // indicate not found |
|
1190 TPtrC8 contentTypeString; |
|
1191 |
|
1192 TUint headerSize = 0; |
|
1193 |
|
1194 HBufC8* buf8 = CalculateAttachmentHeaderLengthL( |
|
1195 *attachmentInfo, |
|
1196 headerSize, |
|
1197 foundName, |
|
1198 contentTypeSize, |
|
1199 contentType, |
|
1200 contentTypeString ); |
|
1201 |
|
1202 delete buf8; // This is not needed |
|
1203 buf8 = NULL; |
|
1204 |
|
1205 CleanupStack::PopAndDestroy( attachmentInfo ); |
|
1206 attachmentInfo = NULL; |
|
1207 |
|
1208 // We have calculated the header length, now we still need the |
|
1209 // uintvar lengths: |
|
1210 |
|
1211 size += GetUintvarLength( size ); // encoding size for attachment length |
|
1212 size += headerSize; |
|
1213 size += GetUintvarLength( headerSize ); // encoding size for header length |
|
1214 |
|
1215 return size; |
|
1216 } |
|
1217 |
|
1218 // --------------------------------------------------------- |
|
1219 // |
|
1220 // --------------------------------------------------------- |
|
1221 // |
|
1222 HBufC8* CMmsEncode::CalculateAttachmentHeaderLengthL( |
|
1223 CMsvAttachment& aAttachmentInfo, |
|
1224 TUint& aHeaderLength, |
|
1225 TBool& aFoundName, |
|
1226 TUint& aContentTypeSize, |
|
1227 TInt8& aContentType, |
|
1228 TPtrC8& aContentTypeString ) |
|
1229 { |
|
1230 |
|
1231 TInt numNonSafe = 0; // number of characters in filename that would require encoding |
|
1232 // Not all content types have parameters. |
|
1233 // The only parameter we can handle to some extent |
|
1234 // is the character set parameter for text content types. |
|
1235 // The name parameter will always be added if not already present |
|
1236 |
|
1237 // Check if we have well-known media. |
|
1238 aContentType = -1; // indicate not found |
|
1239 aContentTypeString.Set( aAttachmentInfo.MimeType() ); |
|
1240 if ( aContentTypeString.Length() == 0 ) |
|
1241 { |
|
1242 // take type from mime headers |
|
1243 HBufC8* tempContentType = HBufC8::NewL( |
|
1244 iMimeHeaders->ContentType().Length() + |
|
1245 iMimeHeaders->ContentSubType().Length() + 1 ); |
|
1246 CleanupStack::PushL( tempContentType ); |
|
1247 tempContentType->Des().Copy( iMimeHeaders->ContentType() ); |
|
1248 if ( ( iMimeHeaders->ContentType().Find( KMmsSlash8 ) != |
|
1249 ( iMimeHeaders->ContentType().Length() - 1 ) ) && |
|
1250 ( iMimeHeaders->ContentSubType().Find( KMmsSlash8 ) != 0 ) && |
|
1251 ( iMimeHeaders->ContentSubType().Length() != 0 ) ) |
|
1252 { |
|
1253 tempContentType->Des().Append( KMmsSlash8 ); |
|
1254 } |
|
1255 tempContentType->Des().Append( iMimeHeaders->ContentSubType() ); |
|
1256 aAttachmentInfo.SetMimeTypeL( tempContentType->Des() ); |
|
1257 CleanupStack::PopAndDestroy( tempContentType ); |
|
1258 aContentTypeString.Set( aAttachmentInfo.MimeType() ); |
|
1259 } |
|
1260 |
|
1261 TInt8 i; |
|
1262 for ( i = 0; i < KNumberContentTypes && aContentType < 0; ++i ) |
|
1263 { |
|
1264 if ( aContentTypeString.CompareF( |
|
1265 TPtrC8( KContentTypeTable[i] ) ) == 0 ) |
|
1266 { |
|
1267 aContentType = i; |
|
1268 } |
|
1269 } |
|
1270 if ( aContentTypeString.Length() == 0 ) |
|
1271 { |
|
1272 aContentTypeString.Set( KMmsUnknownType ); |
|
1273 aContentType = -1; |
|
1274 } |
|
1275 |
|
1276 // we always add the name parameter to content type, so we always |
|
1277 // use the general form. If no name is given, we use the original filename |
|
1278 // If the name parameter is defined, we use it. |
|
1279 |
|
1280 aFoundName = EFalse; |
|
1281 iFileName.SetLength( 0 ); |
|
1282 |
|
1283 aHeaderLength = 0; |
|
1284 // add media type length |
|
1285 if ( aContentType >= 0 ) |
|
1286 { |
|
1287 // well-known media |
|
1288 aHeaderLength += 1; |
|
1289 } |
|
1290 else |
|
1291 { |
|
1292 // Extension media |
|
1293 aHeaderLength += aContentTypeString.Length(); |
|
1294 aHeaderLength += 1; // terminating zero |
|
1295 } |
|
1296 |
|
1297 // If we have parameters, we must calculate their length. |
|
1298 if ( iMimeHeaders->MimeCharset() != 0 ) |
|
1299 { |
|
1300 // charset has well-known encoding |
|
1301 aHeaderLength += 1; |
|
1302 if ( iMimeHeaders->MimeCharset() <= KMmsShortIntegerLimit127 ) |
|
1303 { |
|
1304 // short integer |
|
1305 aHeaderLength += 1; |
|
1306 } |
|
1307 else if ( iMimeHeaders->MimeCharset() < KMmsOneByteLimit ) |
|
1308 { |
|
1309 // long integer, short length + 1 byte of value |
|
1310 aHeaderLength += KMms2; |
|
1311 } |
|
1312 else if ( iMimeHeaders->MimeCharset() < KMmsTwoByteLimit ) |
|
1313 { |
|
1314 // long integer, short length + 2 bytes of value |
|
1315 // so far I don't know any IANA numbers that would |
|
1316 // take more than two hex bytes. |
|
1317 aHeaderLength += KMms3; |
|
1318 } |
|
1319 else if ( iMimeHeaders->MimeCharset() < KMmsThreeByteLimit ) |
|
1320 { |
|
1321 // long integer, short length + 3 bytes of value |
|
1322 aHeaderLength += KMms4; |
|
1323 } |
|
1324 else |
|
1325 { |
|
1326 // long integer, short length + 4 bytes of value |
|
1327 // cannot be longer than this in any case |
|
1328 aHeaderLength += KMms5; |
|
1329 } |
|
1330 } |
|
1331 // Then the rest of the parameters, unknown, |
|
1332 // sent as text strings |
|
1333 // If "name" attribute has been defined, we use it. |
|
1334 // if it is not added, we must add it. |
|
1335 // We must ensure that we don't add it twice... |
|
1336 |
|
1337 TInt mimeHeaderCount = iMimeHeaders->ContentTypeParams().MdcaCount(); |
|
1338 |
|
1339 for ( i = 0; i < mimeHeaderCount; i++ ) |
|
1340 { |
|
1341 // If we have corrupted parameters (length of name is zero) |
|
1342 // we skip the name/value pair. |
|
1343 // value may be zero, it will be encoded as just the terminating zero |
|
1344 if ( i%2 == 0 && |
|
1345 iMimeHeaders->ContentTypeParams().MdcaPoint( i ).Length() == 0 ) |
|
1346 { |
|
1347 i++; |
|
1348 } |
|
1349 else |
|
1350 { |
|
1351 // 8-byte string size + terminating zero |
|
1352 // If parameter has no value, it still must have |
|
1353 // the "no-value" indicator (just the terminating zero.) |
|
1354 if ( iMimeHeaders->ContentTypeParams().MdcaPoint( i ).CompareF( |
|
1355 KWspNameString ) == 0 && i%2 == 0 ) |
|
1356 { |
|
1357 if ( ( i + 1 ) < mimeHeaderCount && |
|
1358 IsStringSafe( iMimeHeaders->ContentTypeParams().MdcaPoint( i + 1 ), |
|
1359 numNonSafe ) ) |
|
1360 { |
|
1361 // We always move the name to the first item. |
|
1362 // It may be this parameter or something else |
|
1363 |
|
1364 // Content type parameters are 8-bit strings. |
|
1365 // We can use the name only if it is safe, otherwise it may contain some |
|
1366 // unknown encoding (maybe utf-8). |
|
1367 iFileName.Copy( ( iMimeHeaders->ContentTypeParams(). |
|
1368 MdcaPoint( i + 1 ) ).Right( KMmsMaxFileName ) ); |
|
1369 i++; |
|
1370 } |
|
1371 else |
|
1372 { |
|
1373 // Skip the next field as it can only be used if it is safe |
|
1374 i++; |
|
1375 } |
|
1376 } |
|
1377 else |
|
1378 { |
|
1379 aHeaderLength += iMimeHeaders->ContentTypeParams().MdcaPoint( i ).Length() + 1; |
|
1380 } |
|
1381 } |
|
1382 } |
|
1383 if ( ( iMimeHeaders->ContentTypeParams().MdcaCount() % 2 ) == 1 ) |
|
1384 { |
|
1385 // Odd number. Obviously last parameter has no value. |
|
1386 // Add the "no value" token |
|
1387 aHeaderLength++; |
|
1388 } |
|
1389 |
|
1390 // include name parameter to content-type |
|
1391 |
|
1392 // if the name was not among our mime headers, |
|
1393 // we must add it. |
|
1394 TInt nameLength = 0; |
|
1395 |
|
1396 // We prefer the suggested filename as the content type name parameter. |
|
1397 // If version is 1.3 or later, we can encode a non-safe filename. |
|
1398 // If suggested filename is not safe, but we already have a safe filename |
|
1399 // in iFilename, we don't override it if version is 1.2 or lower |
|
1400 if ( iMimeHeaders->SuggestedFilename().Length() > 0 ) |
|
1401 { |
|
1402 if ( iMmsHeaders->MmsVersion() > KMmsVersion12 || |
|
1403 IsStringSafe( iMimeHeaders->SuggestedFilename() ) || |
|
1404 iFileName.Length() == 0 ) |
|
1405 { |
|
1406 iFileName.Copy( iMimeHeaders->SuggestedFilename().Right( KMmsMaxFileName ) ); |
|
1407 } |
|
1408 } |
|
1409 |
|
1410 TParse* parse = NULL; |
|
1411 // If we don't have a filename suggestion so far, we just use the |
|
1412 // actual filename the attachment manager has used to save the file. |
|
1413 if ( iFileName.Length() == 0 ) |
|
1414 { |
|
1415 parse = new( ELeave )TParse; |
|
1416 CleanupStack::PushL( parse ); |
|
1417 // aAttachmentInfo.FilePath() is an actual Symbian filename including path |
|
1418 // so it never can be too long to fit into TParse or TFilename |
|
1419 parse->Set( aAttachmentInfo.FilePath(), NULL, NULL ); |
|
1420 iFileName.Copy( parse->NameAndExt() ); |
|
1421 CleanupStack::PopAndDestroy( parse ); |
|
1422 parse = NULL; |
|
1423 } |
|
1424 |
|
1425 // Last effort: |
|
1426 // If our version is 1.2 or lower and the filename suggestion so far |
|
1427 // is not safe, we try content-location. It is always safe |
|
1428 |
|
1429 if ( iMmsHeaders->MmsVersion() <= KMmsVersion12 && |
|
1430 !IsStringSafe( iFileName ) ) |
|
1431 { |
|
1432 if ( iMimeHeaders->ContentLocation().Length() > 0 ) |
|
1433 { |
|
1434 // content location should be safe. |
|
1435 // However, we must make sure it contains no URI escapes. |
|
1436 // for example space is legal in filename, but not in URI. |
|
1437 HBufC16* decoded = NULL; |
|
1438 TRAPD( error, ( decoded = EscapeUtils::EscapeDecodeL( |
|
1439 iMimeHeaders->ContentLocation() ) ) ); |
|
1440 if ( error == KErrNone ) |
|
1441 { |
|
1442 iFileName.Copy( decoded->Des().Right( KMmsMaxFileName ) ); |
|
1443 delete decoded; |
|
1444 decoded = NULL; |
|
1445 } |
|
1446 else |
|
1447 { |
|
1448 iFileName.Copy( iMimeHeaders->ContentLocation().Right( KMmsMaxFileName ) ); |
|
1449 } |
|
1450 } |
|
1451 } |
|
1452 |
|
1453 // remove leading and trailing spaces just in case... |
|
1454 iFileName.Trim(); |
|
1455 |
|
1456 // We should now make sure that the filename is not too long. |
|
1457 // According to MMS conformance specs, the maximum should be 40 characters |
|
1458 // It is unclear if the characters mean the total length or the length |
|
1459 // after conversion to utf-8, but as a first approximation we try |
|
1460 // to ensure that the total does not exceed 40 characters |
|
1461 |
|
1462 nameLength = iFileName.Length(); |
|
1463 |
|
1464 if ( nameLength > KMmsMaxFileNameLength ) |
|
1465 { |
|
1466 parse = new( ELeave )TParse; |
|
1467 CleanupStack::PushL( parse ); |
|
1468 parse->Set( aAttachmentInfo.FilePath(), NULL, NULL ); |
|
1469 iFileName.Copy( parse->Name().Left( KMmsMaxFileNameLength - parse->Ext().Length() ) ); |
|
1470 iFileName.Append( parse->Ext() ); |
|
1471 CleanupStack::PopAndDestroy( parse ); |
|
1472 parse = NULL; |
|
1473 nameLength = iFileName.Length(); |
|
1474 } |
|
1475 |
|
1476 // If encoding version is <=1.2, make filename safe, |
|
1477 // otherwise use MIME encoding (either base64 or quoted printable) |
|
1478 |
|
1479 HBufC8* buf8 = NULL; |
|
1480 |
|
1481 TPtrC16 originalName; |
|
1482 TBuf16<1> oneCharacter; |
|
1483 originalName.Set( iFileName ); |
|
1484 |
|
1485 TInt j; |
|
1486 |
|
1487 if ( IsStringSafe( iFileName ) ) |
|
1488 { |
|
1489 // filename only contains us-ascii characters - use as is |
|
1490 buf8 = HBufC8::NewL( nameLength ); |
|
1491 CleanupStack::PushL( buf8 ); |
|
1492 buf8->Des().Copy( iFileName ); |
|
1493 } |
|
1494 else |
|
1495 { |
|
1496 if ( iMmsHeaders->MmsVersion() <= KMmsVersion12 ) |
|
1497 { |
|
1498 // if version is <= 1.2, the filename must be us-ascii |
|
1499 // replace all illegal characters by underscore |
|
1500 buf8 = HBufC8::NewL( nameLength ); |
|
1501 CleanupStack::PushL( buf8 ); |
|
1502 for ( j = 0; j < nameLength; ++j ) |
|
1503 { |
|
1504 oneCharacter.Copy( originalName.Mid( j, 1 ) ); |
|
1505 if ( !IsStringSafe( oneCharacter ) ) |
|
1506 { |
|
1507 _LIT( KMmsUnderscore, "_" ); |
|
1508 oneCharacter.Copy( KMmsUnderscore ); |
|
1509 } |
|
1510 buf8->Des().Append( oneCharacter ); |
|
1511 } |
|
1512 } |
|
1513 else |
|
1514 { |
|
1515 // MMS encapsulation version is 1.3 or later |
|
1516 // Using non-ascii characters in filename parameter is allowed |
|
1517 // The filename must be encoded either using base64 or quoted printable |
|
1518 HBufC8* temp = NULL; |
|
1519 temp = CnvUtfConverter::ConvertFromUnicodeToUtf8L( originalName ); |
|
1520 CleanupStack::PushL( temp ); |
|
1521 // Now we have the filename in utf-8. |
|
1522 // We must check if it contains non-ascii, and if it does, |
|
1523 // we must use base64 or quoted-printable encoding. |
|
1524 TInt numNonSafe; |
|
1525 // Actually we know already that we are not safe. We just need |
|
1526 // to get the number of non-ascii characters |
|
1527 IsStringSafe( temp->Des(), numNonSafe ); |
|
1528 // We prefer quoted printable as it looks nicer in case we have mostly ascii, |
|
1529 // and it leaves extension in cleartext anyway |
|
1530 if ( ( temp->Des().Length() + ( KMms2 * numNonSafe ) ) <= KMaxEncodingLength ) |
|
1531 { |
|
1532 // use quoted printable, but first convert spaces to underscores |
|
1533 TInt spacePosition = temp->Des().Find( KSpace8 ); |
|
1534 while ( spacePosition != KErrNotFound ) |
|
1535 { |
|
1536 temp->Des()[ spacePosition ] = KMmsIntUnderscore; |
|
1537 spacePosition = temp->Des().Find( KSpace8 ); |
|
1538 } |
|
1539 buf8 = EncodeQuotedPrintableWordL( temp->Des() ); |
|
1540 } |
|
1541 else |
|
1542 { |
|
1543 // use base64 |
|
1544 // We have not restricted the filename length in utf-8 format, |
|
1545 // so it may be way longer than 40 bytes. |
|
1546 // However, we can calculate the length the buffer needs, so we |
|
1547 // can try. However, we may end up with some soft line break in |
|
1548 // the middle of the parameter which may not be acceptable. |
|
1549 buf8 = EncodeBase64WordL( temp->Des() ); |
|
1550 } |
|
1551 |
|
1552 CleanupStack::PopAndDestroy( temp ); |
|
1553 |
|
1554 CleanupStack::PushL( buf8 ); |
|
1555 // we must change nameLength here |
|
1556 } |
|
1557 } |
|
1558 |
|
1559 // The name is now in buf8, either just copied or encoded |
|
1560 nameLength = buf8->Des().Length(); |
|
1561 |
|
1562 if ( aFoundName == EFalse ) |
|
1563 { |
|
1564 // well-known encoding for the header itself |
|
1565 aHeaderLength++; |
|
1566 aHeaderLength += nameLength; |
|
1567 aHeaderLength += 1; // terminating zero |
|
1568 } |
|
1569 |
|
1570 aContentTypeSize = aHeaderLength; |
|
1571 |
|
1572 // As we have general form (at least name parameter), we need to indicate the length |
|
1573 if ( aContentTypeSize <= KMms30 ) |
|
1574 { |
|
1575 // short length |
|
1576 aHeaderLength += 1; |
|
1577 } |
|
1578 else |
|
1579 { |
|
1580 // length quote + at least one byte of uintvar |
|
1581 aHeaderLength += KMms2; |
|
1582 // Expecting over 128 bytes is paranoid. |
|
1583 if ( aContentTypeSize >= KMms0x7F ) |
|
1584 { |
|
1585 aHeaderLength++; |
|
1586 } |
|
1587 } |
|
1588 |
|
1589 // Now the rest of the mime headers: |
|
1590 |
|
1591 // Content-location |
|
1592 // just a short integer + a null terminated string |
|
1593 |
|
1594 if ( iMimeHeaders->ContentLocation().Length() > 0 ) |
|
1595 { |
|
1596 aHeaderLength += 1; // encoding of header as short integer |
|
1597 |
|
1598 // If we want to make sure we are safe, |
|
1599 // we must call IsStringSafe() function. |
|
1600 |
|
1601 // We just assume we are safe now. |
|
1602 aHeaderLength += iMimeHeaders->ContentLocation().Length(); |
|
1603 aHeaderLength += 1; // terminating zero |
|
1604 } |
|
1605 |
|
1606 // Content-ID |
|
1607 |
|
1608 if ( iMimeHeaders->ContentId().Length() > 0 ) |
|
1609 { |
|
1610 aHeaderLength += 1; // encoding of header as short integer |
|
1611 // add terminating zero and preceding quote. |
|
1612 // (needed according to WSP 1.3) |
|
1613 aHeaderLength += iMimeHeaders->ContentId().Length() + KMms2; |
|
1614 if ( iMimeHeaders->ContentId().Find( KMmsLeftAngle ) != 0 ) |
|
1615 { |
|
1616 aHeaderLength += KMms2; // we must add angle bracket |
|
1617 } |
|
1618 } |
|
1619 |
|
1620 // x-type parameters |
|
1621 // Must be stored as name/value pairs like content-type parameters |
|
1622 // X-parameter[i] = parameter name |
|
1623 // X-parameter[i+1] = parameter value |
|
1624 |
|
1625 for ( i = 0; i < iMimeHeaders->XTypeParams().MdcaCount(); ++i ) |
|
1626 { |
|
1627 // If we have corrupted parameters (length of name is zero) |
|
1628 // we skip the name/value pair. |
|
1629 // value may be zero, it will be encoded as just the terminating zero |
|
1630 if ( i%2 == 0 && |
|
1631 ( iMimeHeaders->XTypeParams().MdcaPoint( i ).Length() == 0 || |
|
1632 iMimeHeaders->XTypeParams().MdcaPoint( i ).CompareF( |
|
1633 KMmsSeparateDeliveryOmaXHeader ) == 0 ) ) |
|
1634 { |
|
1635 // We skip the header and its value if |
|
1636 // a) the header length is 0 |
|
1637 // b) the header is X-Oma-Drm-Separate-Delivery |
|
1638 i++; |
|
1639 } |
|
1640 else |
|
1641 { |
|
1642 aHeaderLength += iMimeHeaders->XTypeParams().MdcaPoint( i ).Length() + 1; |
|
1643 } |
|
1644 } |
|
1645 if ( ( iMimeHeaders->XTypeParams().MdcaCount() % 2 ) == 1 ) |
|
1646 { |
|
1647 // Odd number. Obviously last parameter has no value. |
|
1648 // Add the "no value" token |
|
1649 aHeaderLength++; |
|
1650 } |
|
1651 |
|
1652 // THESE ARE NOT IMPLEMENTED |
|
1653 |
|
1654 // Content-disposition & parameters |
|
1655 // Content-description |
|
1656 // Content-base |
|
1657 // Relative path |
|
1658 // version |
|
1659 |
|
1660 #ifdef CONTENT_DISPOSITION_TEST |
|
1661 // not supported |
|
1662 |
|
1663 // We generate a general header for content disposition |
|
1664 // for tests we use the actual filename. |
|
1665 // In real life the user's filename should not be |
|
1666 // sent out to the world |
|
1667 |
|
1668 // Fixed coding: |
|
1669 // Content Disposition, value length, attachment, filename, |
|
1670 // actual filename + terminating 0 |
|
1671 |
|
1672 // attachment, filename, terminating zero |
|
1673 // content disposition should be text-string, not quoted text string |
|
1674 TInt contentDispositionLength = KMms3 + nameLength; |
|
1675 |
|
1676 TInt valueLengthLength = 1; |
|
1677 if ( contentDispositionLength > KMms30 ) |
|
1678 { |
|
1679 // lengths 0 - 30 are encoded using "short length" |
|
1680 valueLengthLength++; |
|
1681 // |
|
1682 if ( contentDispositionLength > ShortIntegerLimit127 ) |
|
1683 { |
|
1684 valueLengthLength++; |
|
1685 } |
|
1686 // Should never be longer than this. |
|
1687 // I don't think anybody has a filename that is longer than 16383 bytes. |
|
1688 } |
|
1689 |
|
1690 aHeaderLength += valueLengthLength + contentDispositionLength + 1; |
|
1691 #endif |
|
1692 |
|
1693 CleanupStack::Pop( buf8 ); |
|
1694 return buf8; // caller will delete this afterwards |
|
1695 |
|
1696 } |
|
1697 |
|
1698 // --------------------------------------------------------- |
|
1699 // |
|
1700 // --------------------------------------------------------- |
|
1701 // |
|
1702 void CMmsEncode::EncodeAttachmentHeadersL( |
|
1703 TUint aSize, |
|
1704 TUint aHeaderSize, |
|
1705 TBool aFoundName, |
|
1706 TUint aContentTypeSize, |
|
1707 TInt8 aContentType, |
|
1708 TPtrC8& aContentTypeString, |
|
1709 TPtrC8& aNameString ) |
|
1710 { |
|
1711 |
|
1712 EncodeUintvar( aHeaderSize ); |
|
1713 |
|
1714 EncodeUintvar( aSize ); |
|
1715 |
|
1716 TUint8 temp = 0; // used to set the high bit for integers |
|
1717 |
|
1718 // if we have character set (or other parameters), |
|
1719 // we must use general encoding |
|
1720 |
|
1721 EncodeValueLength( aContentTypeSize ); |
|
1722 |
|
1723 if ( aContentType >= 0 ) |
|
1724 { |
|
1725 temp = aContentType | KMms0x80; |
|
1726 iEncodeBuffer->Write( iPosition, &temp, 1 ); |
|
1727 iPosition++; |
|
1728 } |
|
1729 else |
|
1730 { |
|
1731 // we assume this is a safe string |
|
1732 EncodeTextString( aContentTypeString ); |
|
1733 } |
|
1734 |
|
1735 // Then content type parameters. Mainly character set, |
|
1736 // but maybe something else, too |
|
1737 |
|
1738 temp = KWspCharset | KMms0x80; // encode as short integer |
|
1739 EncodeOptionalInteger( temp, iMimeHeaders->MimeCharset() ); |
|
1740 |
|
1741 // if we didn't find "Name" parameter among our parameters, we |
|
1742 // put it first. |
|
1743 |
|
1744 // we need the name later anyway... |
|
1745 |
|
1746 if ( !aFoundName ) |
|
1747 { |
|
1748 temp = KWspName | KMms0x80; // encode as short integer |
|
1749 EncodeHeaderAndTextString( temp, aNameString ); |
|
1750 } |
|
1751 |
|
1752 // Then the rest of content type parameters, just text strings. |
|
1753 |
|
1754 TInt i = 0; |
|
1755 |
|
1756 for ( i = 0; i < iMimeHeaders->ContentTypeParams().MdcaCount(); ++i ) |
|
1757 { |
|
1758 // If we have corrupted parameters (length of name is zero) |
|
1759 // we skip the name/value pair. |
|
1760 // value may be zero, it will be encoded as just the terminating zero |
|
1761 if ( i%2 == 0 && |
|
1762 iMimeHeaders->ContentTypeParams().MdcaPoint( i ).Length() == 0 ) |
|
1763 { |
|
1764 i++; |
|
1765 } |
|
1766 else |
|
1767 { |
|
1768 // 8-byte string + terminating zero |
|
1769 // If parameter has no value, it still must have |
|
1770 // the "no-value" indicator (just the terminating zero.) |
|
1771 // The ContentTypeParameters function provides |
|
1772 // an empty string in this case. |
|
1773 if ( iMimeHeaders->ContentTypeParams().MdcaPoint( i ).CompareF( |
|
1774 KWspNameString ) == 0 && i%2 == 0 ) |
|
1775 { |
|
1776 if ( aFoundName ) |
|
1777 { |
|
1778 temp = KWspName | KMms0x80; // encode as short integer |
|
1779 iEncodeBuffer->Write( iPosition, &temp, 1 ); |
|
1780 iPosition++; |
|
1781 } |
|
1782 else |
|
1783 { |
|
1784 // we can use name from mime headers only if it is "safe" |
|
1785 // (contains only us-ascii characters) |
|
1786 // If the name is not safe, the parameter value is skipped |
|
1787 i++; |
|
1788 } |
|
1789 } |
|
1790 else |
|
1791 { |
|
1792 EncodeTextString( |
|
1793 iMimeHeaders->ContentTypeParams().MdcaPoint( i ) ); |
|
1794 } |
|
1795 } |
|
1796 } |
|
1797 if ( ( iMimeHeaders->ContentTypeParams().MdcaCount() % 2 ) == 1 ) |
|
1798 { |
|
1799 // Odd number. Obviously last parameter has no value. |
|
1800 // Add the "no value" token |
|
1801 iEncodeBuffer->Write( iPosition, &KMmsNull, 1 ); |
|
1802 iPosition++; |
|
1803 } |
|
1804 |
|
1805 // content-location |
|
1806 temp = KWspContentLocation | KMms0x80; // encode as short integer |
|
1807 EncodeOptionalStringL( temp, iMimeHeaders->ContentLocation() ); |
|
1808 |
|
1809 // content-id |
|
1810 if ( iMimeHeaders->ContentId().Length() > 0 ) |
|
1811 { |
|
1812 HBufC8* tempContentId = HBufC8::NewL( iMimeHeaders->ContentId().Length() + KMms2 ); |
|
1813 CleanupStack::PushL( tempContentId ); |
|
1814 if ( iMimeHeaders->ContentId().Find( KMmsLeftAngle ) != 0 ) |
|
1815 { |
|
1816 tempContentId->Des().Copy( KMmsLeftAngle ); |
|
1817 tempContentId->Des().Append( iMimeHeaders->ContentId() ); |
|
1818 tempContentId->Des().Append( KMmsRightAngle ); |
|
1819 } |
|
1820 else |
|
1821 { |
|
1822 tempContentId->Des().Copy( iMimeHeaders->ContentId() ); |
|
1823 } |
|
1824 temp = KWspContentId | KMms0x80; // encode as short integer |
|
1825 iEncodeBuffer->Write( iPosition, &temp, 1 ); |
|
1826 iPosition++; |
|
1827 EncodeQuotedTextString( tempContentId->Des() ); |
|
1828 CleanupStack::PopAndDestroy( tempContentId ); |
|
1829 } |
|
1830 |
|
1831 #ifdef CONTENT_DISPOSITION_TEST |
|
1832 // not supported |
|
1833 temp = 0x2E | KMms0x80; // content disposition |
|
1834 iEncodeBuffer->Write( iPosition, &temp, 1 ); |
|
1835 iPosition++; |
|
1836 EncodeValueLength( contentDispositionLength ); |
|
1837 temp = 0x81; // attachment |
|
1838 iEncodeBuffer->Write( iPosition, &temp, 1 ); |
|
1839 iPosition++; |
|
1840 temp = 0x06 | KMms0x80; // filename |
|
1841 // filename should be text-string, not quoted |
|
1842 EncodeHeaderAndTextString( temp, buf8->Des() ); |
|
1843 #endif |
|
1844 |
|
1845 // x-type parameters |
|
1846 for ( i = 0; i < iMimeHeaders->XTypeParams().MdcaCount(); ++i ) |
|
1847 { |
|
1848 // If we have corrupted parameters (length of name is zero) |
|
1849 // we skip the name/value pair. |
|
1850 // value may be zero, it will be encoded as just the terminating zero |
|
1851 if ( i%2 == 0 && |
|
1852 ( iMimeHeaders->XTypeParams().MdcaPoint( i ).Length() == 0 || |
|
1853 iMimeHeaders->XTypeParams().MdcaPoint( i ).CompareF( |
|
1854 KMmsSeparateDeliveryOmaXHeader ) == 0 ) ) |
|
1855 { |
|
1856 // We skip the header and its value if |
|
1857 // a) the header length is 0 |
|
1858 // b) the header is X-Oma-Drm-Separate-Delivery |
|
1859 i++; |
|
1860 } |
|
1861 else |
|
1862 { |
|
1863 // 8-byte string + terminating zero |
|
1864 // If parameter has no value, it still must have |
|
1865 // the "no-value" indicator (just the terminating zero.) |
|
1866 // The ContentTypeParameters function provides |
|
1867 // an empty string in this case. |
|
1868 EncodeTextString( iMimeHeaders->XTypeParams().MdcaPoint( i ) ); |
|
1869 } |
|
1870 } |
|
1871 if ( ( iMimeHeaders->XTypeParams().MdcaCount() % 2 ) == 1 ) |
|
1872 { |
|
1873 // Odd number. Obviously last parameter has no value. |
|
1874 // Add the "no value" token |
|
1875 iEncodeBuffer->Write( iPosition, &KMmsNull, 1 ); |
|
1876 iPosition++; |
|
1877 } |
|
1878 |
|
1879 // End of MIME headers |
|
1880 |
|
1881 } |
|
1882 |
|
1883 // --------------------------------------------------------- |
|
1884 // |
|
1885 // --------------------------------------------------------- |
|
1886 // |
|
1887 void CMmsEncode::EncodeAttachmentData( RFile& aAttachFile, TInt aSize ) |
|
1888 { |
|
1889 // read the attachment file |
|
1890 // set up a pointer to point to iEncodeBuffer at iPosition |
|
1891 TPtr8 pos = iEncodeBuffer->Ptr( iPosition ); |
|
1892 // Attachemnt may be a file attacment or a linked file. |
|
1893 // The file pointer will point to unread part if file is read in chunks |
|
1894 iError = aAttachFile.Read( pos, aSize ); |
|
1895 } |
|
1896 |
|
1897 |
|
1898 // --------------------------------------------------------- |
|
1899 // |
|
1900 // --------------------------------------------------------- |
|
1901 // |
|
1902 void CMmsEncode::FinishL() |
|
1903 { |
|
1904 |
|
1905 // Remove slack to keep garbage out from the end of the file |
|
1906 iEncodeBuffer->ResizeL( iPosition ); |
|
1907 iOverallDataSize = iEncodeBuffer->Size(); |
|
1908 iState = EMmsIdle; |
|
1909 |
|
1910 // Dump the buffer contents into file if requested |
|
1911 Dump(); |
|
1912 |
|
1913 } |
|
1914 |
|
1915 // --------------------------------------------------------- |
|
1916 // |
|
1917 // --------------------------------------------------------- |
|
1918 // |
|
1919 void CMmsEncode::EncodeRequestHeadersL() |
|
1920 { |
|
1921 // encode message depending on type |
|
1922 switch ( iMmsHeaders->MessageType() ) |
|
1923 { |
|
1924 // KMmsMessageTypeMNotifyRespInd and KMmsMessageTypeAcknowledgeInd and all other PDUs |
|
1925 // that contain only headers and no data should be handled by |
|
1926 // using function |
|
1927 // EncodeHeadersL(CMmsHeaders& aMmsHeaders,CBufFlat& aEncodeBuffer) |
|
1928 case KMmsMessageTypeMSendReq: |
|
1929 EncodeSendRequestHeadersL(); |
|
1930 break; |
|
1931 case KMmsMessageTypeMBoxUploadReq: |
|
1932 // This type has attachments and headers |
|
1933 EncodeMMBoxUploadRequestL(); |
|
1934 break; |
|
1935 case KMmsMessageTypeMRetrieveConf: |
|
1936 // for test purposes |
|
1937 EncodeRetrieveConfirmationL(); |
|
1938 break; |
|
1939 case KMmsMessageTypeMboxViewConf: |
|
1940 // for test purposes |
|
1941 EncodeMMBoxViewConfirmationL(); |
|
1942 break; |
|
1943 case KMmsMessageTypeMBoxDescr: |
|
1944 // for test purposes |
|
1945 EncodeMMBoxDescriptionL(); |
|
1946 break; |
|
1947 default: |
|
1948 iError = KMmsErrorUnknownMessageType; |
|
1949 break; |
|
1950 } |
|
1951 } |
|
1952 |
|
1953 // --------------------------------------------------------- |
|
1954 // |
|
1955 // --------------------------------------------------------- |
|
1956 // |
|
1957 void CMmsEncode::EncodeSendRequestHeadersL() |
|
1958 { |
|
1959 |
|
1960 // Insert message type, TID and version number |
|
1961 EncodeStartingHeaders( KMmsMessageTypeMSendReq, |
|
1962 iMmsHeaders->Tid(), iMmsHeaders->MmsVersion() ); |
|
1963 |
|
1964 // if we have set a date, insert it |
|
1965 EncodeDate( iMmsHeaders->Date() ); |
|
1966 |
|
1967 // If we have set the sender, encode it |
|
1968 // If not, we ask MMSC to add the sender |
|
1969 EncodeSenderL( iMmsHeaders->Sender() ); |
|
1970 |
|
1971 // All recipient lists. If no recipients in some of the lists, |
|
1972 // nothing is encoded, no need to check separately |
|
1973 EncodeRecipientL( iMmsHeaders->ToRecipients(), EMmsTo ); |
|
1974 EncodeRecipientL( iMmsHeaders->CcRecipients(), EMmsCc ); |
|
1975 EncodeRecipientL( iMmsHeaders->BccRecipients(), EMmsBcc ); |
|
1976 |
|
1977 // Subject |
|
1978 EncodeOptionalStringL( KMmsAssignedSubject, iMmsHeaders->Subject() ); |
|
1979 |
|
1980 // Message class |
|
1981 EncodeOptionalByte( KMmsAssignedMessageClass, |
|
1982 iMmsHeaders->MessageClass() ); |
|
1983 |
|
1984 // Expiration time |
|
1985 EncodeOptionalIntervalOrDate( KMmsAssignedExpiry, |
|
1986 iMmsHeaders->ExpiryInterval(), |
|
1987 iMmsHeaders->ExpiryDate() ); |
|
1988 |
|
1989 // Delivery time |
|
1990 EncodeOptionalIntervalOrDate( KMmsAssignedDeliveryTime, |
|
1991 iMmsHeaders->DeliveryTimeInterval(), |
|
1992 iMmsHeaders->DeliveryDate() ); |
|
1993 |
|
1994 // Priority |
|
1995 EncodeOptionalByte( KMmsAssignedPriority, iMmsHeaders->MessagePriority() ); |
|
1996 |
|
1997 // Sender visibility |
|
1998 EncodeOptionalByte( KMmsAssignedSenderVisibility, |
|
1999 iMmsHeaders->SenderVisibility() ); |
|
2000 |
|
2001 // Delivery report |
|
2002 EncodeOptionalByte( KMmsAssignedDeliveryReport, |
|
2003 iMmsHeaders->DeliveryReport() ); |
|
2004 |
|
2005 // Read reply |
|
2006 EncodeOptionalByte( KMmsAssignedReadReply, iMmsHeaders->ReadReply() ); |
|
2007 |
|
2008 // MMS encapsulation 1.1 headers - optional |
|
2009 if ( iMmsHeaders->MmsVersion() > KMmsVersion1 ) |
|
2010 { |
|
2011 // Do we want to specify reply charging |
|
2012 if ( iMmsHeaders->ReplyCharging() == KMmsReplyChargingRequested || |
|
2013 iMmsHeaders->ReplyCharging() == KMmsReplyChargingRequestedTextOnly ) |
|
2014 { |
|
2015 // Reply charging value |
|
2016 EncodeOptionalByte( KMmsAssignedReplyCharging, |
|
2017 iMmsHeaders->ReplyCharging() ); |
|
2018 // Reply charging deadline |
|
2019 EncodeOptionalIntervalOrDate( KMmsAssignedReplyChargingDeadline, |
|
2020 iMmsHeaders->ReplyChargingInterval(), |
|
2021 iMmsHeaders->ReplyChargingDate() ); |
|
2022 // Reply charging size |
|
2023 EncodeReplyChargingSize( iMmsHeaders->ReplyChargingSize() ); |
|
2024 } |
|
2025 // Reply charging ID |
|
2026 EncodeOptionalString( KMmsAssignedReplyChargingID, |
|
2027 iMmsHeaders->ReplyChargingId() ); |
|
2028 } |
|
2029 |
|
2030 if ( iMmsHeaders->MmsVersion() > KMmsVersion11 ) |
|
2031 { |
|
2032 // MMBox related headers - optional |
|
2033 if ( iMmsHeaders->ReadOnlyMMBoxMessageHeaders() ) |
|
2034 { |
|
2035 // X-Mms-MM-Store |
|
2036 EncodeOptionalByte( KMmsAssignedMmsStore, |
|
2037 iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->MmsStore() ); |
|
2038 if ( iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->MmsStore() == KMmsYes ) |
|
2039 { |
|
2040 // X-Mms-MM-State |
|
2041 EncodeOptionalByte( KMmsAssignedMMState, |
|
2042 iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->MmsMMState() ); |
|
2043 // X-MMs-MM-Flags |
|
2044 // The keyword token should always be "add" or "remove" |
|
2045 EncodeKeywordArrayL(); |
|
2046 } |
|
2047 } |
|
2048 } |
|
2049 |
|
2050 // Add encapsulation version 1.3 headers - optional |
|
2051 if ( iMmsHeaders->MmsVersion() > KMmsVersion12 ) |
|
2052 { |
|
2053 // X-Mms-Applic-ID, X-Mms-Reply-Applic-ID and X-Mms-Aux-Applic-Info |
|
2054 EncodeApplicationHeadersL(); |
|
2055 // X-Mms-Content-Class |
|
2056 EncodeOptionalByte( KMmsAssignedContentClass, iMmsHeaders->ContentClass() ); |
|
2057 // X-Mms-DRM-Content |
|
2058 EncodeOptionalByte( KMmsAssignedDrmContent, iMmsHeaders->DrmContent() ); |
|
2059 // X-Mms-Adaptation-Allowed |
|
2060 EncodeOptionalByte( KMmsAssignedAdaptationAllowed, iMmsHeaders->AdaptationAllowed() ); |
|
2061 } |
|
2062 |
|
2063 // Get Root TMsvId from headers if set |
|
2064 TMsvAttachmentId rootId = iMmsHeaders->MessageRoot(); |
|
2065 |
|
2066 TInt error = KErrNone; |
|
2067 // If we are handling headers only, we may not have iEntryWrapper |
|
2068 if ( iEntryWrapper ) |
|
2069 { |
|
2070 CMsvStore* store = iEntryWrapper->ReadStoreL(); |
|
2071 CleanupStack::PushL( store ); |
|
2072 MMsvAttachmentManager& attachMan = store->AttachmentManagerL(); |
|
2073 TRAP( error, |
|
2074 { |
|
2075 CMsvAttachment* attachmentInfo = attachMan.GetAttachmentInfoL( |
|
2076 (TMsvAttachmentId) rootId ); |
|
2077 delete attachmentInfo; // we just wanted to check that it was found |
|
2078 } |
|
2079 ); |
|
2080 CleanupStack::PopAndDestroy( store ); |
|
2081 } |
|
2082 |
|
2083 // If we have a valid root part, we send the message as multipart/related. |
|
2084 // Otherwise we send it as multipart mixed. |
|
2085 // We don't try to guess what the root is supposed to be, if it |
|
2086 // is not specified or does not point to an existing attachment. |
|
2087 |
|
2088 if ( error == KErrNone && rootId != 0 && iEntryWrapper ) |
|
2089 { |
|
2090 EncodeMultipartRelatedHeaderL( rootId ); |
|
2091 } |
|
2092 else |
|
2093 { |
|
2094 EncodeMultipartMixedHeaderL(); |
|
2095 } |
|
2096 |
|
2097 } |
|
2098 |
|
2099 // --------------------------------------------------------- |
|
2100 // |
|
2101 // --------------------------------------------------------- |
|
2102 // |
|
2103 void CMmsEncode::EncodeNotifyResponse() |
|
2104 { |
|
2105 |
|
2106 // version may be current version or 1.0 |
|
2107 // Only byte is used. iMmsHeaders controls the value. |
|
2108 |
|
2109 // Insert message type, TID and version number |
|
2110 EncodeStartingHeaders( KMmsMessageTypeMNotifyRespInd, iMmsHeaders->Tid(), |
|
2111 iMmsHeaders->MmsVersion() ); |
|
2112 |
|
2113 // insert message status |
|
2114 EncodeMandatoryByte( KMmsAssignedStatus, iMmsHeaders->Status() ); |
|
2115 |
|
2116 // insert report allowed if present |
|
2117 EncodeOptionalByte( KMmsAssignedReportAllowed, |
|
2118 iMmsHeaders->ReportAllowed() ); |
|
2119 |
|
2120 } |
|
2121 |
|
2122 // --------------------------------------------------------- |
|
2123 // |
|
2124 // --------------------------------------------------------- |
|
2125 // |
|
2126 void CMmsEncode::EncodeAcknowledgeIndication() |
|
2127 { |
|
2128 // Insert message type, TID and version number |
|
2129 EncodeStartingHeaders( KMmsMessageTypeAcknowledgeInd, |
|
2130 iMmsHeaders->Tid(), iMmsHeaders->MmsVersion() ); |
|
2131 |
|
2132 // insert report allowed if present |
|
2133 EncodeOptionalByte( KMmsAssignedReportAllowed, |
|
2134 iMmsHeaders->ReportAllowed() ); |
|
2135 } |
|
2136 |
|
2137 // --------------------------------------------------------- |
|
2138 // |
|
2139 // --------------------------------------------------------- |
|
2140 // |
|
2141 void CMmsEncode::EncodeMmsNotificationL() |
|
2142 { |
|
2143 |
|
2144 // Insert message type, TID and version number |
|
2145 EncodeStartingHeaders( KMmsMessageTypeMNotificationInd, |
|
2146 iMmsHeaders->Tid(), iMmsHeaders->MmsVersion() ); |
|
2147 |
|
2148 // for notification sender is optional - added only if it is known |
|
2149 if ( iMmsHeaders->Sender().Length() > 0 ) |
|
2150 { |
|
2151 EncodeSenderL( iMmsHeaders->Sender() ); |
|
2152 } |
|
2153 |
|
2154 EncodeOptionalStringL( KMmsAssignedSubject, iMmsHeaders->Subject() ); |
|
2155 |
|
2156 EncodeOptionalByte( KMmsAssignedDeliveryReport, |
|
2157 iMmsHeaders->DeliveryReport() ); |
|
2158 |
|
2159 EncodeOptionalByte( KMmsAssignedMessageClass, |
|
2160 iMmsHeaders->MessageClass() ); |
|
2161 |
|
2162 iEncodeBuffer->Write( iPosition, &KMmsAssignedMessageSize, 1 ); |
|
2163 iPosition++; |
|
2164 |
|
2165 TInt64 size = iMmsHeaders->MessageSize(); |
|
2166 EncodeLongInteger( size ); |
|
2167 |
|
2168 EncodeOptionalIntervalOrDate( KMmsAssignedExpiry, |
|
2169 iMmsHeaders->ExpiryInterval(), |
|
2170 iMmsHeaders->ExpiryDate() ); |
|
2171 |
|
2172 // version 1.1 fields - optional |
|
2173 // reply-charging |
|
2174 // reply-charging deadline |
|
2175 // reply-charging size |
|
2176 // reply-charging ID |
|
2177 if ( iMmsHeaders->MmsVersion() > KMmsVersion1 ) |
|
2178 { |
|
2179 // Do we want to specify |
|
2180 if ( iMmsHeaders->ReplyCharging() == KMmsReplyChargingAccepted || |
|
2181 iMmsHeaders->ReplyCharging() == KMmsReplyChargingAcceptedTextOnly ) |
|
2182 { |
|
2183 // Reply charging value |
|
2184 EncodeOptionalByte( KMmsAssignedReplyCharging, |
|
2185 iMmsHeaders->ReplyCharging() ); |
|
2186 // Reply charging deadline |
|
2187 EncodeOptionalIntervalOrDate( KMmsAssignedReplyChargingDeadline, |
|
2188 iMmsHeaders->ReplyChargingInterval(), |
|
2189 iMmsHeaders->ReplyChargingDate() ); |
|
2190 // Reply charging size |
|
2191 EncodeReplyChargingSize( iMmsHeaders->ReplyChargingSize() ); |
|
2192 } |
|
2193 // if this is a reply, we may specify the ID |
|
2194 // Reply charging ID |
|
2195 EncodeOptionalString( KMmsAssignedReplyChargingID, |
|
2196 iMmsHeaders->ReplyChargingId() ); |
|
2197 } |
|
2198 |
|
2199 // version 1.2 headers - optional |
|
2200 if ( iMmsHeaders->MmsVersion() > KMmsVersion11 ) |
|
2201 { |
|
2202 // MMBox headers |
|
2203 if ( iMmsHeaders->ReadOnlyMMBoxMessageHeaders() ) |
|
2204 { |
|
2205 EncodeOptionalByte( KMmsAssignedStored, |
|
2206 iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->MmsStored() ); |
|
2207 } |
|
2208 |
|
2209 // Distribution indicator |
|
2210 EncodeOptionalByte( KMmsAssignedDistributionIndicator, |
|
2211 iMmsHeaders->DistributionIndicator() ); |
|
2212 } |
|
2213 |
|
2214 // Element descriptor |
|
2215 // This is somewhat a mystery - not implemented |
|
2216 |
|
2217 // version 1.3 headers - optional |
|
2218 if ( iMmsHeaders->MmsVersion() > KMmsVersion12 ) |
|
2219 { |
|
2220 // X-Mms-Applic-ID, X-Mms-Reply-Applic-ID and X-Mms-Aux-Applic-Info |
|
2221 EncodeApplicationHeadersL(); |
|
2222 // X-Mms-Recommended-Retrieval-Mode |
|
2223 EncodeOptionalByte( KMmsAssignedRecommendedRetrievalMode, |
|
2224 iMmsHeaders->RecommendedRetrievalMode() ); |
|
2225 // X-Mms-Recommended-Retrieval-Mode-Text |
|
2226 EncodeOptionalStringL( KMmsAssignedRecommendedRetrievalModeText, |
|
2227 iMmsHeaders->RecommendedRetrievalModeText() ); |
|
2228 // X-Mms-Content-Class |
|
2229 EncodeOptionalByte( KMmsAssignedContentClass, iMmsHeaders->ContentClass() ); |
|
2230 // X-Mms-DRM-Content |
|
2231 EncodeOptionalByte( KMmsAssignedDrmContent, iMmsHeaders->DrmContent() ); |
|
2232 // X-Mms-Replace-ID |
|
2233 EncodeOptionalString( KMmsAssignedReplaceId, iMmsHeaders->ReplaceCancelId() ); |
|
2234 } |
|
2235 |
|
2236 // We keep this as the last one, though it does not really matter |
|
2237 // Mandatory content-location |
|
2238 // this must be USASCII or URL encoded |
|
2239 EncodeHeaderAndTextString( KMmsAssignedContentLocation, |
|
2240 iMmsHeaders->ContentLocation() ); |
|
2241 |
|
2242 } |
|
2243 |
|
2244 // --------------------------------------------------------- |
|
2245 // |
|
2246 // --------------------------------------------------------- |
|
2247 // |
|
2248 void CMmsEncode::EncodeSendConfirmationL() |
|
2249 { |
|
2250 // implemented for test purposes |
|
2251 #ifdef __WINS__ |
|
2252 // Insert message type, TID and version number |
|
2253 EncodeStartingHeaders( KMmsMessageTypeMSendConf, |
|
2254 iMmsHeaders->Tid(), iMmsHeaders->MmsVersion() ); |
|
2255 |
|
2256 EncodeMandatoryByte( KMmsAssignedResponseStatus, |
|
2257 iMmsHeaders->ResponseStatus() ); |
|
2258 |
|
2259 EncodeOptionalStringL( KMmsAssignedResponseText, |
|
2260 iMmsHeaders->ResponseText() ); |
|
2261 |
|
2262 // if send confirmation returns error, it might not contain message id |
|
2263 EncodeOptionalString( KMmsAssignedMessageId, iMmsHeaders->MessageId() ); |
|
2264 |
|
2265 // MMBox related headers - optional |
|
2266 if ( iMmsHeaders->ReadOnlyMMBoxMessageHeaders() ) |
|
2267 { |
|
2268 EncodeOptionalByte( KMmsAssignedStoreStatus, |
|
2269 iMmsHeaders->MMBoxMessageHeadersL().MmsStoreStatus() ); |
|
2270 EncodeOptionalStringL( KMmsAssignedStoreStatusText, |
|
2271 iMmsHeaders->MMBoxMessageHeadersL().MmsStoreStatusText() ); |
|
2272 if ( iMmsHeaders->MMBoxMessageHeadersL().MmsStoreStatus() == |
|
2273 KMmsStatusOk ) |
|
2274 { |
|
2275 // this must be USASCII or URL encoded |
|
2276 // If message was stored to MMBox, this is mandatory |
|
2277 EncodeHeaderAndTextString( KMmsAssignedContentLocation, |
|
2278 iMmsHeaders->ContentLocation() ); |
|
2279 } |
|
2280 } |
|
2281 |
|
2282 #endif |
|
2283 |
|
2284 } |
|
2285 |
|
2286 // --------------------------------------------------------- |
|
2287 // |
|
2288 // --------------------------------------------------------- |
|
2289 // |
|
2290 void CMmsEncode::EncodeRetrieveConfirmationL() |
|
2291 { |
|
2292 // implemented for test purposes |
|
2293 #ifdef __WINS__ |
|
2294 |
|
2295 // Insert message type, TID and version number |
|
2296 EncodeStartingHeaders( KMmsMessageTypeMRetrieveConf, |
|
2297 iMmsHeaders->Tid(), iMmsHeaders->MmsVersion() ); |
|
2298 |
|
2299 // message id |
|
2300 EncodeOptionalString( KMmsAssignedMessageId, iMmsHeaders->MessageId() ); |
|
2301 |
|
2302 // if we have set a date, insert it |
|
2303 EncodeDate( iMmsHeaders->Date() ); |
|
2304 |
|
2305 // If we have set the sender, encode it |
|
2306 if ( iMmsHeaders->Sender().Length() > 0 ) |
|
2307 { |
|
2308 EncodeSenderL( iMmsHeaders->Sender() ); |
|
2309 } |
|
2310 |
|
2311 // previously sent by array |
|
2312 TInt i; |
|
2313 TUint oldPosition; |
|
2314 TUint length; |
|
2315 for ( i = 0; i < iMmsHeaders->PreviouslySentList().Count(); ++i ) |
|
2316 { |
|
2317 oldPosition = iPosition; |
|
2318 length = 0; |
|
2319 // Encode once just to find out filed length |
|
2320 EncodeInteger( iMmsHeaders->PreviouslySentList()[i]->Order() ); |
|
2321 EncodeAddressL( iMmsHeaders->PreviouslySentList()[i]->Sender() ); |
|
2322 length += iPosition - oldPosition; |
|
2323 iPosition = oldPosition; |
|
2324 iEncodeBuffer->Write( iPosition, &KMmsAssignedPreviouslySentBy, 1 ); |
|
2325 iPosition++; |
|
2326 EncodeValueLength( length ); |
|
2327 // now we have added length, do the actual encoding |
|
2328 EncodeInteger( iMmsHeaders->PreviouslySentList()[i]->Order() ); |
|
2329 EncodeAddressL( iMmsHeaders->PreviouslySentList()[i]->Sender() ); |
|
2330 oldPosition = iPosition; |
|
2331 length = 0; |
|
2332 EncodeInteger( iMmsHeaders->PreviouslySentList()[i]->Order() ); |
|
2333 EncodeLongInteger( iMmsHeaders->PreviouslySentList()[i]->Date() ); |
|
2334 length += iPosition - oldPosition; |
|
2335 iPosition = oldPosition; |
|
2336 iEncodeBuffer->Write( iPosition, &KMmsAssignedPreviouslySentDate, 1 ); |
|
2337 iPosition++; |
|
2338 EncodeValueLength( length ); |
|
2339 EncodeInteger( iMmsHeaders->PreviouslySentList()[i]->Order() ); |
|
2340 EncodeLongInteger( iMmsHeaders->PreviouslySentList()[i]->Date() ); |
|
2341 } |
|
2342 |
|
2343 // All recipient lists. If no recipients in some of the lists, |
|
2344 // nothing is encoded, no need to check separately |
|
2345 EncodeRecipientL( iMmsHeaders->ToRecipients(), EMmsTo ); |
|
2346 EncodeRecipientL( iMmsHeaders->CcRecipients(), EMmsCc ); |
|
2347 // no Bcc in retrieve confirmation |
|
2348 |
|
2349 // Subject |
|
2350 EncodeOptionalStringL( KMmsAssignedSubject, iMmsHeaders->Subject() ); |
|
2351 |
|
2352 // MMBox headers |
|
2353 if ( iMmsHeaders->ReadOnlyMMBoxMessageHeaders() ) |
|
2354 { |
|
2355 // X-Mms-MM-State |
|
2356 EncodeOptionalByte( KMmsAssignedMMState, |
|
2357 iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->MmsMMState() ); |
|
2358 // X-MMs-MM-Flags |
|
2359 // The keyword token should always be "add" or "remove" |
|
2360 EncodeKeywordArrayL(); |
|
2361 } |
|
2362 |
|
2363 // Message class |
|
2364 EncodeOptionalByte( KMmsAssignedMessageClass, |
|
2365 iMmsHeaders->MessageClass() ); |
|
2366 |
|
2367 // Priority |
|
2368 EncodeOptionalByte( KMmsAssignedPriority, iMmsHeaders->MessagePriority() ); |
|
2369 |
|
2370 // Delivery report |
|
2371 EncodeOptionalByte( KMmsAssignedDeliveryReport, |
|
2372 iMmsHeaders->DeliveryReport() ); |
|
2373 |
|
2374 // Read reply |
|
2375 EncodeOptionalByte( KMmsAssignedReadReply, iMmsHeaders->ReadReply() ); |
|
2376 |
|
2377 // MMS encapsulation 1.1 headers - optional |
|
2378 if ( iMmsHeaders->MmsVersion() > KMmsVersion1 ) |
|
2379 { |
|
2380 // Do we want to specify reply charging |
|
2381 if ( iMmsHeaders->ReplyCharging() == KMmsReplyChargingAccepted || |
|
2382 iMmsHeaders->ReplyCharging() == KMmsReplyChargingAcceptedTextOnly ) |
|
2383 { |
|
2384 // Reply charging value |
|
2385 EncodeOptionalByte( KMmsAssignedReplyCharging, |
|
2386 iMmsHeaders->ReplyCharging() ); |
|
2387 // Reply charging deadline |
|
2388 EncodeOptionalIntervalOrDate( KMmsAssignedReplyChargingDeadline, |
|
2389 iMmsHeaders->ReplyChargingInterval(), |
|
2390 iMmsHeaders->ReplyChargingDate() ); |
|
2391 // Reply charging size |
|
2392 EncodeReplyChargingSize( iMmsHeaders->ReplyChargingSize() ); |
|
2393 } |
|
2394 // Reply charging ID |
|
2395 EncodeOptionalString( KMmsAssignedReplyChargingID, |
|
2396 iMmsHeaders->ReplyChargingId() ); |
|
2397 // status of the operation |
|
2398 EncodeOptionalByte( KMmsAssignedRetrieveStatus, |
|
2399 iMmsHeaders->ResponseStatus() ); |
|
2400 |
|
2401 EncodeOptionalStringL( KMmsAssignedRetrieveText, |
|
2402 iMmsHeaders->ResponseText() ); |
|
2403 } |
|
2404 |
|
2405 // version 1.2 headers - optional |
|
2406 if ( iMmsHeaders->MmsVersion() > KMmsVersion11 ) |
|
2407 { |
|
2408 // Distribution indicator |
|
2409 EncodeOptionalByte( KMmsAssignedDistributionIndicator, |
|
2410 iMmsHeaders->DistributionIndicator() ); |
|
2411 } |
|
2412 |
|
2413 // version 1.3 headers - optional |
|
2414 if ( iMmsHeaders->MmsVersion() > KMmsVersion12 ) |
|
2415 { |
|
2416 // X-Mms-Applic-ID, X-Mms-Reply-Applic-ID and X-Mms-Aux-Applic-Info |
|
2417 EncodeApplicationHeadersL(); |
|
2418 // X-Mms-Content-Class |
|
2419 EncodeOptionalByte( KMmsAssignedContentClass, iMmsHeaders->ContentClass() ); |
|
2420 // X-Mms-DRM-Content |
|
2421 EncodeOptionalByte( KMmsAssignedDrmContent, iMmsHeaders->DrmContent() ); |
|
2422 // X-Mms-Replace-ID |
|
2423 EncodeOptionalString( KMmsAssignedReplaceId, iMmsHeaders->ReplaceCancelId() ); |
|
2424 } |
|
2425 |
|
2426 // Start pointer |
|
2427 TUint ii = 0; |
|
2428 // Get Root TMsvId from headers if set |
|
2429 TMsvId rootId = iMmsHeaders->MessageRoot(); |
|
2430 |
|
2431 TInt error = KErrNone; |
|
2432 if ( iEntryWrapper ) |
|
2433 { |
|
2434 CMsvStore* store = iEntryWrapper->ReadStoreL(); |
|
2435 CleanupStack::PushL( store ); |
|
2436 MMsvAttachmentManager& attachMan = store->AttachmentManagerL(); |
|
2437 TRAP( error, |
|
2438 { |
|
2439 CMsvAttachment* attachmentInfo = attachMan.GetAttachmentInfoL( |
|
2440 (TMsvAttachmentId) rootId ); |
|
2441 delete attachmentInfo; // we just wanted to check that it was found |
|
2442 } |
|
2443 ); |
|
2444 CleanupStack::PopAndDestroy( store ); |
|
2445 } |
|
2446 |
|
2447 // If we have a valid root part, we send the message as multipart/related. |
|
2448 // Otherwise we send it as multipart mixed. |
|
2449 // We don't try to guess what the root is supposed to be, if it |
|
2450 // is not specified or does not point to an existing attachment. |
|
2451 |
|
2452 if ( error == KErrNone && rootId != 0 && iEntryWrapper ) |
|
2453 { |
|
2454 EncodeMultipartRelatedHeaderL( rootId ); |
|
2455 } |
|
2456 else |
|
2457 { |
|
2458 EncodeMultipartMixedHeaderL(); |
|
2459 } |
|
2460 |
|
2461 |
|
2462 #endif |
|
2463 } |
|
2464 |
|
2465 // --------------------------------------------------------- |
|
2466 // |
|
2467 // --------------------------------------------------------- |
|
2468 // |
|
2469 void CMmsEncode::EncodeDeliveryReportL() |
|
2470 { |
|
2471 // implemented for test purposes |
|
2472 #ifdef __WINS__ |
|
2473 |
|
2474 // Insert message type, TID and version number |
|
2475 EncodeStartingHeaders( KMmsMessageTypeDeliveryInd, TPtrC8(), |
|
2476 iMmsHeaders->MmsVersion() ); |
|
2477 |
|
2478 EncodeHeaderAndTextString( KMmsAssignedMessageId, |
|
2479 iMmsHeaders->MessageId() ); |
|
2480 |
|
2481 EncodeRecipientL( iMmsHeaders->ToRecipients(), EMmsTo ); |
|
2482 |
|
2483 // if we have set a date, insert it |
|
2484 EncodeDate( iMmsHeaders->Date() ); |
|
2485 |
|
2486 // insert message status |
|
2487 EncodeMandatoryByte( KMmsAssignedStatus, iMmsHeaders->Status() ); |
|
2488 |
|
2489 // version 1.3 headers - optional |
|
2490 if ( iMmsHeaders->MmsVersion() > KMmsVersion12 ) |
|
2491 { |
|
2492 // X-Mms-Status-Text |
|
2493 // Status text is stored in the same place as response text and retrieve |
|
2494 // text as only one of them can appear in any PDU |
|
2495 EncodeOptionalStringL( KMmsAssignedStatusText, |
|
2496 iMmsHeaders->ResponseText() ); |
|
2497 // X-Mms-Applic-ID, X-Mms-Reply-Applic-ID and X-Mms-Aux-Applic-Info |
|
2498 EncodeApplicationHeadersL(); |
|
2499 } |
|
2500 |
|
2501 #endif |
|
2502 } |
|
2503 |
|
2504 // --------------------------------------------------------- |
|
2505 // |
|
2506 // --------------------------------------------------------- |
|
2507 // |
|
2508 void CMmsEncode::EncodeForwardRequestL() |
|
2509 { |
|
2510 // Insert message type, TID and version number |
|
2511 EncodeStartingHeaders( KMmsMessageTypeForwardReq, |
|
2512 iMmsHeaders->Tid(), iMmsHeaders->MmsVersion() ); |
|
2513 |
|
2514 // if we have set a date, insert it |
|
2515 EncodeDate( iMmsHeaders->Date() ); |
|
2516 |
|
2517 // If we have set the sender, encode it |
|
2518 // If not, we ask MMSC to add the sender |
|
2519 EncodeSenderL( iMmsHeaders->Sender() ); |
|
2520 |
|
2521 // All recipient lists. If no recipients in some of the lists, |
|
2522 // nothing is encoded, no need to check separately |
|
2523 EncodeRecipientL( iMmsHeaders->ToRecipients(), EMmsTo ); |
|
2524 EncodeRecipientL( iMmsHeaders->CcRecipients(), EMmsCc ); |
|
2525 EncodeRecipientL( iMmsHeaders->BccRecipients(), EMmsBcc ); |
|
2526 |
|
2527 // Expiration time |
|
2528 EncodeOptionalIntervalOrDate( KMmsAssignedExpiry, |
|
2529 iMmsHeaders->ExpiryInterval(), |
|
2530 iMmsHeaders->ExpiryDate() ); |
|
2531 |
|
2532 // Delivery time |
|
2533 EncodeOptionalIntervalOrDate( KMmsAssignedDeliveryTime, |
|
2534 iMmsHeaders->DeliveryTimeInterval(), |
|
2535 iMmsHeaders->DeliveryDate() ); |
|
2536 |
|
2537 // Delivery report allowed |
|
2538 EncodeOptionalByte( KMmsAssignedReportAllowed, |
|
2539 iMmsHeaders->ReportAllowed() ); |
|
2540 |
|
2541 // Delivery report |
|
2542 EncodeOptionalByte( KMmsAssignedDeliveryReport, |
|
2543 iMmsHeaders->DeliveryReport() ); |
|
2544 |
|
2545 // Read reply |
|
2546 EncodeOptionalByte( KMmsAssignedReadReply, iMmsHeaders->ReadReply() ); |
|
2547 |
|
2548 // version 1.2 headers - optional |
|
2549 if ( iMmsHeaders->MmsVersion() > KMmsVersion11 ) |
|
2550 { |
|
2551 // MMBox related headers - optional |
|
2552 if ( iMmsHeaders->ReadOnlyMMBoxMessageHeaders() ) |
|
2553 { |
|
2554 // X-Mms-MM-Store |
|
2555 EncodeOptionalByte( KMmsAssignedMmsStore, |
|
2556 iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->MmsStore() ); |
|
2557 if ( iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->MmsStore() == KMmsYes || |
|
2558 iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->MmsStored() == KMmsYes ) |
|
2559 { |
|
2560 // X-Mms-MM-State |
|
2561 EncodeOptionalByte( KMmsAssignedMMState, |
|
2562 iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->MmsMMState() ); |
|
2563 // X-MMs-MM-Flags |
|
2564 // The keyword token should always be "add" or "remove" |
|
2565 EncodeKeywordArrayL(); |
|
2566 } |
|
2567 } |
|
2568 } |
|
2569 |
|
2570 // version 1.3 headers - optional |
|
2571 if ( iMmsHeaders->MmsVersion() > KMmsVersion12 ) |
|
2572 { |
|
2573 // Do we want to specify reply charging |
|
2574 if ( iMmsHeaders->ReplyCharging() == KMmsReplyChargingRequested || |
|
2575 iMmsHeaders->ReplyCharging() == KMmsReplyChargingRequestedTextOnly ) |
|
2576 { |
|
2577 // Reply charging value |
|
2578 EncodeOptionalByte( KMmsAssignedReplyCharging, |
|
2579 iMmsHeaders->ReplyCharging() ); |
|
2580 // Reply charging deadline |
|
2581 EncodeOptionalIntervalOrDate( KMmsAssignedReplyChargingDeadline, |
|
2582 iMmsHeaders->ReplyChargingInterval(), |
|
2583 iMmsHeaders->ReplyChargingDate() ); |
|
2584 // Reply charging size |
|
2585 EncodeReplyChargingSize( iMmsHeaders->ReplyChargingSize() ); |
|
2586 } |
|
2587 } |
|
2588 |
|
2589 // Mandatory content-location |
|
2590 // this must be USASCII or URL encoded |
|
2591 EncodeHeaderAndTextString( KMmsAssignedContentLocation, |
|
2592 iMmsHeaders->ContentLocation() ); |
|
2593 |
|
2594 } |
|
2595 |
|
2596 // --------------------------------------------------------- |
|
2597 // |
|
2598 // --------------------------------------------------------- |
|
2599 // |
|
2600 void CMmsEncode::EncodeForwardConfirmationL() |
|
2601 { |
|
2602 // implemented for test purposes |
|
2603 #ifdef __WINS__ |
|
2604 // Insert message type, TID and version number |
|
2605 EncodeStartingHeaders( KMmsMessageTypeForwardConf, |
|
2606 iMmsHeaders->Tid(), iMmsHeaders->MmsVersion() ); |
|
2607 |
|
2608 EncodeMandatoryByte( KMmsAssignedResponseStatus, |
|
2609 iMmsHeaders->ResponseStatus() ); |
|
2610 |
|
2611 EncodeOptionalStringL( KMmsAssignedResponseText, |
|
2612 iMmsHeaders->ResponseText() ); |
|
2613 |
|
2614 EncodeOptionalString( KMmsAssignedMessageId, iMmsHeaders->MessageId() ); |
|
2615 |
|
2616 // MMBox related headers - optional |
|
2617 if ( iMmsHeaders->ReadOnlyMMBoxMessageHeaders() ) |
|
2618 { |
|
2619 EncodeOptionalByte( KMmsAssignedStoreStatus, |
|
2620 iMmsHeaders->MMBoxMessageHeadersL().MmsStoreStatus() ); |
|
2621 EncodeOptionalStringL( KMmsAssignedStoreStatusText, |
|
2622 iMmsHeaders->MMBoxMessageHeadersL().MmsStoreStatusText() ); |
|
2623 if ( iMmsHeaders->MMBoxMessageHeadersL().MmsStoreStatus() == |
|
2624 KMmsStatusOk ) |
|
2625 { |
|
2626 // this must be USASCII or URL encoded |
|
2627 // If message was stored to MMBox, this is mandatory |
|
2628 EncodeHeaderAndTextString( KMmsAssignedContentLocation, |
|
2629 iMmsHeaders->ContentLocation() ); |
|
2630 } |
|
2631 } |
|
2632 |
|
2633 #endif |
|
2634 } |
|
2635 |
|
2636 // --------------------------------------------------------- |
|
2637 // |
|
2638 // --------------------------------------------------------- |
|
2639 // |
|
2640 void CMmsEncode::EncodeReadReplyL() |
|
2641 { |
|
2642 // Insert message type, TID and version number |
|
2643 EncodeStartingHeaders( iMmsHeaders->MessageType(), TPtrC8(), iMmsHeaders->MmsVersion() ); |
|
2644 |
|
2645 // message id |
|
2646 EncodeHeaderAndTextString( KMmsAssignedMessageId, |
|
2647 iMmsHeaders->MessageId() ); |
|
2648 |
|
2649 // originator of the original message |
|
2650 EncodeRecipientL( iMmsHeaders->ToRecipients(), EMmsTo ); |
|
2651 |
|
2652 // If we have set the sender, encode it |
|
2653 // If not, we ask MMSC to add the sender |
|
2654 EncodeSenderL( iMmsHeaders->Sender() ); |
|
2655 |
|
2656 // if we have set a date, insert it |
|
2657 EncodeDate( iMmsHeaders->Date() ); |
|
2658 |
|
2659 EncodeMandatoryByte( KMmsAssignedReadStatus, iMmsHeaders->ReadStatus() ); |
|
2660 |
|
2661 // version 1.3 headers - optional |
|
2662 if ( iMmsHeaders->MmsVersion() > KMmsVersion12 ) |
|
2663 { |
|
2664 // X-Mms-Applic-ID, X-Mms-Reply-Applic-ID and X-Mms-Aux-Applic-Info |
|
2665 EncodeApplicationHeadersL(); |
|
2666 } |
|
2667 } |
|
2668 |
|
2669 // --------------------------------------------------------- |
|
2670 // |
|
2671 // --------------------------------------------------------- |
|
2672 // |
|
2673 void CMmsEncode::EncodeMMBoxStoreRequestL() |
|
2674 { |
|
2675 // Insert message type, TID and version number |
|
2676 EncodeStartingHeaders( KMmsMessageTypeMboxStoreReq, iMmsHeaders->Tid(), |
|
2677 iMmsHeaders->MmsVersion() ); |
|
2678 |
|
2679 // this must be USASCII or URL encoded |
|
2680 EncodeHeaderAndTextString( KMmsAssignedContentLocation, |
|
2681 iMmsHeaders->ContentLocation() ); |
|
2682 |
|
2683 // MMBox headers |
|
2684 if ( iMmsHeaders->ReadOnlyMMBoxMessageHeaders() ) |
|
2685 { |
|
2686 // X-Mms-MM-State |
|
2687 EncodeOptionalByte( KMmsAssignedMMState, |
|
2688 iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->MmsMMState() ); |
|
2689 // X-MMs-MM-Flags |
|
2690 // The keyword token should always be "add" or "remove" |
|
2691 EncodeKeywordArrayL(); |
|
2692 } |
|
2693 } |
|
2694 |
|
2695 // --------------------------------------------------------- |
|
2696 // |
|
2697 // --------------------------------------------------------- |
|
2698 // |
|
2699 void CMmsEncode::EncodeMMBoxStoreConfirmationL() |
|
2700 { |
|
2701 // implemented for test purposes |
|
2702 #ifdef __WINS__ |
|
2703 // Insert message type, TID and version number |
|
2704 EncodeStartingHeaders( KMmsMessageTypeMboxStoreConf, iMmsHeaders->Tid(), |
|
2705 iMmsHeaders->MmsVersion() ); |
|
2706 |
|
2707 // this must be USASCII or URL encoded |
|
2708 EncodeOptionalString( KMmsAssignedContentLocation, |
|
2709 iMmsHeaders->ContentLocation() ); |
|
2710 |
|
2711 EncodeMandatoryByte( KMmsAssignedStoreStatus, |
|
2712 iMmsHeaders->MMBoxMessageHeadersL().MmsStoreStatus() ); |
|
2713 |
|
2714 EncodeOptionalStringL( KMmsAssignedStoreStatusText, |
|
2715 iMmsHeaders->MMBoxMessageHeadersL().MmsStoreStatusText() ); |
|
2716 |
|
2717 #endif |
|
2718 } |
|
2719 |
|
2720 // --------------------------------------------------------- |
|
2721 // |
|
2722 // --------------------------------------------------------- |
|
2723 // |
|
2724 void CMmsEncode::EncodeMMBoxViewRequestL() |
|
2725 { |
|
2726 // Insert message type, TID and version number |
|
2727 EncodeStartingHeaders( KMmsMessageTypeMboxViewReq, iMmsHeaders->Tid(), |
|
2728 iMmsHeaders->MmsVersion() ); |
|
2729 |
|
2730 // Insert content location header. There may be more than one |
|
2731 EncodeContentLocationArray(); |
|
2732 |
|
2733 if ( iMmsHeaders->ReadOnlyMMBoxMessageHeaders() ) |
|
2734 { |
|
2735 // X-MMs-MM-Flags. The token should always be "filter" |
|
2736 EncodeKeywordArrayL(); |
|
2737 } |
|
2738 |
|
2739 if ( iMmsHeaders->ReadOnlyMMBoxViewHeaders() ) |
|
2740 { |
|
2741 CMmsMMBoxViewHeaders& viewHeaders = iMmsHeaders->MMBoxViewHeadersL(); |
|
2742 |
|
2743 // states used as filter |
|
2744 // X-Mms-MM-State may appear multiple times in view request |
|
2745 EncodeMMBoxStates( viewHeaders.MMStateArray() ); |
|
2746 |
|
2747 // start |
|
2748 EncodeOptionalInteger( KMmsAssignedStart, viewHeaders.MmsStart() ); |
|
2749 // limit |
|
2750 if ( viewHeaders.MmsLimit() != KMaxTUint32 ) |
|
2751 { |
|
2752 // 0 means no message information, absence means all remaining |
|
2753 // messages. |
|
2754 // If header has value KMaxTUint32, it means that info about all |
|
2755 // remaining messages is wanted. |
|
2756 iEncodeBuffer->Write( iPosition, &KMmsAssignedLimit, 1 ); |
|
2757 iPosition++; |
|
2758 EncodeInteger( viewHeaders.MmsLimit() ); |
|
2759 } |
|
2760 |
|
2761 EncodeAttributes( viewHeaders.AttributeArray() ); |
|
2762 // request totals |
|
2763 EncodeOptionalByte( KMmsAssignedTotals, viewHeaders.MmsTotals() ); |
|
2764 // request quotas |
|
2765 EncodeOptionalByte( KMmsAssignedQuotas, viewHeaders.MmsQuotas() ); |
|
2766 } |
|
2767 } |
|
2768 |
|
2769 // --------------------------------------------------------- |
|
2770 // |
|
2771 // --------------------------------------------------------- |
|
2772 // |
|
2773 void CMmsEncode::EncodeMMBoxViewConfirmationL() |
|
2774 { |
|
2775 // implemented for test purposes |
|
2776 #ifdef __WINS__ |
|
2777 // Insert message type, TID and version number |
|
2778 EncodeStartingHeaders( KMmsMessageTypeMboxViewConf, |
|
2779 iMmsHeaders->Tid(), iMmsHeaders->MmsVersion() ); |
|
2780 |
|
2781 EncodeMandatoryByte( KMmsAssignedResponseStatus, |
|
2782 iMmsHeaders->ResponseStatus() ); |
|
2783 |
|
2784 EncodeOptionalStringL( KMmsAssignedResponseText, |
|
2785 iMmsHeaders->ResponseText() ); |
|
2786 |
|
2787 EncodeContentLocationArray(); |
|
2788 |
|
2789 // MMBox headers |
|
2790 if ( iMmsHeaders->ReadOnlyMMBoxMessageHeaders() ) |
|
2791 { |
|
2792 // X-MMs-MM-Flags. The token should always be "filter" |
|
2793 EncodeKeywordArrayL(); |
|
2794 } |
|
2795 |
|
2796 if ( iMmsHeaders->ReadOnlyMMBoxViewHeaders() ) |
|
2797 { |
|
2798 CMmsMMBoxViewHeaders& viewHeaders = iMmsHeaders->MMBoxViewHeadersL(); |
|
2799 |
|
2800 // states used as filter |
|
2801 // X-Mms-MM-State may appear multiple times in view request |
|
2802 EncodeMMBoxStates( viewHeaders.MMStateArray() ); |
|
2803 |
|
2804 // start |
|
2805 EncodeOptionalInteger( KMmsAssignedStart, viewHeaders.MmsStart() ); |
|
2806 // limit |
|
2807 if ( viewHeaders.MmsLimit() != KMaxTUint32 ) |
|
2808 { |
|
2809 // 0 means no message information, absence means all remaining |
|
2810 // messages. |
|
2811 // If header has value KMaxTUint32, it means that info about |
|
2812 // all remaining messages is wanted. |
|
2813 iEncodeBuffer->Write( iPosition, &KMmsAssignedLimit, 1 ); |
|
2814 iPosition++; |
|
2815 EncodeInteger( viewHeaders.MmsLimit() ); |
|
2816 } |
|
2817 EncodeAttributes( viewHeaders.AttributeArray() ); |
|
2818 |
|
2819 // totals |
|
2820 TUint oldPosition = iPosition; |
|
2821 TUint length = 0; |
|
2822 |
|
2823 if ( viewHeaders.MMBoxTotalNumber() != KMaxTUint32 ) |
|
2824 { |
|
2825 oldPosition = iPosition; |
|
2826 EncodeInteger( viewHeaders.MMBoxTotalNumber() ); |
|
2827 length = iPosition - oldPosition; |
|
2828 length += 1; // quota token |
|
2829 iPosition = oldPosition; |
|
2830 iEncodeBuffer->Write( iPosition, &KMmsAssignedMboxTotals, 1 ); |
|
2831 iPosition++; |
|
2832 EncodeValueLength( length ); |
|
2833 iEncodeBuffer->Write( iPosition, &KMmsMessageCountToken, 1 ); |
|
2834 iPosition++; |
|
2835 EncodeInteger( viewHeaders.MMBoxTotalNumber() ); |
|
2836 } |
|
2837 |
|
2838 if ( viewHeaders.MMBoxTotalSize() != KMaxTUint32 ) |
|
2839 { |
|
2840 oldPosition = iPosition; |
|
2841 EncodeInteger( viewHeaders.MMBoxTotalSize() ); |
|
2842 length = iPosition - oldPosition; |
|
2843 length += 1; // quota token |
|
2844 iPosition = oldPosition; |
|
2845 iEncodeBuffer->Write( iPosition, &KMmsAssignedMboxTotals, 1 ); |
|
2846 iPosition++; |
|
2847 EncodeValueLength( length ); |
|
2848 iEncodeBuffer->Write( iPosition, &KMmsMessageSizeToken, 1 ); |
|
2849 iPosition++; |
|
2850 EncodeInteger( viewHeaders.MMBoxTotalSize() ); |
|
2851 } |
|
2852 |
|
2853 // quotas |
|
2854 if ( viewHeaders.MMBoxQuotaNumber() != KMaxTUint32 ) |
|
2855 { |
|
2856 oldPosition = iPosition; |
|
2857 EncodeInteger( viewHeaders.MMBoxQuotaNumber() ); |
|
2858 length = iPosition - oldPosition; |
|
2859 length += 1; // quota token |
|
2860 iPosition = oldPosition; |
|
2861 iEncodeBuffer->Write( iPosition, &KMmsAssignedMboxQuotas, 1 ); |
|
2862 iPosition++; |
|
2863 EncodeValueLength( length ); |
|
2864 iEncodeBuffer->Write( iPosition, &KMmsMessageCountToken, 1 ); |
|
2865 iPosition++; |
|
2866 EncodeInteger( viewHeaders.MMBoxQuotaNumber() ); |
|
2867 } |
|
2868 |
|
2869 if ( viewHeaders.MMBoxQuotaSize() != KMaxTUint32 ) |
|
2870 { |
|
2871 oldPosition = iPosition; |
|
2872 EncodeInteger( viewHeaders.MMBoxQuotaSize() ); |
|
2873 length = iPosition - oldPosition; |
|
2874 length += 1; // quota token |
|
2875 iPosition = oldPosition; |
|
2876 iEncodeBuffer->Write( iPosition, &KMmsAssignedMboxQuotas, 1 ); |
|
2877 iPosition++; |
|
2878 EncodeValueLength( length ); |
|
2879 iEncodeBuffer->Write( iPosition, &KMmsMessageSizeToken, 1 ); |
|
2880 iPosition++; |
|
2881 EncodeInteger( viewHeaders.MMBoxQuotaSize() ); |
|
2882 } |
|
2883 |
|
2884 // Message count |
|
2885 // This should in principle come from the viewHeaders.MmsMessageCount() |
|
2886 // But in this context the number of messages will be the number of |
|
2887 // attachments available in this entry |
|
2888 |
|
2889 // However, we will use the viewHeaders.MmsMessageCount() to generate |
|
2890 // the header so that we can test that the decoding part can handle |
|
2891 // possible conflict between message number and the number of parts |
|
2892 // in the multipart structure. This header is optional. KMaxTUint32 |
|
2893 // will mean unspecified. |
|
2894 |
|
2895 if ( viewHeaders.MmsMessageCount() != KMaxTUint32 ) |
|
2896 { |
|
2897 iEncodeBuffer->Write( iPosition, &KMmsAssignedMessageCount, 1 ); |
|
2898 iPosition++; |
|
2899 EncodeInteger( viewHeaders.MmsMessageCount() ); |
|
2900 } |
|
2901 } |
|
2902 |
|
2903 if ( iNumberOfAttachments == 0 ) |
|
2904 { |
|
2905 EncodeMandatoryByte( KMmsAssignedContentType, KMmsAssignedAny ); |
|
2906 } |
|
2907 else |
|
2908 { |
|
2909 EncodeMultipartMixedHeaderL(); |
|
2910 } |
|
2911 #endif |
|
2912 } |
|
2913 |
|
2914 // --------------------------------------------------------- |
|
2915 // |
|
2916 // --------------------------------------------------------- |
|
2917 // |
|
2918 void CMmsEncode::EncodeMMBoxUploadRequestL() |
|
2919 { |
|
2920 // Insert message type, TID and version number |
|
2921 EncodeStartingHeaders( KMmsMessageTypeMBoxUploadReq, iMmsHeaders->Tid(), |
|
2922 iMmsHeaders->MmsVersion() ); |
|
2923 |
|
2924 // MMBox headers |
|
2925 if ( iMmsHeaders->ReadOnlyMMBoxMessageHeaders() ) |
|
2926 { |
|
2927 // X-Mms-MM-State |
|
2928 EncodeOptionalByte( KMmsAssignedMMState, |
|
2929 iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->MmsMMState() ); |
|
2930 // X-MMs-MM-Flags |
|
2931 // The keyword token should always be "add" or "remove" |
|
2932 EncodeKeywordArrayL(); |
|
2933 } |
|
2934 |
|
2935 // Get Root TMsvId from headers if set |
|
2936 TMsvAttachmentId rootId = iMmsHeaders->MessageRoot(); |
|
2937 |
|
2938 // Find the matching id from attachment list |
|
2939 |
|
2940 TInt error = KErrNone; |
|
2941 if ( iEntryWrapper ) |
|
2942 { |
|
2943 CMsvStore* store = iEntryWrapper->ReadStoreL(); |
|
2944 CleanupStack::PushL( store ); |
|
2945 // Only new attachment structure is supported |
|
2946 MMsvAttachmentManager& attachMan = store->AttachmentManagerL(); |
|
2947 TRAP( error, |
|
2948 { |
|
2949 CMsvAttachment* attachmentInfo = attachMan.GetAttachmentInfoL( |
|
2950 (TMsvAttachmentId) rootId ); |
|
2951 delete attachmentInfo; // we just wanted to check that it was found |
|
2952 } |
|
2953 ); |
|
2954 CleanupStack::PopAndDestroy( store ); |
|
2955 } |
|
2956 |
|
2957 // If we have a valid root part, we send the message as multipart/related. |
|
2958 // Otherwise we send it as multipart mixed. |
|
2959 // We don't try to guess what the root is supposed to be, if it |
|
2960 // is not specified or does not point to an existing attachment. |
|
2961 |
|
2962 // actually the content should be an MMS PDU as in M-MBox-Descr PDU |
|
2963 // It is unclear if if should be wrapped in a multipart structure |
|
2964 // (containing only one header) |
|
2965 // or if the content type should be application/vnd.wap.mms-message |
|
2966 if ( error == KErrNone && rootId != 0 && iEntryWrapper ) |
|
2967 { |
|
2968 EncodeMultipartRelatedHeaderL( rootId ); |
|
2969 } |
|
2970 else |
|
2971 { |
|
2972 EncodeMultipartMixedHeaderL(); |
|
2973 } |
|
2974 |
|
2975 } |
|
2976 |
|
2977 // --------------------------------------------------------- |
|
2978 // |
|
2979 // --------------------------------------------------------- |
|
2980 // |
|
2981 void CMmsEncode::EncodeMMBoxUploadConfirmationL() |
|
2982 { |
|
2983 // implemented for test purposes |
|
2984 #ifdef __WINS__ |
|
2985 // Insert message type, TID and version number |
|
2986 EncodeStartingHeaders( KMmsMessageTypeMBoxUploadConf, iMmsHeaders->Tid(), |
|
2987 iMmsHeaders->MmsVersion() ); |
|
2988 |
|
2989 // this must be USASCII or URL encoded |
|
2990 EncodeOptionalString( KMmsAssignedContentLocation, |
|
2991 iMmsHeaders->ContentLocation() ); |
|
2992 |
|
2993 EncodeMandatoryByte( KMmsAssignedStoreStatus, |
|
2994 iMmsHeaders->MMBoxMessageHeadersL().MmsStoreStatus() ); |
|
2995 |
|
2996 EncodeOptionalStringL( KMmsAssignedStoreStatusText, |
|
2997 iMmsHeaders->MMBoxMessageHeadersL().MmsStoreStatusText() ); |
|
2998 #endif |
|
2999 } |
|
3000 |
|
3001 // --------------------------------------------------------- |
|
3002 // |
|
3003 // --------------------------------------------------------- |
|
3004 // |
|
3005 void CMmsEncode::EncodeDeleteRequestL() |
|
3006 { |
|
3007 // Insert message type, TID and version number |
|
3008 |
|
3009 EncodeStartingHeaders( iMmsHeaders->MessageType(), iMmsHeaders->Tid(), |
|
3010 iMmsHeaders->MmsVersion() ); |
|
3011 |
|
3012 // Insert content location header. There may be more than one |
|
3013 EncodeContentLocationArray(); |
|
3014 } |
|
3015 |
|
3016 // --------------------------------------------------------- |
|
3017 // |
|
3018 // --------------------------------------------------------- |
|
3019 // |
|
3020 void CMmsEncode::EncodeDeleteConfirmationL() |
|
3021 { |
|
3022 // implemented for test purposes |
|
3023 #ifdef __WINS__ |
|
3024 // Insert message type, TID and version number |
|
3025 EncodeStartingHeaders( iMmsHeaders->MessageType(), iMmsHeaders->Tid(), |
|
3026 iMmsHeaders->MmsVersion() ); |
|
3027 |
|
3028 // content location, response status and response text headers have |
|
3029 // different format from other PDUs |
|
3030 |
|
3031 const RPointerArray<CMmsDeleteResultArray>& resultArray = |
|
3032 iMmsHeaders->DeleteResultArray(); |
|
3033 |
|
3034 TInt i; |
|
3035 TInt length = 0; |
|
3036 TInt oldPosition = 0; |
|
3037 TUint oldIndex = KMaxTUint32; |
|
3038 |
|
3039 for ( i = 0; i < resultArray.Count(); i++ ) |
|
3040 { |
|
3041 TUint index = resultArray[i]->Order(); |
|
3042 if ( index != oldIndex ) |
|
3043 { |
|
3044 // We add status and status text only once, there may be more |
|
3045 // than one content location with the same status |
|
3046 oldIndex = index; |
|
3047 if ( resultArray[i]->ResponseStatus() != 0 ) |
|
3048 { |
|
3049 oldPosition = iPosition; |
|
3050 length = 0; |
|
3051 // Encode once just to find out field length |
|
3052 EncodeInteger( index ); |
|
3053 length += iPosition - oldPosition; |
|
3054 length ++; // response status is only one byte |
|
3055 iPosition = oldPosition; |
|
3056 // now we have calculated length, do the actual encoding |
|
3057 iEncodeBuffer->Write( iPosition, &KMmsAssignedResponseStatus, 1 ); |
|
3058 iPosition++; |
|
3059 EncodeValueLength( length ); |
|
3060 EncodeInteger( index ); |
|
3061 TUint8 value = (TUint8) resultArray[i]->ResponseStatus(); |
|
3062 iEncodeBuffer->Write( iPosition, &value, 1 ); |
|
3063 iPosition++; |
|
3064 } |
|
3065 if ( resultArray[i]->ResponseText().Length() > 0 ) |
|
3066 { |
|
3067 oldPosition = iPosition; |
|
3068 length = 0; |
|
3069 // Encode once just to find out field length |
|
3070 EncodeInteger( index ); |
|
3071 EncodeTextStringL( resultArray[i]->ResponseText() ); |
|
3072 length += iPosition - oldPosition; |
|
3073 iPosition = oldPosition; |
|
3074 // now we have calculated length, do the actual encoding |
|
3075 iEncodeBuffer->Write( iPosition, &KMmsAssignedResponseText, 1 ); |
|
3076 iPosition++; |
|
3077 EncodeValueLength( length ); |
|
3078 EncodeInteger( index ); |
|
3079 EncodeTextStringL( resultArray[i]->ResponseText() ); |
|
3080 } |
|
3081 } |
|
3082 if ( resultArray[i]->ContentLocation().Length() > 0 ) |
|
3083 { |
|
3084 oldPosition = iPosition; |
|
3085 length = 0; |
|
3086 // Encode once just to find out field length |
|
3087 EncodeInteger( index ); |
|
3088 EncodeTextString( resultArray[i]->ContentLocation() ); |
|
3089 length += iPosition - oldPosition; |
|
3090 iPosition = oldPosition; |
|
3091 // now we have calculated length, do the actual encoding |
|
3092 iEncodeBuffer->Write( iPosition, &KMmsAssignedContentLocation, 1 ); |
|
3093 iPosition++; |
|
3094 EncodeValueLength( length ); |
|
3095 EncodeInteger( index ); |
|
3096 EncodeTextString( resultArray[i]->ContentLocation() ); |
|
3097 } |
|
3098 } |
|
3099 #endif |
|
3100 } |
|
3101 |
|
3102 // --------------------------------------------------------- |
|
3103 // |
|
3104 // --------------------------------------------------------- |
|
3105 // |
|
3106 void CMmsEncode::EncodeMMBoxDescriptionL() |
|
3107 { |
|
3108 // implemented for test purposes |
|
3109 #ifdef __WINS__ |
|
3110 EncodeMandatoryByte( KMmsAssignedMessageType, KMmsMessageTypeMBoxDescr ); |
|
3111 |
|
3112 // this must be USASCII or URL encoded |
|
3113 EncodeOptionalString( KMmsAssignedContentLocation, |
|
3114 iMmsHeaders->ContentLocation() ); |
|
3115 |
|
3116 EncodeOptionalString( KMmsAssignedMessageId, iMmsHeaders->MessageId() ); |
|
3117 |
|
3118 // MMBox headers |
|
3119 if ( iMmsHeaders->ReadOnlyMMBoxMessageHeaders() ) |
|
3120 { |
|
3121 // X-Mms-MM-State |
|
3122 EncodeOptionalByte( KMmsAssignedMMState, |
|
3123 iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->MmsMMState() ); |
|
3124 // X-MMs-MM-Flags |
|
3125 // The keyword token should always be "add" or "remove" |
|
3126 EncodeKeywordArrayL(); |
|
3127 } |
|
3128 |
|
3129 // if we have set a date, insert it |
|
3130 EncodeDate( iMmsHeaders->Date() ); |
|
3131 |
|
3132 // sender is optional |
|
3133 if ( iMmsHeaders->Sender().Length() > 0 ) |
|
3134 { |
|
3135 EncodeSenderL( iMmsHeaders->Sender() ); |
|
3136 } |
|
3137 |
|
3138 // All recipient lists. If no recipients in some of the lists, |
|
3139 // nothing is encoded, no need to check separately |
|
3140 EncodeRecipientL( iMmsHeaders->ToRecipients(), EMmsTo ); |
|
3141 EncodeRecipientL( iMmsHeaders->CcRecipients(), EMmsCc ); |
|
3142 EncodeRecipientL( iMmsHeaders->BccRecipients(), EMmsBcc ); |
|
3143 |
|
3144 // Message class |
|
3145 EncodeOptionalByte( KMmsAssignedMessageClass, |
|
3146 iMmsHeaders->MessageClass() ); |
|
3147 |
|
3148 // Subject |
|
3149 EncodeOptionalStringL( KMmsAssignedSubject, iMmsHeaders->Subject() ); |
|
3150 |
|
3151 // Priority |
|
3152 EncodeOptionalByte( KMmsAssignedPriority, iMmsHeaders->MessagePriority() ); |
|
3153 |
|
3154 // Delivery time |
|
3155 EncodeOptionalIntervalOrDate( KMmsAssignedDeliveryTime, |
|
3156 iMmsHeaders->DeliveryTimeInterval(), |
|
3157 iMmsHeaders->DeliveryDate() ); |
|
3158 |
|
3159 // Expiration time |
|
3160 EncodeOptionalIntervalOrDate( KMmsAssignedExpiry, |
|
3161 iMmsHeaders->ExpiryInterval(), |
|
3162 iMmsHeaders->ExpiryDate() ); |
|
3163 |
|
3164 // Delivery report |
|
3165 EncodeOptionalByte( KMmsAssignedDeliveryReport, |
|
3166 iMmsHeaders->DeliveryReport() ); |
|
3167 |
|
3168 // Read reply |
|
3169 EncodeOptionalByte( KMmsAssignedReadReply, iMmsHeaders->ReadReply() ); |
|
3170 |
|
3171 if ( iMmsHeaders->MessageSize() > 0 ) |
|
3172 { |
|
3173 iEncodeBuffer->Write( iPosition, &KMmsAssignedMessageSize, 1 ); |
|
3174 iPosition++; |
|
3175 TInt64 size = iMmsHeaders->MessageSize(); |
|
3176 EncodeLongInteger( size ); |
|
3177 } |
|
3178 |
|
3179 // MMBox description appears from 1.2 onwards - no use to check if we are |
|
3180 // 1.1 or later. |
|
3181 // Do we want to specify reply charging |
|
3182 if ( iMmsHeaders->ReplyCharging() == KMmsReplyChargingRequested || |
|
3183 iMmsHeaders->ReplyCharging() == KMmsReplyChargingRequestedTextOnly || |
|
3184 iMmsHeaders->ReplyCharging() == KMmsReplyChargingAccepted || |
|
3185 iMmsHeaders->ReplyCharging() == KMmsReplyChargingAcceptedTextOnly ) |
|
3186 { |
|
3187 // Reply charging value |
|
3188 EncodeOptionalByte( KMmsAssignedReplyCharging, |
|
3189 iMmsHeaders->ReplyCharging() ); |
|
3190 // Reply charging deadline |
|
3191 EncodeOptionalIntervalOrDate( KMmsAssignedReplyChargingDeadline, |
|
3192 iMmsHeaders->ReplyChargingInterval(), |
|
3193 iMmsHeaders->ReplyChargingDate() ); |
|
3194 // Reply charging size |
|
3195 EncodeReplyChargingSize( iMmsHeaders->ReplyChargingSize() ); |
|
3196 } |
|
3197 // Reply charging ID |
|
3198 EncodeOptionalString( KMmsAssignedReplyChargingID, |
|
3199 iMmsHeaders->ReplyChargingId() ); |
|
3200 |
|
3201 TInt i; |
|
3202 TUint oldPosition; |
|
3203 TUint length; |
|
3204 for ( i = 0; i < iMmsHeaders->PreviouslySentList().Count(); ++i ) |
|
3205 { |
|
3206 oldPosition = iPosition; |
|
3207 length = 0; |
|
3208 // Encode once just to find out field length |
|
3209 EncodeInteger( iMmsHeaders->PreviouslySentList()[i]->Order() ); |
|
3210 EncodeAddressL( iMmsHeaders->PreviouslySentList()[i]->Sender() ); |
|
3211 length += iPosition - oldPosition; |
|
3212 iPosition = oldPosition; |
|
3213 iEncodeBuffer->Write( iPosition, &KMmsAssignedPreviouslySentBy, 1 ); |
|
3214 iPosition++; |
|
3215 EncodeValueLength( length ); |
|
3216 // now we have added length, do the actual encoding |
|
3217 EncodeInteger( iMmsHeaders->PreviouslySentList()[i]->Order() ); |
|
3218 EncodeAddressL( iMmsHeaders->PreviouslySentList()[i]->Sender() ); |
|
3219 oldPosition = iPosition; |
|
3220 length = 0; |
|
3221 EncodeInteger( iMmsHeaders->PreviouslySentList()[i]->Order() ); |
|
3222 EncodeLongInteger( iMmsHeaders->PreviouslySentList()[i]->Date() ); |
|
3223 length += iPosition - oldPosition; |
|
3224 iPosition = oldPosition; |
|
3225 iEncodeBuffer->Write( iPosition, &KMmsAssignedPreviouslySentDate, 1 ); |
|
3226 iPosition++; |
|
3227 EncodeValueLength( length ); |
|
3228 EncodeInteger( iMmsHeaders->PreviouslySentList()[i]->Order() ); |
|
3229 EncodeLongInteger( iMmsHeaders->PreviouslySentList()[i]->Date() ); |
|
3230 } |
|
3231 |
|
3232 if ( iNumberOfAttachments > 0 ) |
|
3233 { |
|
3234 EncodeMultipartMixedHeaderL(); |
|
3235 } |
|
3236 |
|
3237 #endif |
|
3238 } |
|
3239 |
|
3240 // --------------------------------------------------------- |
|
3241 // 8-bit version (no conversions) |
|
3242 // --------------------------------------------------------- |
|
3243 // |
|
3244 void CMmsEncode::EncodeTextString( const TDesC8& aString ) |
|
3245 { |
|
3246 // Only Content-Id needs a quoted string, for example |
|
3247 // "<agjrfnjr> |
|
3248 // content-id encoding uses a separate function that adds the quote. |
|
3249 // EncodeQuotedTextString |
|
3250 |
|
3251 // Check if we need a Quote (This does not mean the quoted string.) |
|
3252 TInt length = aString.Length(); |
|
3253 if ( length > 0 && aString[0] >= KMms0x80 ) |
|
3254 { |
|
3255 iEncodeBuffer->Write( iPosition, &KMmsQuote, 1 ); |
|
3256 iPosition++; |
|
3257 } |
|
3258 |
|
3259 iEncodeBuffer->Write( iPosition, aString, length ); |
|
3260 iPosition += length; |
|
3261 |
|
3262 iEncodeBuffer->Write( iPosition, &KMmsNull, 1 ); |
|
3263 iPosition++; |
|
3264 |
|
3265 } |
|
3266 |
|
3267 // --------------------------------------------------------- |
|
3268 // 8-bit version (no conversions) |
|
3269 // --------------------------------------------------------- |
|
3270 // |
|
3271 void CMmsEncode::EncodeQuotedTextString( const TDesC8& aString ) |
|
3272 { |
|
3273 // Before this function is called, the caller must check |
|
3274 // that the length of the string is not 0. Otherwise this |
|
3275 // makes no sense. You cannot quote a zero-length string |
|
3276 |
|
3277 // We need quoted string for content-id. |
|
3278 // So far for nothing else. |
|
3279 // (for the filename in MIME headers, too, just in case) |
|
3280 |
|
3281 // We add one quote to the beginning, nothing to the end. |
|
3282 // As we start with a quote, we don't need to check for the special |
|
3283 // Quote that is needed if a string starts with a character above 128 |
|
3284 TInt length = aString.Length(); |
|
3285 iEncodeBuffer->Write( iPosition, &KMmsStringQuote, 1 ); |
|
3286 iPosition++; |
|
3287 |
|
3288 iEncodeBuffer->Write( iPosition, aString, length ); |
|
3289 iPosition += length; |
|
3290 |
|
3291 iEncodeBuffer->Write( iPosition, &KMmsNull, 1 ); |
|
3292 iPosition++; |
|
3293 |
|
3294 } |
|
3295 |
|
3296 // --------------------------------------------------------- |
|
3297 // unicode version |
|
3298 // --------------------------------------------------------- |
|
3299 // |
|
3300 void CMmsEncode::EncodeTextStringL( const TDesC& aString ) |
|
3301 { |
|
3302 |
|
3303 // What about a RFC2068 quoted strings - |
|
3304 // see explanation in EncodeTextString( const TDesC8& aString ) function |
|
3305 |
|
3306 TInt i = 0; |
|
3307 TInt length = aString.Length(); |
|
3308 |
|
3309 TBool safe = IsStringSafe( aString ); |
|
3310 |
|
3311 // If the string can be encoded as ASCII, go ahead |
|
3312 if ( safe ) |
|
3313 { |
|
3314 TUint8 character; |
|
3315 // No need to check if we need a quote - if we are safe, we have |
|
3316 // no characters >= 128. |
|
3317 |
|
3318 for ( i = 0; i < aString.Length(); ++i ) |
|
3319 { |
|
3320 character = TUint8( aString[i] & KMms0xFF ); |
|
3321 iEncodeBuffer->Write( iPosition, &character, 1 ); |
|
3322 iPosition++; |
|
3323 } |
|
3324 iEncodeBuffer->Write( iPosition, &KMmsNull, 1 ); |
|
3325 iPosition++; |
|
3326 } |
|
3327 else |
|
3328 { |
|
3329 // if our length is 0, we are safe, no need to check the |
|
3330 // length here anymore |
|
3331 // we must convert to utf-8 |
|
3332 |
|
3333 //one ucs-2 character should never produce more than 4 bytes when converted to utf-8 |
|
3334 HBufC8* buffer = HBufC8::NewL( aString.Length() * KMms4 ); // paranoid. |
|
3335 // we don't leave while we need buffer |
|
3336 TPtr8 buf8 = buffer->Des(); |
|
3337 |
|
3338 // if conversion fails, something is really seriously wrong |
|
3339 iError = CnvUtfConverter::ConvertFromUnicodeToUtf8( buf8, aString ); |
|
3340 |
|
3341 length = buf8.Length(); |
|
3342 // utf8 character set encoding needs one byte (fits into short integer) |
|
3343 length += KMms2; // add character set encoding byte and trailing NULL |
|
3344 |
|
3345 if ( buf8[0] >= KMms0x80 ) // 128 |
|
3346 { |
|
3347 length++; // we will need a quote byte at the start... |
|
3348 } |
|
3349 |
|
3350 EncodeValueLength( length ); |
|
3351 |
|
3352 // add one byte of character set |
|
3353 // this is a short integer, high bit must be set |
|
3354 TUint8 charset = KMmsUtf8 | KMms0x80; |
|
3355 |
|
3356 iEncodeBuffer->Write( iPosition, &charset, 1 ); |
|
3357 iPosition++; |
|
3358 |
|
3359 // Check if we need a quote |
|
3360 if ( buf8[0] >= KMms0x80 ) // 128 |
|
3361 { |
|
3362 iEncodeBuffer->Write( iPosition, &KMmsQuote, 1 ); |
|
3363 iPosition++; |
|
3364 } |
|
3365 |
|
3366 // Then write the string itself |
|
3367 iEncodeBuffer->Write( iPosition, buf8, buf8.Length() ); |
|
3368 iPosition += buf8.Length(); |
|
3369 |
|
3370 // Add terminating NULL |
|
3371 iEncodeBuffer->Write( iPosition, &KMmsNull, 1 ); |
|
3372 iPosition++; |
|
3373 |
|
3374 delete buffer; |
|
3375 buffer = NULL; |
|
3376 } |
|
3377 |
|
3378 } |
|
3379 |
|
3380 // --------------------------------------------------------- |
|
3381 // |
|
3382 // --------------------------------------------------------- |
|
3383 // |
|
3384 void CMmsEncode::EncodeDate( const TInt64& aDate) |
|
3385 { |
|
3386 |
|
3387 if ( aDate == 0 ) |
|
3388 { |
|
3389 return; |
|
3390 } |
|
3391 |
|
3392 iEncodeBuffer->Write( iPosition, &KMmsAssignedDate, 1 ); |
|
3393 iPosition++; |
|
3394 |
|
3395 EncodeLongInteger( aDate ); |
|
3396 |
|
3397 } |
|
3398 |
|
3399 // --------------------------------------------------------- |
|
3400 // |
|
3401 // --------------------------------------------------------- |
|
3402 // |
|
3403 void CMmsEncode::EncodeLongInteger( const TInt64& aLongInteger ) |
|
3404 { |
|
3405 |
|
3406 TUint8 length = 0; // number of bytes we will need |
|
3407 // The long integer will take 8 bytes or less |
|
3408 TUint8 array[KMms8]; |
|
3409 |
|
3410 TInt64 temp = aLongInteger; |
|
3411 TInt i = 0; |
|
3412 TInt64 reminder = 0; |
|
3413 |
|
3414 for ( i = 7; i >= 0; --i ) |
|
3415 { |
|
3416 reminder = temp % 0x100; |
|
3417 temp = temp / 0x100; |
|
3418 array[i] = TInt8 ( I64INT( reminder ) ) ; |
|
3419 } |
|
3420 |
|
3421 length = KMms8; |
|
3422 i = 0; |
|
3423 // The array has 8 elements, so this is safe. |
|
3424 while( ( i < KMms8 ) && ( array[i] == 0 ) ) |
|
3425 { |
|
3426 i++; |
|
3427 length--; |
|
3428 } |
|
3429 |
|
3430 // a zero should be coded as short integer. |
|
3431 // However, if there is a valid reason to code a zero as a long integer, |
|
3432 // we allow it. The caller should know what he is doing. |
|
3433 if ( length == 0 ) |
|
3434 { |
|
3435 length = 1; |
|
3436 } |
|
3437 |
|
3438 // write short length |
|
3439 iEncodeBuffer->Write( iPosition, &length, 1 ); |
|
3440 iPosition++; |
|
3441 |
|
3442 // write as many bytes as were non-zero |
|
3443 // array index will stay withing limits because of the way it was calculated |
|
3444 iEncodeBuffer->Write( iPosition, &(array[KMms8 - length] ), length ); |
|
3445 iPosition+= length; |
|
3446 |
|
3447 } |
|
3448 |
|
3449 // --------------------------------------------------------- |
|
3450 // |
|
3451 // --------------------------------------------------------- |
|
3452 // |
|
3453 void CMmsEncode::EncodeInteger( TUint aInteger ) |
|
3454 { |
|
3455 // KMms1 = 1 |
|
3456 // KMms2 = 2 |
|
3457 // KMms3 = 3 |
|
3458 // KMms4 = 4 |
|
3459 // KMms5 = 5 |
|
3460 // etc. |
|
3461 |
|
3462 TUint8 byte = 0; |
|
3463 |
|
3464 if ( aInteger <= KMmsShortIntegerLimit127 ) |
|
3465 { |
|
3466 byte = ( TInt8 ) aInteger; |
|
3467 byte |= KMms0x80; |
|
3468 iEncodeBuffer->Write( iPosition, &byte, 1); |
|
3469 iPosition++; |
|
3470 return; // this was easy |
|
3471 } |
|
3472 |
|
3473 TUint8 length = KMms4; // number of bytes we will need |
|
3474 TUint8 array[KMms4]; |
|
3475 |
|
3476 TUint temp = aInteger; |
|
3477 byte = TInt8( ( temp >> KMms24 ) & KMms0xFF ); |
|
3478 |
|
3479 while ( byte == 0 && length > 0 ) |
|
3480 { |
|
3481 length--; |
|
3482 temp = temp << KMms8; |
|
3483 byte = TInt8( ( temp >> KMms24 ) & KMms0xFF ); |
|
3484 } |
|
3485 |
|
3486 TUint i = 0; |
|
3487 for ( i = 0; i < length; ++i ) |
|
3488 { |
|
3489 array[i] = TInt8( ( temp >> ( KMms8 * ( KMms3 - i ) ) ) & KMms0xFF ); |
|
3490 } |
|
3491 |
|
3492 // write short length |
|
3493 iEncodeBuffer->Write( iPosition, &length, 1 ); |
|
3494 iPosition++; |
|
3495 |
|
3496 // write as many bytes as were non-zero |
|
3497 // aInteger was tested in the beginning - it needs at least one byte |
|
3498 // So length is at least 1 and the array has been properly initialized. |
|
3499 iEncodeBuffer->Write( iPosition, &array[0], length ); |
|
3500 iPosition+= length; |
|
3501 |
|
3502 } |
|
3503 |
|
3504 // --------------------------------------------------------- |
|
3505 // |
|
3506 // --------------------------------------------------------- |
|
3507 // |
|
3508 void CMmsEncode::EncodeSenderL( const TPtrC& aSender ) |
|
3509 { |
|
3510 |
|
3511 iEncodeBuffer->Write( iPosition, &KMmsAssignedFrom, 1 ); |
|
3512 iPosition++; |
|
3513 |
|
3514 // We must insert value length. |
|
3515 |
|
3516 if ( aSender.Length() == 0 ) |
|
3517 { |
|
3518 // The MMSC must insert our address |
|
3519 TUint8 length; |
|
3520 length = 1; |
|
3521 iEncodeBuffer->Write( iPosition, &length, 1 ); |
|
3522 iPosition++; |
|
3523 iEncodeBuffer->Write( iPosition, &KMmsInsertAddressToken, 1 ); |
|
3524 iPosition++; |
|
3525 return; |
|
3526 } |
|
3527 |
|
3528 // Now we must insert something |
|
3529 TUint length = 1; // address present token |
|
3530 |
|
3531 if ( aSender.Find( KMiuMau ) != KErrNotFound ) |
|
3532 { |
|
3533 TBool safe = IsStringSafe( aSender ); |
|
3534 if ( safe ) |
|
3535 { |
|
3536 // this was easy, just ASCII, no conversion |
|
3537 length += aSender.Length(); |
|
3538 length ++; // room for terminating zero |
|
3539 } |
|
3540 else // not USASCII, charset must be specified |
|
3541 { |
|
3542 // worst case scenario. |
|
3543 // must be encoded as UTF-8, value length and character set |
|
3544 // must be added |
|
3545 |
|
3546 // one ucs-2 character will not produce more than 4 bytes when converted to utf-8 |
|
3547 HBufC8* buffer = HBufC8::NewL( aSender.Length() * KMms4 ); // paranoid. |
|
3548 // we don't need to push buffer onto cleanup stack, as we don't |
|
3549 // leave while we are using it |
|
3550 TPtr8 buf8 = buffer->Des(); |
|
3551 |
|
3552 // if we get error here, something is badly wrong |
|
3553 iError = CnvUtfConverter::ConvertFromUnicodeToUtf8( buf8, aSender ); |
|
3554 |
|
3555 length += buf8.Length(); |
|
3556 // utf8 character set encoding needs one byte (short integer) |
|
3557 length += KMms2; // add character set encoding byte and trailing NULL |
|
3558 |
|
3559 if ( buf8[0] >= KMms0x80 ) // 128 |
|
3560 { |
|
3561 length++; // we will need a quote byte at the start... |
|
3562 } |
|
3563 delete buffer; |
|
3564 buffer = NULL; |
|
3565 } |
|
3566 } |
|
3567 else // no miumau found |
|
3568 { |
|
3569 // phone number, must be ASCII |
|
3570 length += aSender.Length(); |
|
3571 length ++; // room for terminating zero |
|
3572 length += KMmsPlmnLength; // type indication |
|
3573 // this should be the length, if we have a phone number (no alias.) |
|
3574 } |
|
3575 |
|
3576 EncodeValueLength( length ); |
|
3577 |
|
3578 iEncodeBuffer->Write( iPosition, &KMmsAddressPresentToken, 1 ); |
|
3579 iPosition++; |
|
3580 |
|
3581 // If the address contains some non-ascii characters, |
|
3582 // it must be converted to utf-8 |
|
3583 |
|
3584 EncodeAddressL( aSender ); |
|
3585 |
|
3586 } |
|
3587 |
|
3588 // --------------------------------------------------------- |
|
3589 // |
|
3590 // --------------------------------------------------------- |
|
3591 // |
|
3592 void CMmsEncode::EncodeAddressL( const TPtrC& aAddress ) |
|
3593 { |
|
3594 // Supports only address types PLMN and email. |
|
3595 // If the address string contains a @ character, |
|
3596 // it is interpreted as an email |
|
3597 |
|
3598 // Internal alias is removed |
|
3599 |
|
3600 TMmsAddressType addressType = EMmsAddressTypeUnknown; |
|
3601 HBufC* realAddress = HBufC::NewL( aAddress.Length() ); |
|
3602 CleanupStack::PushL( realAddress ); |
|
3603 |
|
3604 TInt error = KErrNone; |
|
3605 |
|
3606 TPtr realAddressPointer = realAddress->Des(); |
|
3607 error = TMmsGenUtils::AddressTypeAndRealAddress( |
|
3608 aAddress, |
|
3609 addressType, |
|
3610 realAddressPointer, |
|
3611 aAddress.Length()); |
|
3612 |
|
3613 if ( error != KErrNone || addressType == EMmsAddressTypeUnknown ) |
|
3614 { |
|
3615 // could not resolve. Send unchanged |
|
3616 realAddress->Des().Copy( aAddress ); |
|
3617 if ( aAddress.Find( KMiuMau ) != KErrNotFound ) |
|
3618 { |
|
3619 addressType = EMmsAddressTypeEmail; |
|
3620 } |
|
3621 else |
|
3622 { |
|
3623 addressType = EMmsAddressTypeMobile; |
|
3624 } |
|
3625 } |
|
3626 |
|
3627 if ( addressType == EMmsAddressTypeEmail ) |
|
3628 { |
|
3629 // email address |
|
3630 // If the address contains only ASCII characters, |
|
3631 // it can be sent as text string, if not, it must be sent as utf-8 |
|
3632 |
|
3633 EncodeTextStringL( *realAddress ); |
|
3634 |
|
3635 } |
|
3636 else |
|
3637 { |
|
3638 // must be a phone number |
|
3639 // We expect for now that the format is correct as is |
|
3640 // All legal characters present in a phone number are ASCII |
|
3641 |
|
3642 TInt i = 0; |
|
3643 TUint8 character = 0; |
|
3644 realAddressPointer = realAddress->Des(); |
|
3645 for ( i = 0; i < realAddress->Length(); ++i ) |
|
3646 { |
|
3647 // The array index is safe because i is always < realAddress->Length(). |
|
3648 character = TUint8( realAddressPointer[i] & KMms0xFF ); |
|
3649 iEncodeBuffer->Write( iPosition, &character, 1 ); |
|
3650 iPosition++; |
|
3651 } |
|
3652 iEncodeBuffer->Write( iPosition, KMmsPlmn, KMmsPlmnLength ); |
|
3653 iPosition += KMmsPlmnLength; |
|
3654 iEncodeBuffer->Write( iPosition, &KMmsNull, 1 ); |
|
3655 iPosition++; |
|
3656 } |
|
3657 CleanupStack::PopAndDestroy( realAddress ); |
|
3658 |
|
3659 } |
|
3660 |
|
3661 // --------------------------------------------------------- |
|
3662 // |
|
3663 // --------------------------------------------------------- |
|
3664 // |
|
3665 void CMmsEncode::EncodeValueLength( TUint aLength ) |
|
3666 { |
|
3667 |
|
3668 TUint8 shortLength = 0; |
|
3669 |
|
3670 if ( aLength <= KMms30 ) |
|
3671 { |
|
3672 // short length |
|
3673 shortLength = TUint8( aLength ) ; |
|
3674 iEncodeBuffer->Write( iPosition, &shortLength, 1 ); |
|
3675 iPosition++; |
|
3676 } |
|
3677 else |
|
3678 { |
|
3679 iEncodeBuffer->Write( iPosition, &KMmsLengthQuote, 1 ); |
|
3680 iPosition++; |
|
3681 EncodeUintvar( aLength ); |
|
3682 } |
|
3683 |
|
3684 } |
|
3685 |
|
3686 // --------------------------------------------------------- |
|
3687 // |
|
3688 // --------------------------------------------------------- |
|
3689 // |
|
3690 void CMmsEncode::EncodeUintvar( TUint aInteger ) |
|
3691 { |
|
3692 |
|
3693 // The value is split into 7 bit chunks, and continue bit set |
|
3694 // when needed. |
|
3695 |
|
3696 // No more than 5 bytes will be produced |
|
3697 TUint8 buffer[KMms5]; |
|
3698 TUint temp = aInteger; |
|
3699 TInt i; |
|
3700 |
|
3701 for ( i = 0; i < KMms5; ++i ) |
|
3702 { |
|
3703 buffer[KMms4 - i] = TUint8( temp & KMms0x7F ); |
|
3704 temp >>= KMms7; |
|
3705 } |
|
3706 |
|
3707 i = 0; |
|
3708 // buffer indexes are safe because the buffer has been defined long enough. |
|
3709 while ( i < KMms4 && buffer[i] == 0 ) |
|
3710 { |
|
3711 i++; |
|
3712 } |
|
3713 |
|
3714 TInt j; |
|
3715 |
|
3716 for ( j = i; j < KMms4; ++j ) |
|
3717 { |
|
3718 // buffer indexes are safe because the buffer has been defined long enough. |
|
3719 buffer[j] |= KMms0x80; // set Continue bit, but never to last |
|
3720 } |
|
3721 |
|
3722 // buffer indexes are safe because the buffer has been defined long enough. |
|
3723 iEncodeBuffer->Write( iPosition, &buffer[i], KMms5 - i ); |
|
3724 iPosition += KMms5 - i; |
|
3725 |
|
3726 } |
|
3727 |
|
3728 // --------------------------------------------------------- |
|
3729 // |
|
3730 // --------------------------------------------------------- |
|
3731 // |
|
3732 TInt CMmsEncode::GetUintvarLength( TUint aInteger ) |
|
3733 { |
|
3734 |
|
3735 // The value is split into 7 bit chunks, and continue bit set |
|
3736 // when needed. |
|
3737 |
|
3738 // No more than 5 bytes will be produced |
|
3739 TUint8 buffer[KMms5]; |
|
3740 TUint temp = aInteger; |
|
3741 TInt i; |
|
3742 |
|
3743 for (i = 0; i < KMms5; ++i ) |
|
3744 { |
|
3745 buffer[KMms4 - i] = TUint8( temp & KMms0x7F ); |
|
3746 temp >>= KMms7; |
|
3747 } |
|
3748 |
|
3749 i = 0; |
|
3750 // buffer indexes are safe because the buffer has been defined long enough. |
|
3751 while ( i < KMms4 && buffer[i] == 0 ) |
|
3752 { |
|
3753 i++; |
|
3754 } |
|
3755 |
|
3756 return KMms5 - i; |
|
3757 |
|
3758 } |
|
3759 |
|
3760 // --------------------------------------------------------- |
|
3761 // |
|
3762 // --------------------------------------------------------- |
|
3763 // |
|
3764 void CMmsEncode::EncodeRecipientL( const CDesCArray& aRecipientList, |
|
3765 TMmsRecipients aType ) |
|
3766 { |
|
3767 |
|
3768 TInt i; |
|
3769 TInt size = aRecipientList.Count(); |
|
3770 if ( size == 0 ) |
|
3771 { |
|
3772 return; |
|
3773 } |
|
3774 |
|
3775 TUint8 recipientType = KMmsAssignedTo; |
|
3776 |
|
3777 switch ( aType ) |
|
3778 { |
|
3779 case EMmsTo: |
|
3780 recipientType = KMmsAssignedTo; |
|
3781 break; |
|
3782 case EMmsCc: |
|
3783 recipientType = KMmsAssignedCc; |
|
3784 break; |
|
3785 case EMmsBcc: |
|
3786 recipientType = KMmsAssignedBcc; |
|
3787 break; |
|
3788 default: |
|
3789 break; |
|
3790 } |
|
3791 |
|
3792 for ( i = 0; i < size; ++i ) |
|
3793 { |
|
3794 // check for fakes |
|
3795 if ( aRecipientList[i].Length() > 0 ) |
|
3796 { |
|
3797 iEncodeBuffer->Write( iPosition, &recipientType, 1 ); |
|
3798 iPosition++; |
|
3799 |
|
3800 EncodeAddressL( aRecipientList[i] ); |
|
3801 } |
|
3802 |
|
3803 } |
|
3804 |
|
3805 } |
|
3806 |
|
3807 // --------------------------------------------------------- |
|
3808 // |
|
3809 // --------------------------------------------------------- |
|
3810 // |
|
3811 void CMmsEncode::EncodeOptionalStringL( TUint8 aHeader, |
|
3812 const TPtrC16& aString ) |
|
3813 { |
|
3814 |
|
3815 if ( aString.Length() == 0 ) |
|
3816 { |
|
3817 return; |
|
3818 } |
|
3819 |
|
3820 iEncodeBuffer->Write( iPosition, &aHeader, 1 ); |
|
3821 iPosition++; |
|
3822 |
|
3823 EncodeTextStringL( aString ); |
|
3824 |
|
3825 } |
|
3826 |
|
3827 // --------------------------------------------------------- |
|
3828 // |
|
3829 // --------------------------------------------------------- |
|
3830 // |
|
3831 void CMmsEncode::EncodeOptionalString( TUint8 aHeader, const TPtrC8& aString ) |
|
3832 { |
|
3833 |
|
3834 if ( aString.Length() == 0 ) |
|
3835 { |
|
3836 return; |
|
3837 } |
|
3838 |
|
3839 EncodeHeaderAndTextString( aHeader, aString ); |
|
3840 |
|
3841 } |
|
3842 |
|
3843 // --------------------------------------------------------- |
|
3844 // |
|
3845 // --------------------------------------------------------- |
|
3846 // |
|
3847 void CMmsEncode::EncodeIntervalOrDate( TInt aInterval, const TInt64& aDate ) |
|
3848 { |
|
3849 |
|
3850 TInt64 temp = 0; |
|
3851 TUint8 token = 0; |
|
3852 |
|
3853 if ( aDate != 0 ) |
|
3854 { |
|
3855 temp = aDate; |
|
3856 token = KMmsAbsoluteToken; |
|
3857 } |
|
3858 else |
|
3859 { |
|
3860 temp = aInterval; |
|
3861 token = KMmsRelativeToken; |
|
3862 } |
|
3863 |
|
3864 // calculate value length |
|
3865 |
|
3866 TUint length = KMms8; |
|
3867 TUint mask = 0xff000000; |
|
3868 |
|
3869 while ( ( I64HIGH( temp ) & mask ) == 0 && length > KMms4) |
|
3870 { |
|
3871 mask >>= KMms8; |
|
3872 length--; |
|
3873 } |
|
3874 |
|
3875 mask = 0xff000000; |
|
3876 |
|
3877 // Test if the whole high half was zero |
|
3878 if ( I64HIGH( temp ) == 0 ) |
|
3879 { |
|
3880 while ( ( I64LOW( temp ) & mask ) == 0 && length > 1) |
|
3881 { |
|
3882 mask >>= KMms8; |
|
3883 length--; |
|
3884 } |
|
3885 } |
|
3886 |
|
3887 // now add short length and absolute/relative token |
|
3888 |
|
3889 length += KMms2; |
|
3890 |
|
3891 EncodeValueLength( length ); |
|
3892 |
|
3893 iEncodeBuffer->Write( iPosition, &token, 1 ); |
|
3894 iPosition++; |
|
3895 |
|
3896 EncodeLongInteger( temp ); |
|
3897 |
|
3898 } |
|
3899 |
|
3900 // --------------------------------------------------------- |
|
3901 // |
|
3902 // --------------------------------------------------------- |
|
3903 // |
|
3904 void CMmsEncode::EncodeReplyChargingSize( TInt aReplyChargingSize ) |
|
3905 { |
|
3906 if ( aReplyChargingSize == 0 ) |
|
3907 { |
|
3908 return; |
|
3909 } |
|
3910 TInt64 size = aReplyChargingSize; |
|
3911 iEncodeBuffer->Write( iPosition, &KMmsAssignedReplyChargingSize, 1 ); |
|
3912 iPosition++; |
|
3913 |
|
3914 EncodeLongInteger( size ); |
|
3915 } |
|
3916 |
|
3917 // --------------------------------------------------------- |
|
3918 // |
|
3919 // --------------------------------------------------------- |
|
3920 // |
|
3921 void CMmsEncode::EncodeOptionalByte( TUint8 aHeader, TInt aValue ) |
|
3922 { |
|
3923 if ( aValue == 0 ) |
|
3924 { |
|
3925 return; // not set, nothing to encode, header is optional |
|
3926 } |
|
3927 EncodeMandatoryByte( aHeader, aValue ); |
|
3928 |
|
3929 } |
|
3930 |
|
3931 // --------------------------------------------------------- |
|
3932 // |
|
3933 // --------------------------------------------------------- |
|
3934 // |
|
3935 void CMmsEncode::EncodeMandatoryByte( TUint8 aHeader, TInt aValue ) |
|
3936 { |
|
3937 // When ecoding mandatory byte even value 0 is allowed. |
|
3938 // It will become 0x80, and be correctly decoded back to 0. |
|
3939 TUint8 value = TUint8 ( aValue ) | KMms0x80 ; |
|
3940 |
|
3941 iEncodeBuffer->Write( iPosition, &aHeader, 1 ); |
|
3942 iPosition++; |
|
3943 |
|
3944 iEncodeBuffer->Write( iPosition, &value, 1 ); |
|
3945 iPosition++; |
|
3946 } |
|
3947 |
|
3948 |
|
3949 // --------------------------------------------------------- |
|
3950 // |
|
3951 // --------------------------------------------------------- |
|
3952 // |
|
3953 void CMmsEncode::EncodeOptionalIntervalOrDate( TUint8 aHeader, |
|
3954 TInt aInterval, |
|
3955 const TInt64& aDate ) |
|
3956 { |
|
3957 if ( aInterval == 0 && aDate == 0 ) |
|
3958 { |
|
3959 return; // not set, nothing to encode, header is optional |
|
3960 } |
|
3961 |
|
3962 iEncodeBuffer->Write( iPosition, &aHeader, 1 ); |
|
3963 iPosition++; |
|
3964 |
|
3965 EncodeIntervalOrDate( aInterval, aDate ); |
|
3966 } |
|
3967 |
|
3968 // --------------------------------------------------------- |
|
3969 // |
|
3970 // --------------------------------------------------------- |
|
3971 // |
|
3972 void CMmsEncode::EncodeHeaderAndTextString( TUint8 aHeader, |
|
3973 const TDesC8& aString ) |
|
3974 { |
|
3975 |
|
3976 iEncodeBuffer->Write( iPosition, &aHeader, 1 ); |
|
3977 iPosition++; |
|
3978 |
|
3979 EncodeTextString( aString ); |
|
3980 |
|
3981 } |
|
3982 |
|
3983 |
|
3984 // --------------------------------------------------------- |
|
3985 // |
|
3986 // --------------------------------------------------------- |
|
3987 // |
|
3988 TBool CMmsEncode::IsStringSafe( const TDesC& aString ) |
|
3989 { |
|
3990 |
|
3991 // Very simple check to see if string is "safe" ASCII |
|
3992 // Used for headers, which are short strings |
|
3993 |
|
3994 TInt i; |
|
3995 TBool safe = ETrue; |
|
3996 |
|
3997 for ( i = 0; i < aString.Length() && safe; ++i ) |
|
3998 { |
|
3999 if ( aString[i] < KMmsLowestAscii || aString[i] >= KMmsHighestAscii ) |
|
4000 { |
|
4001 safe = EFalse; |
|
4002 } |
|
4003 } |
|
4004 return safe; |
|
4005 |
|
4006 } |
|
4007 |
|
4008 // --------------------------------------------------------- |
|
4009 // |
|
4010 // --------------------------------------------------------- |
|
4011 // |
|
4012 TBool CMmsEncode::IsStringSafe( const TDesC8& aString, TInt& aNumNonSafe ) |
|
4013 { |
|
4014 |
|
4015 // Very simple check to see if string is "safe" ASCII |
|
4016 // Used for headers, which are short strings |
|
4017 // spaces count as non-safe because their number must be taken into |
|
4018 // account when calculating the length |
|
4019 |
|
4020 const TInt KIntQuestion = 0x3F; |
|
4021 const TInt KIntEquals = 0x3D; |
|
4022 |
|
4023 TInt i; |
|
4024 aNumNonSafe = 0; |
|
4025 TBool safe = ETrue; |
|
4026 |
|
4027 for ( i = 0; i < aString.Length()/* && safe*/; ++i ) |
|
4028 { |
|
4029 if ( aString[i] < KMmsLowestAscii || aString[i] >= KMmsHighestAscii ) |
|
4030 { |
|
4031 safe = EFalse; |
|
4032 aNumNonSafe++; |
|
4033 } |
|
4034 if ( aString[i] == KIntQuestion || aString[i] == KIntEquals ) |
|
4035 { |
|
4036 // These are safe but must be encoded if quoted printable |
|
4037 // encoding is used. The number is needed to check the header length |
|
4038 aNumNonSafe++; |
|
4039 } |
|
4040 if ( aString[i] == KMmsIntUnderscore ) |
|
4041 { |
|
4042 // This must always be encoded as base64 because Symbian |
|
4043 // does not encode underscores when quoted printable is used. |
|
4044 aNumNonSafe = KMaxEncodingLength; |
|
4045 } |
|
4046 |
|
4047 } |
|
4048 return safe; |
|
4049 |
|
4050 } |
|
4051 |
|
4052 // --------------------------------------------------------- |
|
4053 // |
|
4054 // --------------------------------------------------------- |
|
4055 // |
|
4056 void CMmsEncode::EncodeMultipartRelatedHeaderL( const TMsvAttachmentId aRootId ) |
|
4057 { |
|
4058 |
|
4059 iEncodeBuffer->Write( iPosition, &KMmsAssignedContentType, 1 ); |
|
4060 iPosition++; |
|
4061 |
|
4062 // We have parameters (start), so we must use Content-general-form |
|
4063 |
|
4064 // We need the content-id for the root part. If it is not defined already, |
|
4065 // we must generate one. |
|
4066 |
|
4067 TUint headerLength = 1; // one byte for well known media |
|
4068 TInt cleanupCount = 0; // we must keep track what we have on store |
|
4069 |
|
4070 User::LeaveIfError( iEntryWrapper->SetCurrentEntry( iCurrentMessageId ) ); |
|
4071 |
|
4072 CMsvStore* store = iEntryWrapper->EditStoreL(); |
|
4073 CleanupStack::PushL( store ); cleanupCount++; |
|
4074 MMsvAttachmentManager& attachMan = store->AttachmentManagerL(); |
|
4075 CMsvAttachment* attachmentInfo = NULL; |
|
4076 attachmentInfo = attachMan.GetAttachmentInfoL( (TMsvAttachmentId) aRootId ); |
|
4077 CleanupStack::PushL( attachmentInfo ); cleanupCount++; |
|
4078 |
|
4079 iMimeHeaders->RestoreL( *attachmentInfo ); |
|
4080 |
|
4081 if ( iError != KErrNone ) |
|
4082 { |
|
4083 CleanupStack::PopAndDestroy( cleanupCount ); |
|
4084 return; |
|
4085 } |
|
4086 |
|
4087 TPtrC8 cid = iMimeHeaders->ContentId(); |
|
4088 TBufC8<KMmsMaxCidLength> target; |
|
4089 |
|
4090 // If cid has not been defined, we must generate one |
|
4091 if ( cid.Length() == 0 ) |
|
4092 { |
|
4093 TTime now; |
|
4094 now.UniversalTime(); |
|
4095 TInt random; |
|
4096 TInt64 seed = now.Int64(); |
|
4097 random = Math::Rand( seed ); |
|
4098 // type conversions irrelevant - just creating a magic number for content id |
|
4099 target.Des().Num( random ); |
|
4100 target.Des().Insert(0, KMmsLeftAngle ); |
|
4101 target.Des().Append( KMmsRightAngle ); |
|
4102 cid.Set( target.Des() ); |
|
4103 // exclude the angle brackets |
|
4104 iMimeHeaders->SetContentIdL( cid.Mid( 1, cid.Length() - KMms2 ) ); |
|
4105 // save the cid to be present when we create the attachment headers |
|
4106 // If this does not succeed, the message will have no root. |
|
4107 MMsvAttachmentManagerSync& attachManSync = |
|
4108 store->AttachmentManagerExtensionsL(); |
|
4109 iMimeHeaders->StoreL( *attachmentInfo ); |
|
4110 attachManSync.ModifyAttachmentInfoL( attachmentInfo ); |
|
4111 // attachment manager now own attachemnt info |
|
4112 CleanupStack::Pop( attachmentInfo ); cleanupCount--; |
|
4113 store->CommitL(); |
|
4114 attachmentInfo = attachMan.GetAttachmentInfoL( (TMsvAttachmentId) aRootId ); |
|
4115 CleanupStack::PushL( attachmentInfo ); cleanupCount++; |
|
4116 } |
|
4117 |
|
4118 // add start header length & |
|
4119 // assigned number for start parameter, and terminating zero for cid |
|
4120 headerLength += cid.Length() + KMms2; |
|
4121 if ( cid.Find( KMmsLeftAngle ) != 0 ) |
|
4122 { |
|
4123 headerLength += KMms2; // we must add angle bracket |
|
4124 } |
|
4125 |
|
4126 // Then the length of the content-type header... |
|
4127 TPtrC8 contentTypeString = iMimeHeaders->ContentType(); |
|
4128 |
|
4129 HBufC8* tempContentType = HBufC8::NewL( iMimeHeaders->ContentType().Length() + |
|
4130 iMimeHeaders->ContentSubType().Length() + 1 ); |
|
4131 CleanupStack::PushL( tempContentType ); |
|
4132 tempContentType->Des().Copy( iMimeHeaders->ContentType() ); |
|
4133 if ( ( iMimeHeaders->ContentType().Find( KMmsSlash8 ) != |
|
4134 ( iMimeHeaders->ContentType().Length() - 1 ) ) && |
|
4135 ( iMimeHeaders->ContentSubType().Find( KMmsSlash8 ) != 0 ) && |
|
4136 ( iMimeHeaders->ContentSubType().Length() != 0 ) ) |
|
4137 { |
|
4138 tempContentType->Des().Append( KMmsSlash8 ); |
|
4139 } |
|
4140 tempContentType->Des().Append( iMimeHeaders->ContentSubType() ); |
|
4141 attachmentInfo->SetMimeTypeL( tempContentType->Des() ); |
|
4142 CleanupStack::PopAndDestroy( tempContentType ); |
|
4143 contentTypeString.Set( attachmentInfo->MimeType() ); |
|
4144 |
|
4145 if ( contentTypeString.Length() == 0 ) |
|
4146 { |
|
4147 // We need a content type... |
|
4148 // If we don't know, we say "Any" |
|
4149 contentTypeString.Set( KMmsAny ); |
|
4150 } |
|
4151 // Check if we have well-known media. |
|
4152 TInt8 rootContentType = -1; |
|
4153 |
|
4154 TInt8 i = 0; |
|
4155 for ( i = 0; i < KNumberContentTypes && rootContentType < 0; ++i ) |
|
4156 { |
|
4157 if ( contentTypeString.CompareF( TPtrC8( KContentTypeTable[i] ) ) == 0 ) |
|
4158 { |
|
4159 rootContentType = i; |
|
4160 } |
|
4161 } |
|
4162 |
|
4163 // start parameter assignment |
|
4164 headerLength += 1; |
|
4165 if ( rootContentType != -1 ) |
|
4166 { |
|
4167 // well known content type |
|
4168 headerLength += 1; |
|
4169 } |
|
4170 else |
|
4171 { |
|
4172 // string + terminating zero |
|
4173 headerLength += contentTypeString.Length() + 1; |
|
4174 } |
|
4175 |
|
4176 TPtrC8 appIdPtr; |
|
4177 appIdPtr.Set( KMmsJavaApplicationId ); |
|
4178 // Java application id parameters added to content-type |
|
4179 if ( iMmsHeaders->ApplicId().Length() > 0 ) |
|
4180 { |
|
4181 headerLength += appIdPtr.Length() + 1 ; |
|
4182 headerLength += iMmsHeaders->ApplicId().Length() + 1; |
|
4183 } |
|
4184 appIdPtr.Set( KMmsJavaReplyApplicationId ); |
|
4185 if ( iMmsHeaders->ReplyApplicId().Length() > 0 ) |
|
4186 { |
|
4187 headerLength += appIdPtr.Length() + 1 ; |
|
4188 headerLength += iMmsHeaders->ReplyApplicId().Length() + 1; |
|
4189 } |
|
4190 |
|
4191 // write general encoding length |
|
4192 EncodeValueLength( headerLength ); |
|
4193 |
|
4194 // Then the Media Type with parameters |
|
4195 |
|
4196 // We are multipart/related, which is a well-known media |
|
4197 // encode as short integer |
|
4198 TUint8 byte = KMmsAssignedApplicationVndWapMultipartRelated | KMms0x80; |
|
4199 iEncodeBuffer->Write( iPosition, &byte, 1 ); |
|
4200 iPosition++; |
|
4201 |
|
4202 // Then the start parameter and cid text string |
|
4203 byte = KWspStart | KMms0x80; |
|
4204 |
|
4205 if ( cid.Length() > 0 ) |
|
4206 { |
|
4207 HBufC8* tempContentId = HBufC8::NewL( iMimeHeaders->ContentId().Length() + KMms2 ); |
|
4208 CleanupStack::PushL( tempContentId ); |
|
4209 if ( cid.Find( KMmsLeftAngle ) != 0 ) |
|
4210 { |
|
4211 tempContentId->Des().Copy( KMmsLeftAngle ); |
|
4212 tempContentId->Des().Append( cid ); |
|
4213 tempContentId->Des().Append( KMmsRightAngle ); |
|
4214 } |
|
4215 else |
|
4216 { |
|
4217 tempContentId->Des().Copy( cid ); |
|
4218 } |
|
4219 EncodeHeaderAndTextString( byte, tempContentId->Des() ); |
|
4220 CleanupStack::PopAndDestroy( tempContentId ); |
|
4221 } |
|
4222 |
|
4223 |
|
4224 // next the content type of the root part |
|
4225 byte = KWspRelatedType | KMms0x80; |
|
4226 // and the actual type either as a well-known media type |
|
4227 // or a text string. |
|
4228 |
|
4229 if ( rootContentType != -1 ) |
|
4230 { |
|
4231 // Well known content type. |
|
4232 // EncodeMandatoryByte will set the high bit |
|
4233 EncodeMandatoryByte( byte, rootContentType ); |
|
4234 } |
|
4235 else |
|
4236 { |
|
4237 // string + terminating zero |
|
4238 EncodeHeaderAndTextString( byte, contentTypeString ); |
|
4239 } |
|
4240 |
|
4241 if ( iMmsHeaders->ApplicId().Length() > 0 || |
|
4242 iMmsHeaders->ReplyApplicId().Length() > 0 ) |
|
4243 { |
|
4244 EncodeApplicationIdParametersL(); |
|
4245 } |
|
4246 |
|
4247 // encode number of parts |
|
4248 EncodeUintvar( iNumberOfAttachments ); |
|
4249 |
|
4250 // get rid of stuff we put on stack |
|
4251 CleanupStack::PopAndDestroy( cleanupCount ); |
|
4252 } |
|
4253 |
|
4254 // --------------------------------------------------------- |
|
4255 // |
|
4256 // --------------------------------------------------------- |
|
4257 // |
|
4258 void CMmsEncode::EncodeMultipartMixedHeaderL() |
|
4259 { |
|
4260 |
|
4261 // If Java has added application id or reply-to application id, |
|
4262 // even multipart/mxed type needs parameters. |
|
4263 |
|
4264 TUint headerLength = 0; // assume no parameters |
|
4265 |
|
4266 if ( iMmsHeaders->ApplicId().Length() > 0 || |
|
4267 iMmsHeaders->ReplyApplicId().Length() > 0 ) |
|
4268 { |
|
4269 headerLength = 1; // one byte for well known media |
|
4270 TPtrC8 appIdPtr; |
|
4271 appIdPtr.Set( KMmsJavaApplicationId ); |
|
4272 if ( iMmsHeaders->ApplicId().Length() > 0 ) |
|
4273 { |
|
4274 headerLength += appIdPtr.Length() + 1 ; |
|
4275 headerLength += iMmsHeaders->ApplicId().Length() + 1; |
|
4276 } |
|
4277 appIdPtr.Set( KMmsJavaReplyApplicationId ); |
|
4278 if ( iMmsHeaders->ReplyApplicId().Length() > 0 ) |
|
4279 { |
|
4280 headerLength += appIdPtr.Length() + 1 ; |
|
4281 headerLength += iMmsHeaders->ReplyApplicId().Length() + 1; |
|
4282 } |
|
4283 } |
|
4284 |
|
4285 iEncodeBuffer->Write( iPosition, &KMmsAssignedContentType, 1 ); |
|
4286 iPosition++; |
|
4287 |
|
4288 if ( headerLength > 0 ) |
|
4289 { |
|
4290 // write general encoding length |
|
4291 EncodeValueLength( headerLength ); |
|
4292 } |
|
4293 |
|
4294 // encode as short integer |
|
4295 TUint8 contentType = KMmsAssignedApplicationVndWapMultipartMixed | KMms0x80; |
|
4296 iEncodeBuffer->Write( iPosition, &contentType, 1 ); |
|
4297 iPosition++; |
|
4298 |
|
4299 if ( iMmsHeaders->ApplicId().Length() > 0 || |
|
4300 iMmsHeaders->ReplyApplicId().Length() > 0 ) |
|
4301 { |
|
4302 EncodeApplicationIdParametersL(); |
|
4303 } |
|
4304 |
|
4305 // No more parameters for multipart/mixed, actual parts follow |
|
4306 |
|
4307 // encode number of parts |
|
4308 EncodeUintvar( iNumberOfAttachments ); |
|
4309 |
|
4310 } |
|
4311 |
|
4312 // --------------------------------------------------------- |
|
4313 // |
|
4314 // --------------------------------------------------------- |
|
4315 // |
|
4316 void CMmsEncode::EncodeKeywordArrayL() |
|
4317 { |
|
4318 TInt i = 0; |
|
4319 TInt length = 0; |
|
4320 |
|
4321 // caller must check that iMmsHeaders->ReadOnlyMMBoxMessageHeaders() is not NULL |
|
4322 CMmsMMBoxMessageHeaders& temp = iMmsHeaders->MMBoxMessageHeadersL(); |
|
4323 for ( i = 0; i < temp.KeywordArray().Count(); ++i ) |
|
4324 { |
|
4325 length = temp.KeywordArray()[i]->Keyword().Length(); |
|
4326 if ( length > 0 ) |
|
4327 { |
|
4328 iEncodeBuffer->Write( iPosition, &KMmsAssignedMMFlags, 1 ); |
|
4329 iPosition++; |
|
4330 // do some fake encoding to get the text length |
|
4331 TUint oldPosition = iPosition; // we will return here |
|
4332 EncodeTextStringL( temp.KeywordArray()[i]->Keyword() ); |
|
4333 length = iPosition - oldPosition; |
|
4334 iPosition = oldPosition; // return to original place |
|
4335 length += 1; // token must come before string |
|
4336 EncodeValueLength( length ); |
|
4337 TUint8 token = (TUint8) temp.KeywordArray()[i]->Token(); |
|
4338 if ( iMmsHeaders->MessageType() == KMmsMessageTypeMboxViewReq || |
|
4339 iMmsHeaders->MessageType() == KMmsMessageTypeMboxViewConf || |
|
4340 iMmsHeaders->MessageType() == KMmsMessageTypeMBoxDescr ) |
|
4341 { |
|
4342 // the token must always be filter for MMbox PDUs |
|
4343 token = KMmsFilterToken; |
|
4344 } |
|
4345 iEncodeBuffer->Write( iPosition, &token, 1 ); |
|
4346 iPosition++; |
|
4347 EncodeTextStringL( temp.KeywordArray()[i]->Keyword() ); |
|
4348 } |
|
4349 } |
|
4350 } |
|
4351 |
|
4352 // --------------------------------------------------------- |
|
4353 // |
|
4354 // --------------------------------------------------------- |
|
4355 // |
|
4356 void CMmsEncode::EncodeOptionalInteger( TUint8 aHeader, TUint aValue ) |
|
4357 { |
|
4358 if ( aValue == 0 ) |
|
4359 { |
|
4360 return; // not set, nothing to encode, header is optional |
|
4361 } |
|
4362 |
|
4363 iEncodeBuffer->Write( iPosition, &aHeader, 1 ); |
|
4364 iPosition++; |
|
4365 |
|
4366 EncodeInteger( aValue ); |
|
4367 |
|
4368 } |
|
4369 |
|
4370 // --------------------------------------------------------- |
|
4371 // |
|
4372 // --------------------------------------------------------- |
|
4373 // |
|
4374 void CMmsEncode::EncodeAttributes( RArray<TUint>& aAttributeArray ) |
|
4375 { |
|
4376 TInt i; |
|
4377 |
|
4378 for ( i = 0; i < aAttributeArray.Count(); ++i ) |
|
4379 { |
|
4380 EncodeMandatoryByte( KMmsAssignedAttributes, aAttributeArray[i] ); |
|
4381 } |
|
4382 } |
|
4383 |
|
4384 // --------------------------------------------------------- |
|
4385 // |
|
4386 // --------------------------------------------------------- |
|
4387 // |
|
4388 void CMmsEncode::EncodeMMBoxStates( RArray<TInt>& aStateArray ) |
|
4389 { |
|
4390 TInt i; |
|
4391 |
|
4392 for ( i = 0; i < aStateArray.Count(); ++i ) |
|
4393 { |
|
4394 EncodeMandatoryByte( KMmsAssignedMMState, aStateArray[i] ); |
|
4395 } |
|
4396 } |
|
4397 |
|
4398 // --------------------------------------------------------- |
|
4399 // |
|
4400 // --------------------------------------------------------- |
|
4401 // |
|
4402 void CMmsEncode::EncodeContentLocationArray() |
|
4403 { |
|
4404 TBool mustCheck = EFalse; |
|
4405 if ( iMmsHeaders->ContentLocation().Length() > 0 ) |
|
4406 { |
|
4407 mustCheck = ETrue; |
|
4408 EncodeHeaderAndTextString( KMmsAssignedContentLocation, |
|
4409 iMmsHeaders->ContentLocation() ); |
|
4410 } |
|
4411 // If there is content location array, encode it, too. |
|
4412 // A content-location should never occur in both places, but we still check |
|
4413 |
|
4414 TInt i = 0; |
|
4415 if ( iMmsHeaders->ReadOnlyMMBoxMessageHeaders() ) |
|
4416 { |
|
4417 for ( i = 0; |
|
4418 i < iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->ContentLocationList().Count(); |
|
4419 i++ ) |
|
4420 { |
|
4421 if ( !( mustCheck && iMmsHeaders->ContentLocation().Compare( |
|
4422 iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->ContentLocationList()[i] ) == 0 ) ) |
|
4423 { |
|
4424 // the content location in the list does not appear as |
|
4425 // separate header, we must add it |
|
4426 EncodeHeaderAndTextString( KMmsAssignedContentLocation, |
|
4427 iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->ContentLocationList()[i] ); |
|
4428 } |
|
4429 } |
|
4430 } |
|
4431 } |
|
4432 |
|
4433 // --------------------------------------------------------- |
|
4434 // |
|
4435 // --------------------------------------------------------- |
|
4436 // |
|
4437 void CMmsEncode::EncodeStartingHeaders( TInt aMessageType, |
|
4438 const TPtrC8& aTID, TInt aVersion ) |
|
4439 { |
|
4440 // EncodeMandatoryByte will always set the high bit. |
|
4441 |
|
4442 // Message type |
|
4443 EncodeMandatoryByte( KMmsAssignedMessageType, aMessageType ); |
|
4444 // TID if present |
|
4445 EncodeOptionalString( KMmsAssignedTID, aTID ); |
|
4446 // MMS encapsulation version |
|
4447 EncodeMandatoryByte( KMmsAssignedMmsVersion, aVersion ); |
|
4448 } |
|
4449 |
|
4450 // --------------------------------------------------------- |
|
4451 // |
|
4452 // --------------------------------------------------------- |
|
4453 // |
|
4454 void CMmsEncode::EncodeApplicationIdParametersL() |
|
4455 { |
|
4456 if ( iMmsHeaders->ApplicId().Length() > 0 ) |
|
4457 { |
|
4458 EncodeTextString( KMmsJavaApplicationId ); |
|
4459 EncodeTextStringL( iMmsHeaders->ApplicId() ); |
|
4460 } |
|
4461 if ( iMmsHeaders->ReplyApplicId().Length() > 0 ) |
|
4462 { |
|
4463 EncodeTextString( KMmsJavaReplyApplicationId ); |
|
4464 EncodeTextStringL( iMmsHeaders->ReplyApplicId() ); |
|
4465 } |
|
4466 } |
|
4467 |
|
4468 // --------------------------------------------------------- |
|
4469 // |
|
4470 // --------------------------------------------------------- |
|
4471 void CMmsEncode::Dump() |
|
4472 { |
|
4473 // no dump if not logging |
|
4474 #ifndef _NO_MMSS_LOGGING_ |
|
4475 TInt error = KErrNone; |
|
4476 // if no can do, sorry. |
|
4477 TRAP( error, |
|
4478 { |
|
4479 if ( iEntryWrapper ) |
|
4480 { |
|
4481 if ( ( iEntryWrapper->GetDumpFlag() ) && |
|
4482 iEncodeBuffer && |
|
4483 iEncodeBuffer->Size() > 0 ) |
|
4484 { |
|
4485 iFileName = KMmsDefaultLogDirectory; |
|
4486 TUint att; |
|
4487 if ( iFs.Att( iFileName, att ) == KErrNone ) |
|
4488 { |
|
4489 _LIT( KRelated, "Sent.mms"); |
|
4490 iParse.Set( iFileName, &KRelated, NULL ); |
|
4491 iFileName = iParse.FullName(); |
|
4492 User::LeaveIfError( CApaApplication::GenerateFileName( |
|
4493 iFs, iFileName ) ); |
|
4494 RFile file; |
|
4495 User::LeaveIfError( file.Create( iFs, iFileName, |
|
4496 EFileWrite | EFileShareExclusive ) ); |
|
4497 // for message id generation |
|
4498 iParse.Set( iFileName, NULL, NULL ); |
|
4499 |
|
4500 // the data is supposed to be in the encode buffer |
|
4501 TPtr8 ptr = iEncodeBuffer->BackPtr( iPosition ); |
|
4502 file.Write( ptr ); |
|
4503 file.Flush(); |
|
4504 |
|
4505 // done - close files |
|
4506 file.Close(); |
|
4507 } |
|
4508 } |
|
4509 } |
|
4510 } |
|
4511 ); |
|
4512 if ( error != KErrNone ) |
|
4513 { |
|
4514 TMmsLogger::Log( _L("Dump left with error %d"), error ); |
|
4515 } |
|
4516 #endif |
|
4517 } |
|
4518 |
|
4519 // --------------------------------------------------------- |
|
4520 // |
|
4521 // --------------------------------------------------------- |
|
4522 void CMmsEncode::DumpAppend() |
|
4523 { |
|
4524 |
|
4525 // no dump if not logging |
|
4526 #ifndef _NO_MMSS_LOGGING_ |
|
4527 TInt error = KErrNone; |
|
4528 // if no can do, sorry. |
|
4529 TRAP( error, |
|
4530 { |
|
4531 if ( iEntryWrapper ) |
|
4532 { |
|
4533 if ( ( iEntryWrapper->GetDumpFlag() ) && |
|
4534 iEncodeBuffer && |
|
4535 iEncodeBuffer->Size() > 0 ) |
|
4536 { |
|
4537 iFileName = KMmsDefaultLogDirectory; |
|
4538 TUint att; |
|
4539 if ( iFs.Att( iFileName, att ) == KErrNone ) |
|
4540 { |
|
4541 RFile file; |
|
4542 iFileName = iParse.FullName(); |
|
4543 User::LeaveIfError( file.Open( iFs, iFileName, |
|
4544 EFileWrite | EFileShareExclusive ) ); |
|
4545 TInt position = 0; // seek to end |
|
4546 file.Seek( ESeekEnd, position ); |
|
4547 // the data is supposed to be in the encode buffer |
|
4548 TPtr8 ptr = iEncodeBuffer->BackPtr( iPosition ); |
|
4549 file.Write( ptr ); |
|
4550 file.Flush(); |
|
4551 // done - close files |
|
4552 file.Close(); |
|
4553 } |
|
4554 } |
|
4555 } |
|
4556 } |
|
4557 ); |
|
4558 if ( error != KErrNone ) |
|
4559 { |
|
4560 TMmsLogger::Log( _L("DumpAppend left with error %d"), error ); |
|
4561 } |
|
4562 #endif |
|
4563 } |
|
4564 |
|
4565 // --------------------------------------------------------- |
|
4566 // |
|
4567 // --------------------------------------------------------- |
|
4568 void CMmsEncode::EncodeApplicationHeadersL() |
|
4569 { |
|
4570 // Application headers are only supported in WINS for testing purposes |
|
4571 // Complete support for routing messages to arbitrary applications |
|
4572 // requires support for selecting which applications are allowed |
|
4573 // to send messages etc. |
|
4574 #ifdef __WINS__ |
|
4575 // The optional string functions check the length |
|
4576 // and return without doing anything if the length of the string is 0 |
|
4577 if ( IsStringSafe( iMmsHeaders->ApplicId() ) ) |
|
4578 { |
|
4579 // We only send this header if it is us-ascii only |
|
4580 // There is no encoding defined, so if this is converted |
|
4581 // from unicode to some other character set there is |
|
4582 // no guarantee that the recipient can decode it. |
|
4583 EncodeOptionalStringL( KMmsAssignedApplicId, iMmsHeaders->ApplicId() ); |
|
4584 } |
|
4585 |
|
4586 if ( IsStringSafe( iMmsHeaders->ReplyApplicId() ) ) |
|
4587 { |
|
4588 EncodeOptionalStringL( KMmsAssignedReplyApplicId, iMmsHeaders->ReplyApplicId() ); |
|
4589 } |
|
4590 |
|
4591 EncodeOptionalString( KMmsAssignedAuxApplicInfo, iMmsHeaders->AuxApplicInfo() ); |
|
4592 #endif |
|
4593 } |
|
4594 |
|
4595 // --------------------------------------------------------- |
|
4596 // |
|
4597 // --------------------------------------------------------- |
|
4598 void CMmsEncode::EncodeCancelRequest() |
|
4599 { |
|
4600 // implemented for test purposes |
|
4601 #ifdef __WINS__ |
|
4602 // Insert message type, TID and version number |
|
4603 EncodeStartingHeaders( KMmsMessageTypeCancelReq, |
|
4604 iMmsHeaders->Tid(), iMmsHeaders->MmsVersion() ); |
|
4605 |
|
4606 EncodeOptionalString( KMmsAssignedCancelId, iMmsHeaders->ReplaceCancelId() ); |
|
4607 #endif |
|
4608 } |
|
4609 |
|
4610 // --------------------------------------------------------- |
|
4611 // |
|
4612 // --------------------------------------------------------- |
|
4613 void CMmsEncode::EncodeCancelResponse() |
|
4614 { |
|
4615 // Insert message type, TID and version number |
|
4616 EncodeStartingHeaders( KMmsMessageTypeCancelConf, |
|
4617 iMmsHeaders->Tid(), iMmsHeaders->MmsVersion() ); |
|
4618 |
|
4619 EncodeOptionalByte( KMmsAssignedCancelStatus, iMmsHeaders->CancelStatus() ); |
|
4620 } |
|
4621 |
|
4622 // --------------------------------------------------------- |
|
4623 // |
|
4624 // --------------------------------------------------------- |
|
4625 HBufC8* CMmsEncode::EncodeQuotedPrintableWordL( const TPtrC8& aSource ) |
|
4626 { |
|
4627 // We have calculated that it fits |
|
4628 |
|
4629 TInt bufferLength = KMaxNameBufferLength; |
|
4630 |
|
4631 HBufC8* buffer = HBufC8::NewL( bufferLength ); |
|
4632 CleanupStack::PushL( buffer ); |
|
4633 TPtr8 ptr = buffer->Des(); |
|
4634 buffer->Des().Copy( KMmsQuotedPreamble ); |
|
4635 ptr.SetLength( bufferLength ); |
|
4636 TPtr8 encodeBuffer = ptr.MidTPtr( KMmsPreambleLength ); |
|
4637 encodeBuffer.SetLength( 0 ); // empty the buffer |
|
4638 |
|
4639 TImCodecQP encoder; |
|
4640 |
|
4641 // The function would return the number of characters written to the buffer. |
|
4642 // We don't do anything with the result, so we ignore the return value. |
|
4643 encoder.Encode( aSource, encodeBuffer ); |
|
4644 |
|
4645 ptr.SetLength( encodeBuffer.Length() + KMmsPreambleLength ); |
|
4646 |
|
4647 buffer->Des().Append( KMmsEncodingTrailer ); |
|
4648 CleanupStack::Pop( buffer ); |
|
4649 return buffer; |
|
4650 } |
|
4651 |
|
4652 // --------------------------------------------------------- |
|
4653 // |
|
4654 // --------------------------------------------------------- |
|
4655 HBufC8* CMmsEncode::EncodeBase64WordL( const TPtrC8& aSource ) |
|
4656 { |
|
4657 // ((length + 2)/3)*4 3 bytes alwaus produces 4 encoded bytes. Allow filler |
|
4658 TInt bufferLength = KMmsEncodingExtraLength + ( aSource.Length() + KMms2 ) / KMms3 * KMms4; |
|
4659 |
|
4660 HBufC8* buffer = HBufC8::NewL( bufferLength ); |
|
4661 CleanupStack::PushL( buffer ); |
|
4662 TPtr8 ptr = buffer->Des(); |
|
4663 buffer->Des().Copy( KMmsBase64Preamble ); |
|
4664 ptr.SetLength( bufferLength ); |
|
4665 |
|
4666 TPtr8 encodeBuffer = ptr.MidTPtr( KMmsPreambleLength ); |
|
4667 encodeBuffer.SetLength( 0 ); // empty the buffer |
|
4668 |
|
4669 TImCodecB64 encoder; |
|
4670 |
|
4671 // It is rather unclear what this function actually returns (no documentation found). |
|
4672 // Therefore we just ignore the result. |
|
4673 // Our buffer is long enough for the result to always fit. |
|
4674 encoder.Encode( aSource, encodeBuffer ); |
|
4675 |
|
4676 ptr.SetLength( encodeBuffer.Length() + KMmsPreambleLength ); |
|
4677 |
|
4678 buffer->Des().Append( KMmsEncodingTrailer ); |
|
4679 CleanupStack::Pop( buffer ); |
|
4680 return buffer; |
|
4681 } |
|
4682 |
|
4683 |
|
4684 // --------------------------------------------------------- |
|
4685 // CMmsEncode::PreProcessAttachmentDataL |
|
4686 // Open the message store(Edit mode) and process attachments for further encoding in required encoding type. |
|
4687 // Update the message store accordingly with the new encoding type and data in the corresponding attachments. |
|
4688 // --------------------------------------------------------- |
|
4689 void CMmsEncode::PreProcessAttachmentDataL() |
|
4690 { |
|
4691 TInt error = KErrNone; |
|
4692 RFile attachFile; |
|
4693 TBool retVal = EFalse; |
|
4694 TInt currAttachI; |
|
4695 |
|
4696 #ifndef _NO_MMSS_LOGGING_ |
|
4697 TMmsLogger::Log( _L("CMmsEncode::PreProcessAttachmentDataL- start ") ); |
|
4698 #endif /* _NO_MMSS_LOGGING_ */ |
|
4699 CMsvStore* editStore = iEntryWrapper->EditStoreL(); |
|
4700 CleanupStack::PushL( editStore ); |
|
4701 |
|
4702 MMsvAttachmentManager& attachMan = editStore->AttachmentManagerL(); |
|
4703 MMsvAttachmentManagerSync& attachManagerSync = editStore->AttachmentManagerExtensionsL(); |
|
4704 TInt numberOfAttachments = attachMan.AttachmentCount(); |
|
4705 CMsvAttachment* attachmentInfo = NULL; |
|
4706 iTextUtils = CMsgTextUtils::NewL( iFs ); |
|
4707 |
|
4708 for ( currAttachI = 0; ( currAttachI < numberOfAttachments ) && ( error == KErrNone ); currAttachI++ ) |
|
4709 { |
|
4710 //gets the ownership from attachment manager |
|
4711 attachmentInfo = attachMan.GetAttachmentInfoL( currAttachI ); |
|
4712 CleanupStack::PushL( attachmentInfo ); |
|
4713 iMimeHeaders->RestoreL( *attachmentInfo ); |
|
4714 #ifndef _NO_MMSS_LOGGING_ |
|
4715 TMmsLogger::Log( _L("CMmsEncode::PreProcessAttachmentDataL- Attchment:%d "), currAttachI ); |
|
4716 #endif /* _NO_MMSS_LOGGING_ */ |
|
4717 |
|
4718 if ( iFileOpen ) |
|
4719 { |
|
4720 // close any file in case we have been reset while the file is still open |
|
4721 iAttachFile.Close(); |
|
4722 iFileOpen = EFalse; |
|
4723 } |
|
4724 |
|
4725 retVal = CheckAndUpdateAttachmentL(*attachmentInfo, *iMimeHeaders); |
|
4726 |
|
4727 if( retVal ) |
|
4728 { |
|
4729 TRAPD( |
|
4730 err, |
|
4731 attachManagerSync.ModifyAttachmentInfoL(attachmentInfo); |
|
4732 editStore->CommitL(); |
|
4733 ); |
|
4734 #ifndef _NO_MMSS_LOGGING_ |
|
4735 if(err != KErrNone) |
|
4736 { |
|
4737 TMmsLogger::Log( _L("CMmsEncode::PreProcessAttachmentData:: store commit error: %d"), err ); |
|
4738 } |
|
4739 else |
|
4740 { |
|
4741 TMmsLogger::Log( _L("CMmsEncode::PreProcessAttachmentData:: store commit success") ); |
|
4742 } |
|
4743 #endif /* _NO_MMSS_LOGGING_ */ |
|
4744 /* attachmentInfo ownership is transferred to attachment manager |
|
4745 * Hence, JUST pop attachmentInfo, DO NOT Destroy. |
|
4746 */ |
|
4747 CleanupStack::Pop( attachmentInfo ); |
|
4748 } |
|
4749 else |
|
4750 { |
|
4751 CleanupStack::PopAndDestroy( attachmentInfo ); |
|
4752 attachmentInfo = NULL; |
|
4753 #ifndef _NO_MMSS_LOGGING_ |
|
4754 TMmsLogger::Log( _L("CMmsEncode::PreProcessAttachmentData:: Tgt encoding NOT Reqd.") ); |
|
4755 #endif /* _NO_MMSS_LOGGING_ */ |
|
4756 } |
|
4757 } |
|
4758 CleanupStack::PopAndDestroy( editStore ); |
|
4759 |
|
4760 delete iTextUtils; |
|
4761 iTextUtils = NULL; |
|
4762 #ifndef _NO_MMSS_LOGGING_ |
|
4763 TMmsLogger::Log( _L("CMmsEncode::PreProcessAttachmentDataL- end ") ); |
|
4764 #endif /* _NO_MMSS_LOGGING_ */ |
|
4765 } |
|
4766 |
|
4767 // --------------------------------------------------------- |
|
4768 // CMmsEncode::CheckAndUpdateAttachmentL |
|
4769 // Check and proceed if given attachment can be encoded using target encoding type based on its content type. |
|
4770 // Returns False if target encoding is not supported for this content type. |
|
4771 // --------------------------------------------------------- |
|
4772 TBool CMmsEncode::CheckAndUpdateAttachmentL( CMsvAttachment& aAttachmentInfo, |
|
4773 CMsvMimeHeaders& aMimeHeaders ) |
|
4774 { |
|
4775 //get the content type string... and set to attachment if required |
|
4776 TInt contentType = -1; // indicate not found |
|
4777 TPtrC8 contentTypeString; |
|
4778 TBool retVal = EFalse; |
|
4779 #ifndef _NO_MMSS_LOGGING_ |
|
4780 TMmsLogger::Log( _L("CMmsEncode::CheckAndUpdateAttachmentL- start ") ); |
|
4781 #endif /* _NO_MMSS_LOGGING_ */ |
|
4782 |
|
4783 HBufC8* tempContentType = NULL; |
|
4784 contentTypeString.Set( aAttachmentInfo.MimeType() ); |
|
4785 if ( contentTypeString.Length() == 0 ) |
|
4786 { |
|
4787 // take type from mime headers |
|
4788 TInt cotentLength = aMimeHeaders.ContentType().Length(); |
|
4789 TInt subCotentLength = aMimeHeaders.ContentSubType().Length(); |
|
4790 tempContentType = HBufC8::NewL( cotentLength + subCotentLength + 1 ); |
|
4791 CleanupStack::PushL( tempContentType ); |
|
4792 tempContentType->Des().Copy( aMimeHeaders.ContentType() ); |
|
4793 if ( ( aMimeHeaders.ContentType().Find( KMmsSlash8 ) != ( cotentLength - 1 ) ) && |
|
4794 ( aMimeHeaders.ContentSubType().Find( KMmsSlash8 ) != 0 ) && ( subCotentLength != 0 ) ) |
|
4795 { |
|
4796 tempContentType->Des().Append( KMmsSlash8 ); |
|
4797 } |
|
4798 tempContentType->Des().Append( aMimeHeaders.ContentSubType() ); |
|
4799 aAttachmentInfo.SetMimeTypeL( tempContentType->Des() ); |
|
4800 contentTypeString.Set( aAttachmentInfo.MimeType() ); |
|
4801 } |
|
4802 |
|
4803 //map the content type string to content type |
|
4804 TInt8 i; |
|
4805 for ( i = 0; i < KNumberContentTypes && contentType < 0; i++ ) |
|
4806 { |
|
4807 if ( contentTypeString.CompareF( TPtrC8( KContentTypeTable[i] ) ) == 0 ) |
|
4808 { |
|
4809 contentType = i; |
|
4810 } |
|
4811 } |
|
4812 #ifndef _NO_MMSS_LOGGING_ |
|
4813 TMmsLogger::Log( _L("CMmsEncode::CheckAndUpdateAttachmentL- content type:%d" ), contentType ); |
|
4814 #endif /* _NO_MMSS_LOGGING_ */ |
|
4815 //check if this content type need to be encoded using korean specific |
|
4816 if( IsConversionSupportedContentType( contentType ) ) |
|
4817 { |
|
4818 /* Do the attachment data conversion from "src type" to "target type" for the given "attached file". |
|
4819 * Target type encodng MIB enum is obtained from cenrep. |
|
4820 */ |
|
4821 retVal = ProcessAndConvertAttachmentDataL( aMimeHeaders.MimeCharset(), |
|
4822 iTargetEncodingType, |
|
4823 aAttachmentInfo); |
|
4824 if( retVal ) |
|
4825 { |
|
4826 #ifndef _NO_MMSS_LOGGING_ |
|
4827 TMmsLogger::Log( _L("CMmsEncode::CheckAndUpdateAttachmentL- conv success: Tgt Enc: %d"), iTargetEncodingType ); |
|
4828 #endif /* _NO_MMSS_LOGGING_ */ |
|
4829 //set new charset type in headers and update attachment info |
|
4830 aMimeHeaders.SetMimeCharset( iTargetEncodingType ); |
|
4831 aMimeHeaders.StoreL(aAttachmentInfo); // save the new charset to attachment as well |
|
4832 /* mimetype might get reset to original mimeheader content type. |
|
4833 * ensure the full content type(if created from mime content and subcontent) is set to attachment |
|
4834 */ |
|
4835 if( tempContentType != NULL ) |
|
4836 { |
|
4837 aAttachmentInfo.SetMimeTypeL( tempContentType->Des() ); |
|
4838 CleanupStack::PopAndDestroy( tempContentType ); |
|
4839 } |
|
4840 } |
|
4841 } |
|
4842 #ifndef _NO_MMSS_LOGGING_ |
|
4843 TMmsLogger::Log( _L("CMmsEncode::CheckAndUpdateAttachmentL- End , retVal: %d"), retVal ); |
|
4844 #endif /* _NO_MMSS_LOGGING_ */ |
|
4845 return retVal; |
|
4846 } |
|
4847 |
|
4848 // --------------------------------------------------------- |
|
4849 // CMmsEncode::ProcessAndConvertAttachmentDataL |
|
4850 // converts of attachment data from source to target encoding type. |
|
4851 // |src charset buffer| --->converted to ---> |unicode buffer| ---> converted to ---> |target charset| |
|
4852 // Returns false if data is already int target format, or plugins are missing, or file operation issues. |
|
4853 // --------------------------------------------------------- |
|
4854 TBool CMmsEncode::ProcessAndConvertAttachmentDataL( TUint aSrcCharSetMIBEnum, |
|
4855 TUint aTargetCharSetMIBEnum, |
|
4856 CMsvAttachment& aAttachmentInfo) |
|
4857 { |
|
4858 #ifndef _NO_MMSS_LOGGING_ |
|
4859 TMmsLogger::Log( _L("CMmsEncode::ProcessAndConvertAttachmentDataL- start ") ); |
|
4860 #endif /* _NO_MMSS_LOGGING_ */ |
|
4861 if( aSrcCharSetMIBEnum == aTargetCharSetMIBEnum ) |
|
4862 { |
|
4863 #ifndef _NO_MMSS_LOGGING_ |
|
4864 TMmsLogger::Log( _L("CMmsEncode::ProcessAndConvertAttachmentDataL- src and dest are same ") ); |
|
4865 #endif /* _NO_MMSS_LOGGING_ */ |
|
4866 //if source and target charset MIB enums are same. |
|
4867 return EFalse; // no conversion |
|
4868 } |
|
4869 |
|
4870 //get source and target charset mapping here. if any error, return |
|
4871 TUint srcCharSetId = iTextUtils->MibIdToCharconvIdL( aSrcCharSetMIBEnum ); |
|
4872 TUint targetCharSetId = iTextUtils->MibIdToCharconvIdL( aTargetCharSetMIBEnum ); |
|
4873 if( srcCharSetId == targetCharSetId || KDefaultCharConvCharset == targetCharSetId) |
|
4874 { |
|
4875 /* If target charset plugin is missing, then default is returned. |
|
4876 Do not encode to any target encoding type, send data as is . |
|
4877 */ |
|
4878 #ifndef _NO_MMSS_LOGGING_ |
|
4879 TMmsLogger::Log( _L("CMmsEncode::ProcessAndConvertAttachmentDataL- missing plugin: Tgt Charset %x"), targetCharSetId ); |
|
4880 #endif /* _NO_MMSS_LOGGING_ */ |
|
4881 return EFalse; |
|
4882 } |
|
4883 |
|
4884 RFile attachFile; |
|
4885 TInt error; |
|
4886 |
|
4887 const TDesC& fileName = aAttachmentInfo.FilePath(); |
|
4888 error = attachFile.Open(iFs, fileName, EFileWrite); |
|
4889 if(error != KErrNone) |
|
4890 { |
|
4891 #ifndef _NO_MMSS_LOGGING_ |
|
4892 TMmsLogger::Log( _L("CMmsEncode::ProcessAndConvertAttachmentData:: file: %s, open error: %d"), fileName, error ); |
|
4893 #endif /* _NO_MMSS_LOGGING_ */ |
|
4894 attachFile.Close(); |
|
4895 return EFalse; |
|
4896 } |
|
4897 |
|
4898 TInt maxLength; |
|
4899 error = attachFile.Size(maxLength); |
|
4900 if( error != KErrNone || maxLength == 0 ) |
|
4901 { |
|
4902 #ifndef _NO_MMSS_LOGGING_ |
|
4903 TMmsLogger::Log( _L("CMmsEncode::ProcessAndConvertAttachmentData:: file size: %d, error: %d"), maxLength, error ); |
|
4904 #endif /* _NO_MMSS_LOGGING_ */ |
|
4905 attachFile.Close(); |
|
4906 return EFalse; |
|
4907 } |
|
4908 |
|
4909 //read the original file data into srcBuffer |
|
4910 TInt cleanupCount = 0; |
|
4911 HBufC8* srcBuffer = HBufC8::NewLC( maxLength ); |
|
4912 cleanupCount++; |
|
4913 |
|
4914 TPtr8 srcPtr = srcBuffer->Des(); |
|
4915 attachFile.Read( srcPtr, maxLength ); |
|
4916 |
|
4917 //intermediate buffer in the form of unicode. |
|
4918 HBufC16* unicodeBuffer(NULL); |
|
4919 |
|
4920 //Convert, scrBuffer to unicode format if not already in unicode format |
|
4921 if(srcCharSetId != 0) |
|
4922 { |
|
4923 //Convert from respective foreign charset to unicode buffer. |
|
4924 //returns buf16 pointer descriptor |
|
4925 TRAPD(err, unicodeBuffer = iTextUtils->ConvertToUnicodeL(srcPtr, srcCharSetId) ); |
|
4926 if( err != KErrNone ) |
|
4927 { |
|
4928 #ifndef _NO_MMSS_LOGGING_ |
|
4929 TMmsLogger::Log( _L("CMmsEncode::ProcessAndConvertAttachmentData:: ConvertToUnicodeL error: %d"), err ); |
|
4930 #endif /* _NO_MMSS_LOGGING_ */ |
|
4931 delete unicodeBuffer; |
|
4932 attachFile.Close(); |
|
4933 CleanupStack::PopAndDestroy( cleanupCount, srcBuffer ); // srcBuffer |
|
4934 return EFalse; |
|
4935 } |
|
4936 CleanupStack::PushL( unicodeBuffer ); |
|
4937 cleanupCount++; |
|
4938 } |
|
4939 else |
|
4940 { |
|
4941 TInt unicodeStdHeaderWordLE = 0xFEFF; |
|
4942 TInt unicodeStdHeaderWordBE = 0xFFFE; |
|
4943 //data is already in unicode format. need to extract the data to 16-bit buffer |
|
4944 unicodeBuffer = HBufC16::NewLC( maxLength/2 );//maxlength value is in terms of bytes |
|
4945 cleanupCount++; |
|
4946 |
|
4947 TPtr16 ptr = unicodeBuffer->Des(); |
|
4948 iTextUtils->ConvertPtrToDesC16(srcPtr, ptr); |
|
4949 /* In case if attachment is UTF-16 format, it will have the UTF-16 representation word(2 butes) |
|
4950 * at the start. Find and delete it before passing the data for conversion |
|
4951 */ |
|
4952 if( ptr[0] == unicodeStdHeaderWordLE || ptr[0] == unicodeStdHeaderWordBE ) |
|
4953 { |
|
4954 ptr.Delete(0, 1); |
|
4955 } |
|
4956 } |
|
4957 |
|
4958 //Now convert unicode buffer to respective target charset type. |
|
4959 if( targetCharSetId != 0 ) |
|
4960 { |
|
4961 // reset this file and write new encoded data to it directly |
|
4962 error = attachFile.SetSize(0); |
|
4963 #ifndef _NO_MMSS_LOGGING_ |
|
4964 if( error != KErrNone ) |
|
4965 { |
|
4966 TMmsLogger::Log( _L("CMmsEncode::ProcessAndConvertAttachmentData:: file size: %d, error: %d"), maxLength, error ); |
|
4967 //attachFile.Close(); |
|
4968 //return EFalse; |
|
4969 } |
|
4970 #endif /* _NO_MMSS_LOGGING_ */ |
|
4971 |
|
4972 /* convert to target charset id. |
|
4973 * Ideally, this should not leave with plugin-NOT-found, since it it already verified |
|
4974 */ |
|
4975 iTextUtils->ConvertToFileL(*unicodeBuffer, attachFile, targetCharSetId ); |
|
4976 } |
|
4977 else |
|
4978 { |
|
4979 TPtr16 ptr = unicodeBuffer->Des(); |
|
4980 //Reset/erase old file content. |
|
4981 TInt err = attachFile.SetSize(0); |
|
4982 |
|
4983 //write new encoded data to file using write stream |
|
4984 RFileWriteStream writer( attachFile ); |
|
4985 writer.PushL(); |
|
4986 writer.WriteL( ptr ); |
|
4987 //writer.CommitL(); |
|
4988 writer.Pop(); |
|
4989 writer.Close(); |
|
4990 } |
|
4991 //close file |
|
4992 attachFile.Close(); |
|
4993 CleanupStack::PopAndDestroy( cleanupCount, srcBuffer ); //unicodeBuffer, srcBuffer |
|
4994 #ifndef _NO_MMSS_LOGGING_ |
|
4995 TMmsLogger::Log( _L("CMmsEncode::ProcessAndConvertAttachmentDataL- End, retVal: TRUE") ); |
|
4996 #endif /* _NO_MMSS_LOGGING_ */ |
|
4997 return ETrue; |
|
4998 } |
|
4999 |
|
5000 |
|
5001 // --------------------------------------------------------- |
|
5002 // CMmsEncode::IsConversionSupportedContentType |
|
5003 // checks if input content type is supported for target encoding |
|
5004 // --------------------------------------------------------- |
|
5005 TBool CMmsEncode::IsConversionSupportedContentType( TInt aContentType ) |
|
5006 { |
|
5007 /* Currently only "text/plain" content types are supported for korean encoding. |
|
5008 * Add to the switch case, if any new content type can be supported as well. |
|
5009 * |
|
5010 * IMPORTANT: |
|
5011 * Ensure the values added map to corresponding content type entry in the table KContentTypeTable[], |
|
5012 * defined in ../inc/mmscodec.h |
|
5013 */ |
|
5014 #ifndef _NO_MMSS_LOGGING_ |
|
5015 TMmsLogger::Log( _L("CMmsEncode::IsConversionSupportedContentType- start: %d "), aContentType ); |
|
5016 #endif /* _NO_MMSS_LOGGING_ */ |
|
5017 TBool retVal = EFalse; |
|
5018 switch( aContentType ) |
|
5019 { |
|
5020 case 0x03 : // "text/plain" |
|
5021 { |
|
5022 retVal = ETrue; |
|
5023 break; |
|
5024 } |
|
5025 default: |
|
5026 //do nothing |
|
5027 break;// to avoid compile errors/warning |
|
5028 } |
|
5029 #ifndef _NO_MMSS_LOGGING_ |
|
5030 TMmsLogger::Log( _L("CMmsEncode::IsConversionSupportedContentType- end ") ); |
|
5031 #endif /* _NO_MMSS_LOGGING_ */ |
|
5032 return retVal; |
|
5033 } |
|
5034 |
|
5035 // ================= OTHER EXPORTED FUNCTIONS ============== |
|
5036 |
|
5037 // End of File |