~ubuntu-branches/ubuntu/quantal/enigmail/quantal-security

« back to all changes in this revision

Viewing changes to extensions/enigmail/src/nsEnigMimeListener.cpp

  • Committer: Package Import Robot
  • Author(s): Chris Coulson
  • Date: 2013-09-13 16:02:15 UTC
  • mfrom: (0.12.16)
  • Revision ID: package-import@ubuntu.com-20130913160215-u3g8nmwa0pdwagwc
Tags: 2:1.5.2-0ubuntu0.12.10.1
* New upstream release v1.5.2 for Thunderbird 24

* Build enigmail using a stripped down Thunderbird 17 build system, as it's
  now quite difficult to build the way we were doing previously, with the
  latest Firefox build system
* Add debian/patches/no_libxpcom.patch - Don't link against libxpcom, as it
  doesn't exist anymore (but exists in the build system)
* Add debian/patches/use_sdk.patch - Use the SDK version of xpt.py and
  friends
* Drop debian/patches/ipc-pipe_rename.diff (not needed anymore)
* Drop debian/patches/makefile_depth.diff (not needed anymore)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* ***** BEGIN LICENSE BLOCK *****
2
 
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3
 
 *
4
 
 * The contents of this file are subject to the Mozilla Public
5
 
 * License Version 1.1 (the "MPL"); you may not use this file
6
 
 * except in compliance with the MPL. You may obtain a copy of
7
 
 * the MPL at http://www.mozilla.org/MPL/
8
 
 *
9
 
 * Software distributed under the MPL is distributed on an "AS
10
 
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11
 
 * implied. See the MPL for the specific language governing
12
 
 * rights and limitations under the MPL.
13
 
 *
14
 
 * The Original Code is Enigmail.
15
 
 *
16
 
 * The Initial Developer of the Original Code is Ramalingam Saravanan.
17
 
 * Portions created by Ramalingam Saravanan <sarava@sarava.net> are
18
 
 * Copyright (C) 2002 Ramalingam Saravanan. All Rights Reserved.
19
 
 *
20
 
 * Contributor(s):
21
 
 * Patrick Brunschwig <patrick@mozilla-enigmail.org>
22
 
 *
23
 
 * Alternatively, the contents of this file may be used under the terms of
24
 
 * either the GNU General Public License Version 2 or later (the "GPL"), or
25
 
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26
 
 * in which case the provisions of the GPL or the LGPL are applicable instead
27
 
 * of those above. If you wish to allow use of your version of this file only
28
 
 * under the terms of either the GPL or the LGPL, and not to allow others to
29
 
 * use your version of this file under the terms of the MPL, indicate your
30
 
 * decision by deleting the provisions above and replace them with the notice
31
 
 * and other provisions required by the GPL or the LGPL. If you do not delete
32
 
 * the provisions above, a recipient may use your version of this file under
33
 
 * the terms of any one of the MPL, the GPL or the LGPL.
34
 
 * ***** END LICENSE BLOCK ***** */
35
 
 
36
 
// Logging of debug output
37
 
// The following define statement should occur before any include statements
38
 
#define FORCE_PR_LOG       /* Allow logging even in release build */
39
 
 
40
 
#include "enigmail.h"
41
 
#include "prlog.h"
42
 
#include "nsCOMPtr.h"
43
 
#include "nsIInputStream.h"
44
 
#include "nsIThread.h"
45
 
#include "nsStringAPI.h"
46
 
#include "nsNetUtil.h"
47
 
#include "mimehdrs2.h"
48
 
#include "nsMimeTypes.h"
49
 
#include "nsMailHeaders.h"
50
 
 
51
 
#include "nsEnigMimeListener.h"
52
 
 
53
 
#ifdef PR_LOGGING
54
 
PRLogModuleInfo* gEnigMimeListenerLog = NULL;
55
 
#endif
56
 
 
57
 
#define ERROR_LOG(args)    PR_LOG(gEnigMimeListenerLog,PR_LOG_ERROR,args)
58
 
#define WARNING_LOG(args)  PR_LOG(gEnigMimeListenerLog,PR_LOG_WARNING,args)
59
 
#define DEBUG_LOG(args)    PR_LOG(gEnigMimeListenerLog,PR_LOG_DEBUG,args)
60
 
 
61
 
#define NS_PIPE_CONSOLE_BUFFER_SIZE   (1024)
62
 
 
63
 
static const PRUint32 kCharMax = 1024;
64
 
 
65
 
#define MK_MIME_ERROR_WRITING_FILE -1
66
 
 
67
 
///////////////////////////////////////////////////////////////////////////////
68
 
 
69
 
// nsEnigMimeListener implementation
70
 
 
71
 
// nsISupports implementation
72
 
NS_IMPL_THREADSAFE_ISUPPORTS4(nsEnigMimeListener,
73
 
                              nsIEnigMimeListener,
74
 
                              nsIRequestObserver,
75
 
                              nsIStreamListener,
76
 
                              nsIInputStream)
77
 
 
78
 
 
79
 
// nsEnigMimeListener implementation
80
 
nsEnigMimeListener::nsEnigMimeListener()
81
 
  : mInitialized(PR_FALSE),
82
 
    mRequestStarted(PR_FALSE),
83
 
    mSkipHeaders(PR_FALSE),
84
 
    mSkipBody(PR_FALSE),
85
 
 
86
 
    mContentType(""),
87
 
    mContentCharset(""),
88
 
    mContentBoundary(""),
89
 
    mContentProtocol(""),
90
 
    mContentMicalg(""),
91
 
 
92
 
    mContentEncoding(""),
93
 
    mContentDisposition(""),
94
 
    mContentLength(-1),
95
 
 
96
 
    mDecodeContent(PR_FALSE),
97
 
    mDecoderData(NULL),
98
 
 
99
 
    mLinebreak(""),
100
 
    mHeaders(""),
101
 
    mDataStr(""),
102
 
    mHeaderSearchCounter(0),
103
 
 
104
 
    mHeadersFinalCR(PR_FALSE),
105
 
    mHeadersLinebreak(2),
106
 
 
107
 
    mMaxHeaderBytes(0),
108
 
    mDataOffset(0),
109
 
 
110
 
    mStreamBuf(NULL),
111
 
    mStreamOffset(0),
112
 
    mStreamLength(0),
113
 
    mSubPartTreatment(PR_FALSE),
114
 
 
115
 
    mListener(NULL),
116
 
    mContext(NULL)
117
 
{
118
 
    NS_INIT_ISUPPORTS();
119
 
 
120
 
#ifdef PR_LOGGING
121
 
  if (gEnigMimeListenerLog == NULL) {
122
 
    gEnigMimeListenerLog = PR_NewLogModule("nsEnigMimeListener");
123
 
  }
124
 
#endif
125
 
 
126
 
#ifdef FORCE_PR_LOG
127
 
  nsresult rv;
128
 
  nsCOMPtr<nsIThread> myThread;
129
 
  rv = ENIG_GET_THREAD(myThread);
130
 
  DEBUG_LOG(("nsEnigMimeListener:: <<<<<<<<< CTOR(%p): myThread=%p\n",
131
 
         this, myThread.get()));
132
 
#endif
133
 
}
134
 
 
135
 
 
136
 
nsEnigMimeListener::~nsEnigMimeListener()
137
 
{
138
 
  nsresult rv;
139
 
#ifdef FORCE_PR_LOG
140
 
  nsCOMPtr<nsIThread> myThread;
141
 
  rv = ENIG_GET_THREAD(myThread);
142
 
  DEBUG_LOG(("nsEnigMimeListener:: >>>>>>>>> DTOR(%p): myThread=%p\n",
143
 
         this, myThread.get()));
144
 
#endif
145
 
 
146
 
  if (mDecoderData) {
147
 
    // Clear decoder buffer
148
 
    MimeDecoderDestroy(mDecoderData, PR_FALSE);
149
 
    mDecoderData = NULL;
150
 
  }
151
 
 
152
 
  // Release owning refs
153
 
  mListener = NULL;
154
 
  mContext = NULL;
155
 
}
156
 
 
157
 
 
158
 
///////////////////////////////////////////////////////////////////////////////
159
 
// nsIEnigMimeListener methods
160
 
///////////////////////////////////////////////////////////////////////////////
161
 
 
162
 
NS_IMETHODIMP
163
 
nsEnigMimeListener::Init(nsIStreamListener* listener, nsISupports* ctxt,
164
 
                         PRUint32 maxHeaderBytes, EMBool skipHeaders,
165
 
                         EMBool skipBody, EMBool decodeContent)
166
 
{
167
 
  DEBUG_LOG(("nsEnigMimeListener::Init: (%p) %d, %d, %d, %d\n", this,
168
 
             maxHeaderBytes, skipHeaders, skipBody, decodeContent));
169
 
 
170
 
  if (!listener)
171
 
    return NS_ERROR_NULL_POINTER;
172
 
 
173
 
  if (decodeContent)
174
 
    return NS_ERROR_NOT_IMPLEMENTED;
175
 
 
176
 
  mListener = listener;
177
 
  mContext = ctxt;
178
 
 
179
 
  mMaxHeaderBytes = maxHeaderBytes;
180
 
 
181
 
  mSkipHeaders = skipHeaders;
182
 
  mSkipBody = skipBody;
183
 
  mDecodeContent = decodeContent;
184
 
 
185
 
  // There is implicitly a newline preceding the first character
186
 
  mHeadersLinebreak = 2;
187
 
  mHeadersFinalCR = PR_FALSE;
188
 
 
189
 
  mInitialized = PR_TRUE;
190
 
 
191
 
  return NS_OK;
192
 
}
193
 
 
194
 
 
195
 
NS_IMETHODIMP
196
 
nsEnigMimeListener::Write(const char* buf, PRUint32 count,
197
 
                          nsIRequest* aRequest, nsISupports* aContext)
198
 
{
199
 
  nsresult rv;
200
 
 
201
 
  DEBUG_LOG(("nsEnigMimeListener::Write: (%p) %d\n", this, count));
202
 
 
203
 
  if (mRequestStarted)
204
 
    return Transmit(buf, count, aRequest, aContext);
205
 
 
206
 
  // Search for headers
207
 
  EMBool startingRequest = HeaderSearch(buf, count);
208
 
  if (!startingRequest)
209
 
    return NS_OK;
210
 
 
211
 
  rv = StartRequest(aRequest, aContext);
212
 
  if (NS_FAILED(rv))
213
 
    return rv;
214
 
 
215
 
  return NS_OK;
216
 
}
217
 
 
218
 
static nsresult
219
 
EnigMimeListener_write(const char *buf, PRInt32 size, void *closure)
220
 
{
221
 
  DEBUG_LOG(("nsEnigMimeListener::EnigMimeListener_write: (%p) %d\n", closure, size));
222
 
 
223
 
  if (!closure)
224
 
    return NS_ERROR_FAILURE;
225
 
 
226
 
  nsEnigMimeListener* enigMimeListener = (nsEnigMimeListener *) closure;
227
 
 
228
 
  return enigMimeListener->SendStream(buf, size, NULL, NULL);
229
 
}
230
 
 
231
 
 
232
 
NS_METHOD
233
 
nsEnigMimeListener::Transmit(const char* buf, PRUint32 count,
234
 
                             nsIRequest* aRequest, nsISupports* aContext)
235
 
{
236
 
  DEBUG_LOG(("nsEnigMimeListener::Transmit: (%p) %d\n", this, count));
237
 
 
238
 
  if (!mDecoderData) {
239
 
    return SendStream(buf, count, aRequest, aContext);
240
 
  }
241
 
 
242
 
  // Decode data before transmitting to listener
243
 
  int status = MimeDecoderWrite(mDecoderData, buf, count);
244
 
 
245
 
  return (status == 0) ? NS_OK : NS_ERROR_FAILURE;
246
 
}
247
 
 
248
 
 
249
 
NS_METHOD
250
 
nsEnigMimeListener::SendStream(const char* buf, PRUint32 count,
251
 
                               nsIRequest* aRequest, nsISupports* aContext)
252
 
{
253
 
  nsresult rv;
254
 
 
255
 
  DEBUG_LOG(("nsEnigMimeListener::SendStream: (%p) %d\n", this, count));
256
 
 
257
 
  if (!mListener)
258
 
    return NS_OK;
259
 
 
260
 
  // Transmit data to listener
261
 
  mStreamBuf = buf;
262
 
  mStreamOffset = 0;
263
 
  mStreamLength = count;
264
 
 
265
 
  rv = mListener->OnDataAvailable(aRequest,
266
 
                                  mContext ? mContext.get() : aContext,
267
 
                                  (nsIInputStream*)(this),
268
 
                                  0, count);
269
 
  Close();
270
 
 
271
 
  return rv;
272
 
}
273
 
 
274
 
 
275
 
NS_IMETHODIMP
276
 
nsEnigMimeListener::GetHeaders(nsACString &aHeaders)
277
 
{
278
 
  aHeaders = mHeaders;
279
 
  DEBUG_LOG(("nsEnigMimeListener::GetHeaders: %d\n", mHeaders.Length()));
280
 
  return NS_OK;
281
 
}
282
 
 
283
 
NS_IMETHODIMP
284
 
nsEnigMimeListener::GetLinebreak(nsACString &aLinebreak)
285
 
{
286
 
  aLinebreak = mLinebreak;
287
 
  DEBUG_LOG(("nsEnigMimeListener::GetLinebreak: %d\n", mLinebreak.Length()));
288
 
  return NS_OK;
289
 
}
290
 
 
291
 
NS_IMETHODIMP
292
 
nsEnigMimeListener::GetContentType(nsACString &aContentType)
293
 
{
294
 
  aContentType = mContentType;
295
 
  DEBUG_LOG(("nsEnigMimeListener::GetContentType: %s\n", mContentType.get()));
296
 
  return NS_OK;
297
 
}
298
 
 
299
 
NS_IMETHODIMP
300
 
nsEnigMimeListener::GetContentCharset(nsACString &aContentCharset)
301
 
{
302
 
  aContentCharset = mContentCharset;
303
 
  DEBUG_LOG(("nsEnigMimeListener::GetContentCharset: %s\n", mContentCharset.get()));
304
 
  return NS_OK;
305
 
}
306
 
 
307
 
NS_IMETHODIMP
308
 
nsEnigMimeListener::GetContentBoundary(nsACString &aContentBoundary)
309
 
{
310
 
  aContentBoundary = mContentBoundary;
311
 
  DEBUG_LOG(("nsEnigMimeListener::GetContentBoundary: %s\n", mContentBoundary.get()));
312
 
  return NS_OK;
313
 
}
314
 
 
315
 
NS_IMETHODIMP
316
 
nsEnigMimeListener::GetContentProtocol(nsACString &aContentProtocol)
317
 
{
318
 
  aContentProtocol = mContentProtocol;
319
 
  DEBUG_LOG(("nsEnigMimeListener::GetContentProtocol: %s\n", mContentProtocol.get()));
320
 
  return NS_OK;
321
 
}
322
 
 
323
 
NS_IMETHODIMP
324
 
nsEnigMimeListener::GetContentMicalg(nsACString &aContentMicalg)
325
 
{
326
 
  aContentMicalg = mContentMicalg;
327
 
  DEBUG_LOG(("nsEnigMimeListener::GetContentMicalg: %s\n", mContentMicalg.get()));
328
 
  return NS_OK;
329
 
}
330
 
 
331
 
NS_IMETHODIMP
332
 
nsEnigMimeListener::GetContentEncoding(nsACString &aContentEncoding)
333
 
{
334
 
  aContentEncoding = mContentEncoding;
335
 
  DEBUG_LOG(("nsEnigMimeListener::GetContentEncoding: %s\n", mContentEncoding.get()));
336
 
  return NS_OK;
337
 
}
338
 
 
339
 
NS_IMETHODIMP
340
 
nsEnigMimeListener::GetContentDisposition(nsACString &aContentDisposition)
341
 
{
342
 
  aContentDisposition = mContentDisposition;
343
 
  DEBUG_LOG(("nsEnigMimeListener::GetContentDisposition: %s\n", mContentDisposition.get()));
344
 
  return NS_OK;
345
 
}
346
 
 
347
 
NS_IMETHODIMP
348
 
nsEnigMimeListener::GetContentLength(PRInt32 *aContentLength)
349
 
{
350
 
  DEBUG_LOG(("nsEnigMimeListener::GetContentLength: \n"));
351
 
  *aContentLength = mContentLength;
352
 
  return NS_OK;
353
 
}
354
 
 
355
 
///////////////////////////////////////////////////////////////////////////////
356
 
// nsIRequestObserver methods
357
 
///////////////////////////////////////////////////////////////////////////////
358
 
 
359
 
NS_IMETHODIMP
360
 
nsEnigMimeListener::OnStartRequest(nsIRequest *aRequest,
361
 
                                   nsISupports *aContext)
362
 
{
363
 
  DEBUG_LOG(("nsEnigMimeListener::OnStartRequest: (%p)\n", this));
364
 
 
365
 
  if (!mInitialized)
366
 
    return NS_ERROR_NOT_INITIALIZED;
367
 
 
368
 
  return NS_OK;
369
 
}
370
 
 
371
 
NS_IMETHODIMP
372
 
nsEnigMimeListener::OnStopRequest(nsIRequest* aRequest,
373
 
                                  nsISupports* aContext,
374
 
                                  nsresult aStatus)
375
 
{
376
 
  nsresult rv = NS_OK;
377
 
 
378
 
  DEBUG_LOG(("nsEnigMimeListener::OnStopRequest: (%p)\n", this));
379
 
 
380
 
  // Ensure that OnStopRequest call chain does not break by failing softly
381
 
 
382
 
  if (!mRequestStarted) {
383
 
 
384
 
    if (mHeadersFinalCR) {
385
 
      // Handle special case of terminating CR with no content
386
 
      mHeadersFinalCR = PR_FALSE;
387
 
 
388
 
      mLinebreak = "\r";
389
 
      mHeaders = mDataStr;
390
 
 
391
 
      if (mSkipHeaders) {
392
 
        // Skip headers
393
 
        mDataStr = "";
394
 
      }
395
 
    }
396
 
 
397
 
    rv = StartRequest(aRequest, aContext);
398
 
    if (NS_FAILED(rv))
399
 
      aStatus = NS_BINDING_ABORTED;
400
 
  }
401
 
 
402
 
  if (mDecoderData) {
403
 
    // Clear decoder buffer
404
 
    MimeDecoderDestroy(mDecoderData, PR_FALSE);
405
 
    mDecoderData = NULL;
406
 
  }
407
 
 
408
 
  if (mListener) {
409
 
    rv = mListener->OnStopRequest(aRequest,
410
 
                                  mContext ? mContext.get() : aContext,
411
 
                                  aStatus);
412
 
    if (NS_FAILED(rv))
413
 
      aStatus = NS_BINDING_ABORTED;
414
 
  }
415
 
 
416
 
  // Release owning refs
417
 
  mListener = NULL;
418
 
  mContext = NULL;
419
 
 
420
 
  return (aStatus == NS_BINDING_ABORTED) ? NS_ERROR_FAILURE : NS_OK;
421
 
}
422
 
 
423
 
///////////////////////////////////////////////////////////////////////////////
424
 
// nsIStreamListener method
425
 
///////////////////////////////////////////////////////////////////////////////
426
 
 
427
 
NS_IMETHODIMP
428
 
nsEnigMimeListener::OnDataAvailable(nsIRequest* aRequest,
429
 
                                    nsISupports* aContext,
430
 
                                    nsIInputStream *aInputStream,
431
 
#if MOZILLA_MAJOR_VERSION < 18
432
 
                                    PRUint32 aSourceOffset,
433
 
#else
434
 
                                    PRUint64 aSourceOffset,
435
 
#endif
436
 
                                    PRUint32 aLength)
437
 
{
438
 
  nsresult rv = NS_OK;
439
 
 
440
 
  DEBUG_LOG(("nsEnigMimeListener::OnDataAvailable: (%p) %d\n", this, aLength));
441
 
 
442
 
  if (!mInitialized)
443
 
    return NS_ERROR_NOT_INITIALIZED;
444
 
 
445
 
  char buf[kCharMax];
446
 
  PRUint32 readCount, readMax;
447
 
 
448
 
  while ((aLength > 0) && (!mRequestStarted || mDecoderData) ) {
449
 
    // Searching for headers or decoding content
450
 
 
451
 
    readMax = (aLength < kCharMax) ? aLength : kCharMax;
452
 
    rv = aInputStream->Read((char *) buf, readMax, &readCount);
453
 
    if (NS_FAILED(rv)){
454
 
      ERROR_LOG(("nsEnigMimeListener::OnDataAvailable: Error in reading from input stream, %x\n", rv));
455
 
      return rv;
456
 
    }
457
 
 
458
 
    if (readCount <= 0)
459
 
      break;
460
 
 
461
 
    aLength -= readCount;
462
 
    aSourceOffset += readCount;
463
 
 
464
 
    rv = Write(buf, readCount, aRequest, aContext);
465
 
    if (NS_FAILED(rv))
466
 
      return rv;
467
 
  }
468
 
 
469
 
  // Not searching for headers and not decoding content
470
 
  if (!mSkipBody && (aLength > 0) && mListener) {
471
 
    // Transmit body data unread
472
 
    rv = mListener->OnDataAvailable(aRequest,
473
 
                                    mContext ? mContext.get() : aContext,
474
 
                                    aInputStream, mDataOffset, aLength);
475
 
    mDataOffset += aLength;
476
 
 
477
 
    if (NS_FAILED(rv))
478
 
      return rv;
479
 
  }
480
 
 
481
 
  return NS_OK;
482
 
}
483
 
 
484
 
 
485
 
NS_IMETHODIMP
486
 
nsEnigMimeListener::StartRequest(nsIRequest* aRequest, nsISupports* aContext)
487
 
{
488
 
  nsresult rv;
489
 
 
490
 
  DEBUG_LOG(("nsEnigMimeListener::StartRequest: (%p)\n", this));
491
 
 
492
 
  if (!mHeaders.IsEmpty()) {
493
 
    // Try to parse headers
494
 
    ParseMimeHeaders(mHeaders.get(), mHeaders.Length());
495
 
  }
496
 
 
497
 
  if (mListener) {
498
 
    rv = mListener->OnStartRequest(aRequest,
499
 
                                   mContext ? mContext.get() : aContext);
500
 
    if (NS_FAILED(rv))
501
 
      return rv;
502
 
  }
503
 
 
504
 
  mRequestStarted = PR_TRUE;
505
 
 
506
 
  if (mHeaders.IsEmpty() && mSkipBody) {
507
 
    // No headers terminated and skipping body; so discard whatever we have
508
 
    mDataStr = "";
509
 
  }
510
 
 
511
 
  if (!mDataStr.IsEmpty()) {
512
 
    // Transmit header/body data already in buffer
513
 
    nsCAutoString temStr( mDataStr );
514
 
 
515
 
    mDataOffset += mDataStr.Length();
516
 
    mDataStr = "";
517
 
 
518
 
    rv = Transmit(temStr.get(), temStr.Length(), aRequest, aContext);
519
 
    if (NS_FAILED(rv))
520
 
      return rv;
521
 
  }
522
 
 
523
 
  return NS_OK;
524
 
}
525
 
 
526
 
 
527
 
EMBool
528
 
nsEnigMimeListener::HeaderSearch(const char* buf, PRUint32 count)
529
 
{
530
 
  DEBUG_LOG(("nsEnigMimeListener::HeaderSearch: (%p) count=%d\n", this, count));
531
 
 
532
 
  mHeaderSearchCounter++;
533
 
 
534
 
  if (mMaxHeaderBytes <= 0) {
535
 
    // Not looking for MIME headers; start request immediately
536
 
    return PR_TRUE;
537
 
  }
538
 
 
539
 
  if (!count)
540
 
    return PR_FALSE;
541
 
 
542
 
  PRUint32 bytesAvailable = mMaxHeaderBytes - mDataStr.Length();
543
 
  NS_ASSERTION(bytesAvailable > 0, "bytesAvailable <= 0");
544
 
 
545
 
  EMBool lastSegment = (bytesAvailable <= count);
546
 
 
547
 
  PRUint32 scanLen = lastSegment ? bytesAvailable : count;
548
 
 
549
 
  EMBool headersFound = PR_FALSE;
550
 
  PRUint32 offset = 0;
551
 
  PRUint32 startOffset = 0;
552
 
  PRUint32 j = 0;
553
 
  char ch;
554
 
  if (mSubPartTreatment) {
555
 
    // FIXME:
556
 
    // this is a HACK necessary because Mozilla does not deliver
557
 
    // a subpart starting with its headers (so we get the
558
 
    // part on a higher level and sort out things manually!)
559
 
    // there is (so far) no way to get the headers of an
560
 
    // arbitrary message mime part
561
 
    DEBUG_LOG(("nsEnigMimeListener::HeaderSearch: subparts treatment\n"));
562
 
    ch='\n';
563
 
    while(j<scanLen-3) {
564
 
      if (((ch=='\n') || (ch=='\r')) &&
565
 
          (buf[j]=='-') &&
566
 
          (buf[j+1]=='-') &&
567
 
          (buf[j+2]!='\n') &&
568
 
          (buf[j+2]!='\r'))
569
 
      {
570
 
          startOffset = j;
571
 
          DEBUG_LOG(("nsEnigMimeListener::HeaderSearch: startOffset=%d\n",startOffset));
572
 
          break;
573
 
      }
574
 
      ch=buf[j];
575
 
      j++;
576
 
    }
577
 
 
578
 
    // set j=startOffset needed if startOffset == 0!
579
 
    j=startOffset;
580
 
/*
581
 
    // Solution for how to do it, if the content-type info
582
 
    // would be available
583
 
    nsCAutoString cType("Content-Type: multipart/signed; micalg=pgp-sha1; protocol=\"application/pgp-signature\"; boundary=\"J2SCkAp4GZ/dPZZf\"\n\n");
584
 
    mDataStr.Append(cType.get(), cType.Length());
585
 
    mHeaders = cType;
586
 
    if (mSkipHeaders)
587
 
      mDataStr = "";
588
 
    if (!mSkipBody)
589
 
      mDataStr.Append(buf, count);
590
 
 
591
 
    mHeadersLinebreak = 0;
592
 
    mLinebreak = "\n";
593
 
*/
594
 
    mSubPartTreatment = PR_FALSE;
595
 
    // return PR_TRUE;
596
 
  }
597
 
 
598
 
  while (j<scanLen) {
599
 
    ch = buf[j];
600
 
 
601
 
    if (mHeadersFinalCR) {
602
 
      // End-of-headers found
603
 
      mHeadersFinalCR = PR_FALSE;
604
 
 
605
 
      if (ch == '\n') {
606
 
        offset = j+1;
607
 
        mLinebreak = "\r\n";
608
 
        DEBUG_LOG(("nsEnigMimeListener::HeaderSearch: Found final CRLF"));
609
 
 
610
 
      } else {
611
 
        offset = j;
612
 
        mLinebreak = "\r";
613
 
        DEBUG_LOG(("nsEnigMimeListener::HeaderSearch: Found final CR"));
614
 
      }
615
 
 
616
 
      headersFound = PR_TRUE;
617
 
      break;
618
 
 
619
 
    }
620
 
 
621
 
    if (ch == '\n') {
622
 
 
623
 
      if (mHeadersLinebreak == 2) {
624
 
        // End-of-headers found
625
 
        headersFound = PR_TRUE;
626
 
 
627
 
        offset = j+1;
628
 
        mLinebreak = "\n";
629
 
        DEBUG_LOG(("nsEnigMimeListener::HeaderSearch: Found final LF"));
630
 
        break;
631
 
      }
632
 
 
633
 
      mHeadersLinebreak = 2;
634
 
 
635
 
    } else if (ch == '\r') {
636
 
 
637
 
      if (mHeadersLinebreak > 0) {
638
 
        // Final CR
639
 
        mHeadersFinalCR = PR_TRUE;
640
 
      } else {
641
 
        mHeadersLinebreak = 1;
642
 
      }
643
 
 
644
 
    } else {
645
 
      mHeadersLinebreak = 0;
646
 
    }
647
 
 
648
 
    j++;
649
 
  }
650
 
 
651
 
  DEBUG_LOG(("nsEnigMimeListener::HeaderSearch: offset=%d\n", offset));
652
 
 
653
 
  if (headersFound) {
654
 
    // Copy headers out of stream buffer
655
 
    if (offset > 0)
656
 
      mDataStr.Append(buf+startOffset, offset-startOffset);
657
 
 
658
 
    mHeaders = mDataStr;
659
 
 
660
 
    if (mSkipHeaders) {
661
 
      // Skip headers
662
 
      mDataStr = "";
663
 
    }
664
 
 
665
 
    if (!mSkipBody && (offset < count)) {
666
 
      // Copy remaining data into stream buffer
667
 
     mDataStr.Append(buf+offset, count-offset);
668
 
    }
669
 
 
670
 
  } else if (!lastSegment) {
671
 
    // Save headers data
672
 
    mDataStr.Append(buf, count);
673
 
  }
674
 
 
675
 
  return headersFound || lastSegment;
676
 
}
677
 
 
678
 
static void
679
 
__ReplaceCSubstring (nsACString &string, const char* replace, const char* with)
680
 
{
681
 
        PRInt32 i = string.Find (replace);
682
 
        while ( i >= 0 ) {
683
 
        string.Replace (i, strlen (replace), with);
684
 
        i = string.Find (replace);
685
 
  }
686
 
}
687
 
 
688
 
static void
689
 
__ReplaceCChar (nsACString &string, const char replace, const char with)
690
 
{
691
 
        PRInt32 i = string.FindChar (replace);
692
 
  while (i >= 0 ) {
693
 
          string.Replace (i, 1, (const char*) &with, 1);
694
 
          i = string.FindChar (replace);
695
 
        }
696
 
}
697
 
 
698
 
void
699
 
nsEnigMimeListener::ParseMimeHeaders(const char* mimeHeaders, PRUint32 count)
700
 
{
701
 
  DEBUG_LOG(("nsEnigMimeListener::ParseMimeHeaders, count=%d\n", count));
702
 
 
703
 
  // Copy headers string
704
 
  nsCAutoString headers(mimeHeaders, count);
705
 
 
706
 
  // Replace CRLF with just LF
707
 
  __ReplaceCSubstring(headers, "\r\n", "\n");
708
 
 
709
 
  // Replace CR with LF (for MAC-style line endings)
710
 
  __ReplaceCChar(headers, '\r', '\n');
711
 
 
712
 
  // Eliminate all leading whitespace (including linefeeds)
713
 
  headers.Trim(" \t\n", PR_TRUE, PR_FALSE);
714
 
 
715
 
  if (headers.Length() <= 3) {
716
 
    // No headers to parse
717
 
    return;
718
 
  }
719
 
 
720
 
  // Handle continuation of MIME headers, i.e., newline followed by whitespace
721
 
  __ReplaceCSubstring(headers, "\n ",  " ");
722
 
  __ReplaceCSubstring(headers, "\n\t", "\t");
723
 
 
724
 
  //DEBUG_LOG(("nsEnigMimeListener::ParseMimeHeaders: headers='%s'\n", headers.get()));
725
 
 
726
 
  PRUint32 offset = 0;
727
 
  while (offset < headers.Length()) {
728
 
    PRInt32 lineEnd = headers.FindChar('\n', offset);
729
 
 
730
 
    if (lineEnd < 0) {
731
 
      // Header line terminator not found
732
 
      NS_NOTREACHED("lineEnd == kNotFound");
733
 
      return;
734
 
    }
735
 
 
736
 
    // Normal exit if empty header line
737
 
    if (lineEnd == (int)offset)
738
 
      break;
739
 
 
740
 
    // Parse header line
741
 
    ParseHeader((headers.get())+offset, lineEnd - offset);
742
 
 
743
 
    offset = lineEnd+1;
744
 
  }
745
 
 
746
 
  return;
747
 
}
748
 
 
749
 
void
750
 
nsEnigMimeListener::ParseHeader(const char* header, PRUint32 count)
751
 
{
752
 
 
753
 
  //DEBUG_LOG(("nsEnigMimeListener::ParseHeader: header='%s'\n", header));
754
 
 
755
 
  if (!header || (count <= 0) )
756
 
    return;
757
 
 
758
 
  // Create header string
759
 
  nsCAutoString headerStr(header, count);
760
 
 
761
 
  //DEBUG_LOG(("nsEnigMimeListener::ParseHeader: header='%s'\n", headerStr.get()));
762
 
  PRInt32 colonOffset;
763
 
  colonOffset = headerStr.FindChar(':');
764
 
  if (colonOffset < 0)
765
 
    return;
766
 
 
767
 
  // Null header key not allowed
768
 
  if (colonOffset == 0)
769
 
    return;
770
 
 
771
 
  // Extract header key (not case-sensitive)
772
 
  nsCAutoString headerKey = (nsCString) nsDependentCSubstring (headerStr, 0, colonOffset);
773
 
  ToLowerCase(headerKey);
774
 
 
775
 
 
776
 
  // Extract header value, trimming leading/trailing whitespace
777
 
  nsCAutoString buf = (nsCString) nsDependentCSubstring (headerStr, colonOffset+1, headerStr.Length() - colonOffset);
778
 
  buf.Trim(" ", PR_TRUE, PR_TRUE);
779
 
 
780
 
  //DEBUG_LOG(("nsEnigMimeListener::ParseHeader: '%s': %s\n", headerKey.get(), buf.get()));
781
 
 
782
 
  PRInt32 semicolonOffset = buf.FindChar(';');
783
 
 
784
 
  nsCString headerValue;
785
 
  if (semicolonOffset < 0) {
786
 
    // No parameters
787
 
    headerValue = ((nsCString)buf).get();
788
 
 
789
 
  } else {
790
 
    // Extract value to left of parameters
791
 
    headerValue = nsDependentCSubstring (buf, 0, semicolonOffset);
792
 
  }
793
 
 
794
 
  // Trim leading and trailing spaces in header value
795
 
  headerValue.Trim(" ", PR_TRUE, PR_TRUE);
796
 
 
797
 
  if (headerKey.Equals("content-type")) {
798
 
    mContentType = headerValue;
799
 
 
800
 
    DEBUG_LOG(("nsEnigMimeListener::ParseHeader: ContentType=%s\n",
801
 
               mContentType.get()));
802
 
 
803
 
    if (!buf.IsEmpty()) {
804
 
      char *charset  = MimeHeaders_get_parameter(buf.get(),
805
 
                              HEADER_PARM_CHARSET, NULL, NULL);
806
 
      char *boundary = MimeHeaders_get_parameter(buf.get(),
807
 
                              HEADER_PARM_BOUNDARY, NULL, NULL);
808
 
      char *protocol = MimeHeaders_get_parameter(buf.get(),
809
 
                              PARAM_PROTOCOL, NULL, NULL);
810
 
      char *micalg   = MimeHeaders_get_parameter(buf.get(),
811
 
                               PARAM_MICALG, NULL, NULL);
812
 
 
813
 
      if (charset)
814
 
        mContentCharset = charset;
815
 
 
816
 
      if (boundary)
817
 
        mContentBoundary = boundary;
818
 
 
819
 
      if (protocol)
820
 
        mContentProtocol = protocol;
821
 
 
822
 
      if (micalg)
823
 
        mContentMicalg = micalg;
824
 
 
825
 
      PR_FREEIF(charset);
826
 
      PR_FREEIF(boundary);
827
 
      PR_FREEIF(protocol);
828
 
      PR_FREEIF(micalg);
829
 
 
830
 
      DEBUG_LOG(("nsEnigMimeListener::ParseHeader: ContentCharset=%s\n",
831
 
                 mContentCharset.get()));
832
 
 
833
 
      DEBUG_LOG(("nsEnigMimeListener::ParseHeader: ContentBoundary=%s\n",
834
 
                 mContentBoundary.get()));
835
 
 
836
 
      DEBUG_LOG(("nsEnigMimeListener::ParseHeader: ContentProtocol=%s\n",
837
 
                 mContentProtocol.get()));
838
 
 
839
 
      DEBUG_LOG(("nsEnigMimeListener::ParseHeader: ContentMicalg=%s\n",
840
 
                 mContentMicalg.get()));
841
 
    }
842
 
 
843
 
  } else if (headerKey.Equals("content-transfer-encoding")) {
844
 
    mContentEncoding = buf;
845
 
    ToLowerCase(mContentEncoding);
846
 
 
847
 
    DEBUG_LOG(("nsEnigMimeListener::ParseHeader: ContentEncoding=%s\n",
848
 
               mContentEncoding.get()));
849
 
 
850
 
  } else if (headerKey.Equals("content-disposition")) {
851
 
    mContentDisposition = buf;
852
 
 
853
 
    DEBUG_LOG(("nsEnigMimeListener::ParseHeader: ContentDisposition=%s\n",
854
 
               mContentDisposition.get()));
855
 
 
856
 
  } else if (headerKey.Equals("content-length")) {
857
 
    nsresult status;
858
 
    PRInt32 value = headerValue.ToInteger(&status);
859
 
 
860
 
    if (NS_SUCCEEDED(status))
861
 
      mContentLength = value;
862
 
 
863
 
    DEBUG_LOG(("nsEnigMimeListener::ParseHeader: ContenLengtht=%d\n",
864
 
               mContentLength));
865
 
  }
866
 
 
867
 
  return;
868
 
}
869
 
 
870
 
 
871
 
///////////////////////////////////////////////////////////////////////////////
872
 
// nsIInputStream methods
873
 
///////////////////////////////////////////////////////////////////////////////
874
 
 
875
 
NS_IMETHODIMP
876
 
#if MOZILLA_MAJOR_VERSION < 17
877
 
nsEnigMimeListener::Available(PRUint32* _retval)
878
 
#else
879
 
nsEnigMimeListener::Available(PRUint64* _retval)
880
 
#endif
881
 
{
882
 
  if (!_retval)
883
 
    return NS_ERROR_NULL_POINTER;
884
 
 
885
 
  *_retval = (mStreamLength > mStreamOffset) ?
886
 
              mStreamLength - mStreamOffset : 0;
887
 
 
888
 
  DEBUG_LOG(("nsEnigMimeListener::Available: (%p) %d\n", this, *_retval));
889
 
 
890
 
  return NS_OK;
891
 
}
892
 
 
893
 
NS_IMETHODIMP
894
 
nsEnigMimeListener::Read(char* buf, PRUint32 count,
895
 
                         PRUint32 *readCount)
896
 
{
897
 
  DEBUG_LOG(("nsEnigMimeListener::Read: (%p) %d\n", this, count));
898
 
 
899
 
  if (!buf || !readCount)
900
 
    return NS_ERROR_NULL_POINTER;
901
 
 
902
 
  PRInt32 avail = (mStreamLength > mStreamOffset) ?
903
 
                   mStreamLength - mStreamOffset : 0;
904
 
 
905
 
  *readCount = ((PRUint32) avail > count) ? count : avail;
906
 
 
907
 
  if (*readCount) {
908
 
    memcpy(buf, mStreamBuf+mStreamOffset, *readCount);
909
 
    mStreamOffset += *readCount;
910
 
  }
911
 
 
912
 
  if (mStreamOffset >= mStreamLength) {
913
 
    Close();
914
 
  }
915
 
 
916
 
  return NS_OK;
917
 
}
918
 
 
919
 
NS_IMETHODIMP
920
 
nsEnigMimeListener::ReadSegments(nsWriteSegmentFun writer,
921
 
                                 void * aClosure, PRUint32 count,
922
 
                                 PRUint32 *readCount)
923
 
{
924
 
  DEBUG_LOG(("nsEnigMimeListener::ReadSegments: %d\n", count));
925
 
 
926
 
  if (!readCount)
927
 
    return NS_ERROR_NULL_POINTER;
928
 
 
929
 
  PRInt32 avail = (mStreamLength > mStreamOffset) ?
930
 
                   mStreamLength - mStreamOffset : 0;
931
 
 
932
 
  PRUint32 readyCount = ((PRUint32) avail > count) ? count : avail;
933
 
 
934
 
  if (!readyCount) {
935
 
    *readCount = 0;
936
 
 
937
 
  } else {
938
 
    nsresult rv = writer((nsIInputStream*)(this),
939
 
                         aClosure, mStreamBuf+mStreamOffset,
940
 
                         mStreamOffset, readyCount, readCount);
941
 
    if (NS_FAILED(rv))
942
 
      return rv;
943
 
 
944
 
    mStreamOffset += *readCount;
945
 
  }
946
 
 
947
 
  if (mStreamOffset >= mStreamLength) {
948
 
    Close();
949
 
  }
950
 
 
951
 
  return NS_OK;
952
 
}
953
 
 
954
 
NS_IMETHODIMP
955
 
nsEnigMimeListener::IsNonBlocking(EMBool *aNonBlocking)
956
 
{
957
 
  DEBUG_LOG(("nsEnigMimeListener::IsNonBlocking: \n"));
958
 
 
959
 
  *aNonBlocking = PR_TRUE;
960
 
  return NS_OK;
961
 
}
962
 
 
963
 
NS_IMETHODIMP
964
 
nsEnigMimeListener::GetSubPartTreatment(EMBool* aSubPartTreatment)
965
 
{
966
 
  *aSubPartTreatment = mSubPartTreatment;
967
 
  return NS_OK;
968
 
}
969
 
 
970
 
NS_IMETHODIMP
971
 
nsEnigMimeListener::SetSubPartTreatment(EMBool aSubPartTreatment)
972
 
{
973
 
  DEBUG_LOG(("nsEnigMimeListener::SetSubPartTreatment: %d\n", aSubPartTreatment));
974
 
 
975
 
  mSubPartTreatment = aSubPartTreatment;
976
 
  return NS_OK;
977
 
}
978
 
 
979
 
NS_IMETHODIMP
980
 
nsEnigMimeListener::Close()
981
 
{
982
 
  DEBUG_LOG(("nsEnigMimeListener::Close: (%p)\n", this));
983
 
  mStreamBuf = NULL;
984
 
  mStreamOffset = 0;
985
 
  mStreamLength = 0;
986
 
  return NS_OK;
987
 
}