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

« back to all changes in this revision

Viewing changes to extensions/enigmail/src/nsEnigMsgCompose.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 "nsStringAPI.h"
42
 
#include "nsIMsgCompFields.h"
43
 
#include "nsIMsgWindow.h"
44
 
#include "nsMsgBaseCID.h"
45
 
#include "nsMsgCompCID.h"
46
 
#include "nsIMsgMailSession.h"
47
 
#include "nsIEnigMsgCompFields.h"
48
 
#include "nsEnigMsgCompose.h"
49
 
#include "nspr.h"
50
 
#include "nsCOMPtr.h"
51
 
#include "nsIPrompt.h"
52
 
#include "nsNetUtil.h"
53
 
#include "nsIThread.h"
54
 
#include "msgCore.h"
55
 
#include "nsComposeStrings.h"
56
 
#undef MOZILLA_INTERNAL_API
57
 
 
58
 
#ifdef PR_LOGGING
59
 
PRLogModuleInfo* gEnigMsgComposeLog = NULL;
60
 
#endif
61
 
 
62
 
#define ERROR_LOG(args)    PR_LOG(gEnigMsgComposeLog,PR_LOG_ERROR,args)
63
 
#define WARNING_LOG(args)  PR_LOG(gEnigMsgComposeLog,PR_LOG_WARNING,args)
64
 
#define DEBUG_LOG(args)    PR_LOG(gEnigMsgComposeLog,PR_LOG_DEBUG,args)
65
 
 
66
 
#define NS_MSGCOMPOSESECURE_CID                    \
67
 
{ /* dd753201-9a23-4e08-957f-b3616bf7e012 */       \
68
 
   0xdd753201, 0x9a23, 0x4e08,                     \
69
 
  {0x95, 0x7f, 0xb3, 0x61, 0x6b, 0xf7, 0xe0, 0x12 }}
70
 
 
71
 
static NS_DEFINE_CID(kMsgComposeSecureCID, NS_MSGCOMPOSESECURE_CID);
72
 
 
73
 
#define MAX_HEADER_BYTES 16000
74
 
#define MAX_SIGNATURE_BYTES 16000
75
 
 
76
 
static const PRUint32 kCharMax = 1024;
77
 
 
78
 
// nsEnigMsgCompose implementation
79
 
 
80
 
const char* nsEnigMsgCompose::FromStr = "From ";
81
 
EMBool nsEnigMsgCompose::mRandomSeeded = PR_FALSE;
82
 
 
83
 
// nsISupports implementation
84
 
NS_IMPL_THREADSAFE_ISUPPORTS3(nsEnigMsgCompose,
85
 
                              nsIMsgComposeSecure,
86
 
                              nsIRequestObserver,
87
 
                              nsIStreamListener)
88
 
 
89
 
// nsEnigMsgCompose implementation
90
 
nsEnigMsgCompose::nsEnigMsgCompose()
91
 
  : mInitialized(PR_FALSE),
92
 
    mUseSMIME(PR_FALSE),
93
 
    mIsDraft(PR_FALSE),
94
 
    mRequestStopped(PR_FALSE),
95
 
 
96
 
    mLinebreak(PR_TRUE),
97
 
    mSpace(0),
98
 
    mMatchFrom(0),
99
 
 
100
 
    mInputLen(0),
101
 
    mOutputLen(0),
102
 
 
103
 
    mSendFlags(0),
104
 
    mUIFlags(0),
105
 
 
106
 
    mMultipartSigned(PR_FALSE),
107
 
    mStripWhitespace(PR_FALSE),
108
 
 
109
 
    mSenderEmailAddr(""),
110
 
    mRecipients(""),
111
 
    mBccAddr(""),
112
 
    mHashAlgorithm("sha1"),
113
 
 
114
 
    mBoundary(""),
115
 
 
116
 
    mStream(0),
117
 
 
118
 
    mEncoderData(NULL),
119
 
 
120
 
    mMsgComposeSecure(NULL),
121
 
    mMimeListener(NULL),
122
 
 
123
 
    mWriter(NULL),
124
 
    mPipeTrans(NULL)
125
 
{
126
 
  nsresult rv;
127
 
 
128
 
  NS_INIT_ISUPPORTS();
129
 
 
130
 
#ifdef PR_LOGGING
131
 
  if (gEnigMsgComposeLog == NULL) {
132
 
    gEnigMsgComposeLog = PR_NewLogModule("nsEnigMsgCompose");
133
 
  }
134
 
#endif
135
 
 
136
 
  // Remember to use original CID, not CONTRACTID, to avoid infinite looping!
137
 
  mMsgComposeSecure = do_CreateInstance(kMsgComposeSecureCID, &rv);
138
 
 
139
 
#ifdef FORCE_PR_LOG
140
 
  nsCOMPtr<nsIThread> myThread;
141
 
  rv = ENIG_GET_THREAD(myThread);
142
 
  DEBUG_LOG(("nsEnigMsgCompose:: <<<<<<<<< CTOR(%p): myThread=%p\n",
143
 
         this, myThread.get()));
144
 
#endif
145
 
}
146
 
 
147
 
 
148
 
nsEnigMsgCompose::~nsEnigMsgCompose()
149
 
{
150
 
  nsresult rv;
151
 
#ifdef FORCE_PR_LOG
152
 
  nsCOMPtr<nsIThread> myThread;
153
 
  rv = ENIG_GET_THREAD(myThread);
154
 
  DEBUG_LOG(("nsEnigMsgCompose:: >>>>>>>>> DTOR(%p): myThread=%p\n",
155
 
         this, myThread.get()));
156
 
#endif
157
 
 
158
 
  Finalize();
159
 
 
160
 
}
161
 
 
162
 
nsresult
163
 
nsEnigMsgCompose::Finalize()
164
 
{
165
 
  DEBUG_LOG(("nsEnigMsgCompose::Finalize:\n"));
166
 
 
167
 
  mMsgComposeSecure = NULL;
168
 
  mMimeListener = NULL;
169
 
 
170
 
  if (mPipeTrans) {
171
 
    mPipeTrans->Terminate();
172
 
    mPipeTrans = NULL;
173
 
  }
174
 
 
175
 
  if (mWriter) {
176
 
    mWriter->Close();
177
 
    mWriter = NULL;
178
 
  }
179
 
 
180
 
  if (mEncoderData) {
181
 
    // Clear encoder buffer
182
 
    MimeEncoderDestroy(mEncoderData, PR_FALSE);
183
 
    mEncoderData = NULL;
184
 
  }
185
 
 
186
 
  return NS_OK;
187
 
}
188
 
 
189
 
 
190
 
nsresult
191
 
nsEnigMsgCompose::GetRandomTime(PRUint32 *_retval)
192
 
{
193
 
  if (!*_retval)
194
 
    return NS_ERROR_NULL_POINTER;
195
 
 
196
 
  // Current local time (microsecond resolution)
197
 
  PRExplodedTime localTime;
198
 
  PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &localTime);
199
 
 
200
 
  PRUint32       randomNumberA = localTime.tm_sec*1000000+localTime.tm_usec;
201
 
 
202
 
  // Elapsed time (1 millisecond to 10 microsecond resolution)
203
 
  PRIntervalTime randomNumberB = PR_IntervalNow();
204
 
 
205
 
  DEBUG_LOG(("nsEnigMsgCompose::GetRandomTime: ranA=0x%p, ranB=0x%p\n",
206
 
                                           randomNumberA, randomNumberB));
207
 
 
208
 
  *_retval = ((randomNumberA & 0xFFFFF) << 12) | (randomNumberB & 0xFFF);
209
 
 
210
 
  return NS_OK;
211
 
}
212
 
 
213
 
 
214
 
nsresult
215
 
nsEnigMsgCompose::MakeBoundary(const char *prefix)
216
 
{
217
 
  DEBUG_LOG(("nsEnigMsgCompose::MakeBoundary:\n"));
218
 
 
219
 
  nsresult rv;
220
 
 
221
 
  if (!mRandomSeeded) {
222
 
    PRUint32 ranTime = 1;
223
 
 
224
 
    rv = GetRandomTime(&ranTime);
225
 
    if (NS_FAILED(rv))
226
 
      return rv;
227
 
 
228
 
    srand( ranTime );
229
 
    mRandomSeeded = PR_TRUE;
230
 
  }
231
 
 
232
 
 
233
 
  unsigned char ch[13];
234
 
  for( PRUint32 j = 0; j < 12; j++)
235
 
    ch[j] = rand() % 256;
236
 
 
237
 
  char* boundary = PR_smprintf("------------%s"
238
 
           "%02X%02X%02X%02X"
239
 
           "%02X%02X%02X%02X"
240
 
           "%02X%02X%02X%02X",
241
 
           prefix,
242
 
           ch[0], ch[1], ch[2], ch[3],
243
 
           ch[4], ch[5], ch[6], ch[7],
244
 
           ch[8], ch[9], ch[10], ch[11]);
245
 
 
246
 
  if (!boundary)
247
 
    return NS_ERROR_OUT_OF_MEMORY;
248
 
 
249
 
  DEBUG_LOG(("nsEnigMsgCompose::MakeBoundary: boundary='%s'\n",
250
 
         boundary));
251
 
 
252
 
 
253
 
  mBoundary = boundary;
254
 
 
255
 
  PR_Free(boundary);
256
 
 
257
 
  return NS_OK;
258
 
}
259
 
 
260
 
nsresult
261
 
nsEnigMsgCompose::WriteEncryptedHeaders()
262
 
{
263
 
  nsresult rv;
264
 
  DEBUG_LOG(("nsEnigMsgCompose::WriteEncryptedHeaders:\n"));
265
 
 
266
 
  rv = MakeBoundary("enig");
267
 
  if (NS_FAILED(rv))
268
 
    return rv;
269
 
 
270
 
  char* headers = PR_smprintf(
271
 
 "Content-Type: multipart/encrypted;\r\n"
272
 
 " protocol=\"application/pgp-encrypted\";\r\n"
273
 
 " boundary=\"%s\"\r\n"
274
 
 "\r\n"
275
 
 "This is an OpenPGP/MIME encrypted message (RFC 2440 and 3156)\r\n"
276
 
 "--%s\r\n"
277
 
 "Content-Type: application/pgp-encrypted\r\n"
278
 
 "Content-Description: PGP/MIME version identification\r\n"
279
 
 "\r\n"
280
 
 "Version: 1\r\n"
281
 
 "\r\n"
282
 
 "--%s\r\n"
283
 
 "Content-Type: application/octet-stream; name=\"encrypted.asc\"\r\n"
284
 
 "Content-Description: OpenPGP encrypted message\r\n"
285
 
 "Content-Disposition: inline; filename=\"encrypted.asc\"\r\n"
286
 
 "\r\n",
287
 
 mBoundary.get(), mBoundary.get(), mBoundary.get());
288
 
 
289
 
  if (!headers)
290
 
    return NS_ERROR_OUT_OF_MEMORY;
291
 
 
292
 
  rv = WriteOut(headers, strlen(headers));
293
 
 
294
 
  PR_Free(headers);
295
 
 
296
 
  return rv;
297
 
}
298
 
 
299
 
nsresult
300
 
nsEnigMsgCompose::WriteSignedHeaders1(EMBool isEightBit)
301
 
{
302
 
  nsresult rv;
303
 
  DEBUG_LOG(("nsEnigMsgCompose::WriteSignedHeaders1: %d\n", (int) isEightBit));
304
 
 
305
 
  rv = MakeBoundary("enig");
306
 
  if (NS_FAILED(rv))
307
 
    return rv;
308
 
 
309
 
  char* headers = PR_smprintf(
310
 
       "Content-Type: multipart/signed; micalg=pgp-%s;\r\n"
311
 
       " protocol=\"application/pgp-signature\";\r\n"
312
 
       " boundary=\"%s\"\r\n"
313
 
       "%s"
314
 
       "This is an OpenPGP/MIME signed message (RFC 2440 and 3156)\r\n"
315
 
       "--%s\r\n",
316
 
       mHashAlgorithm.get(), mBoundary.get(),
317
 
       isEightBit ? "Content-Transfer-Encoding: 8bit\r\n\r\n" : "\r\n",
318
 
       mBoundary.get());
319
 
 
320
 
  if (!headers)
321
 
    return NS_ERROR_OUT_OF_MEMORY;
322
 
 
323
 
  rv = WriteOut(headers, strlen(headers));
324
 
 
325
 
  PR_Free(headers);
326
 
 
327
 
  return rv;
328
 
}
329
 
 
330
 
nsresult
331
 
nsEnigMsgCompose::WriteSignedHeaders2()
332
 
{
333
 
  nsresult rv;
334
 
  DEBUG_LOG(("nsEnigMsgCompose::WriteSignedHeaders2:\n"));
335
 
 
336
 
  char* headers = PR_smprintf(
337
 
 "\r\n--%s\r\n"
338
 
 "Content-Type: application/pgp-signature; name=\"signature.asc\"\r\n"
339
 
 "Content-Description: OpenPGP digital signature\r\n"
340
 
 "Content-Disposition: attachment; filename=\"signature.asc\"\r\n"
341
 
 "\r\n",
342
 
 mBoundary.get());
343
 
 
344
 
  if (!headers)
345
 
    return NS_ERROR_OUT_OF_MEMORY;
346
 
 
347
 
  rv = WriteOut(headers, strlen(headers));
348
 
 
349
 
  PR_Free(headers);
350
 
 
351
 
  return rv;
352
 
}
353
 
 
354
 
nsresult
355
 
nsEnigMsgCompose::WriteFinalSeparator()
356
 
{
357
 
  nsresult rv;
358
 
  DEBUG_LOG(("nsEnigMsgCompose::WriteSeparator:\n"));
359
 
 
360
 
  if (mBoundary.IsEmpty())
361
 
    return NS_OK;
362
 
 
363
 
  // Write out final MIME multipart separator
364
 
  char* separator = PR_smprintf(
365
 
 "\r\n--%s--\r\n",
366
 
 mBoundary.get());
367
 
 
368
 
  if (!separator)
369
 
    return NS_ERROR_OUT_OF_MEMORY;
370
 
 
371
 
  rv = WriteOut(separator, strlen(separator));
372
 
 
373
 
  PR_Free(separator);
374
 
 
375
 
  return rv;
376
 
}
377
 
 
378
 
nsresult
379
 
nsEnigMsgCompose::Init()
380
 
{
381
 
  nsresult rv;
382
 
 
383
 
  DEBUG_LOG(("nsEnigMsgCompose::Init: sendFlags=%p\n", mSendFlags));
384
 
 
385
 
  EMBool signMsg    = mSendFlags & nsIEnigmail::SEND_SIGNED;
386
 
  EMBool encryptMsg = mSendFlags & nsIEnigmail::SEND_ENCRYPTED;
387
 
  EMBool usePgpMime = mSendFlags & nsIEnigmail::SEND_PGP_MIME;
388
 
 
389
 
  mMultipartSigned = usePgpMime && signMsg && !encryptMsg;
390
 
 
391
 
  mWriter = do_CreateInstance(NS_ENIGMIMEWRITER_CONTRACTID, &rv);
392
 
  if (NS_FAILED(rv)) return rv;
393
 
 
394
 
  rv = mWriter->Init(mStream, PR_TRUE);
395
 
  if (NS_FAILED(rv)) return rv;
396
 
 
397
 
  nsCOMPtr<nsIPrompt> prompter;
398
 
  nsCOMPtr <nsIMsgMailSession> mailSession (do_GetService(NS_MSGMAILSESSION_CONTRACTID));
399
 
  if (mailSession) {
400
 
    nsCOMPtr<nsIMsgWindow> msgWindow;
401
 
    mailSession->GetTopmostMsgWindow(getter_AddRefs(msgWindow));
402
 
    if (msgWindow)
403
 
      msgWindow->GetPromptDialog(getter_AddRefs(prompter));
404
 
  }
405
 
 
406
 
  nsCOMPtr<nsIEnigmail> enigmailSvc = do_GetService(NS_ENIGMAIL_CONTRACTID, &rv);
407
 
  if (NS_FAILED(rv)) return rv;
408
 
 
409
 
  if (usePgpMime && signMsg && (! encryptMsg)) {
410
 
    // determine hash algorithm to use for PGP/MIME signed msg
411
 
    PRInt32 exitCode;
412
 
    PRUnichar* ha;
413
 
 
414
 
    rv = enigmailSvc->DetermineHashAlgorithm(prompter,
415
 
                                             mUIFlags,
416
 
                                             mSenderEmailAddr.get(),
417
 
                                             &ha,
418
 
                                             &exitCode);
419
 
 
420
 
    DEBUG_LOG(("nsEnigMsgCompose::Init: DetermineHash: rv=%d, exitCode=%d\n", rv, exitCode));
421
 
 
422
 
    if (NS_FAILED(rv))
423
 
      return rv;
424
 
 
425
 
    if (exitCode != 0)
426
 
      return NS_ERROR_SMTP_PASSWORD_UNDEFINED;
427
 
 
428
 
    mHashAlgorithm = NS_ConvertUTF16toUTF8(ha).get();
429
 
    DEBUG_LOG(("nsEnigMsgCompose::Init: hashAlgorithm=%s\n", mHashAlgorithm.get()));
430
 
  }
431
 
 
432
 
  nsString errorMsg;
433
 
  PRUint32 statusFlags;
434
 
  rv = enigmailSvc->EncryptMessageStart(NULL, prompter,
435
 
                                        mUIFlags,
436
 
                                        mSenderEmailAddr.get(),
437
 
                                        mRecipients.get(),
438
 
                                        mBccAddr.get(),
439
 
                                        mHashAlgorithm.get(),
440
 
                                        mSendFlags,
441
 
                                        (nsIStreamListener*)(mWriter),
442
 
                                        &statusFlags,
443
 
                                        getter_Copies(errorMsg),
444
 
                                        getter_AddRefs(mPipeTrans) );
445
 
  if (NS_FAILED(rv))
446
 
    return rv;
447
 
 
448
 
  if (statusFlags & nsIEnigmail::MISSING_PASSPHRASE)
449
 
    return NS_ERROR_SMTP_PASSWORD_UNDEFINED;
450
 
 
451
 
  if (!mPipeTrans)
452
 
    return NS_OK;
453
 
 
454
 
  rv = enigmailSvc->StripWhitespace(mSendFlags,
455
 
                                    &mStripWhitespace);
456
 
  if (NS_FAILED(rv))
457
 
    return rv;
458
 
 
459
 
  mInitialized = PR_TRUE;
460
 
 
461
 
  return NS_OK;
462
 
}
463
 
 
464
 
///////////////////////////////////////////////////////////////////////////////
465
 
// nsIMsgComposeSecure methods:
466
 
///////////////////////////////////////////////////////////////////////////////
467
 
 
468
 
NS_IMETHODIMP
469
 
nsEnigMsgCompose::RequiresCryptoEncapsulation(
470
 
                                        nsIMsgIdentity* aIdentity,
471
 
                                        nsIMsgCompFields* aCompFields,
472
 
                                        EMBool* aRequiresEncryptionWork)
473
 
{
474
 
  nsresult rv;
475
 
  DEBUG_LOG(("nsEnigMsgCompose::RequiresCryptoEncapsulation: \n"));
476
 
 
477
 
  if (!mMsgComposeSecure)
478
 
    return NS_ERROR_FAILURE;
479
 
 
480
 
  rv = mMsgComposeSecure->RequiresCryptoEncapsulation(aIdentity,
481
 
                                                      aCompFields,
482
 
                                                      &mUseSMIME);
483
 
  if (NS_FAILED(rv))
484
 
    return rv;
485
 
 
486
 
  if (mUseSMIME) {
487
 
    DEBUG_LOG(("nsEnigMsgCompose::RequiresCryptoEncapsulation: Using SMIME\n"));
488
 
    *aRequiresEncryptionWork = PR_TRUE;
489
 
    return NS_OK;
490
 
  }
491
 
 
492
 
  // Enigmail stuff
493
 
#ifdef __gen_nsIMsgSecurityInfo_h__
494
 
  nsCOMPtr<nsIMsgSecurityInfo> securityInfo;
495
 
#else
496
 
  nsCOMPtr<nsISupports> securityInfo;
497
 
#endif
498
 
 
499
 
  rv = aCompFields->GetSecurityInfo(getter_AddRefs(securityInfo));
500
 
  if (NS_FAILED(rv))
501
 
    return rv;
502
 
 
503
 
  if (!securityInfo) {
504
 
    DEBUG_LOG(("nsEnigMsgCompose::RequiresCryptoEncapsulation: no crypto required\n"));
505
 
    *aRequiresEncryptionWork = PR_FALSE;
506
 
    return NS_OK;
507
 
  }
508
 
 
509
 
  nsCOMPtr<nsIEnigMsgCompFields> enigSecurityInfo = do_QueryInterface(securityInfo);
510
 
 
511
 
  if (enigSecurityInfo) {
512
 
    PRUint32 sendFlags;
513
 
    rv = enigSecurityInfo->GetSendFlags(&sendFlags);
514
 
    if (NS_FAILED(rv))
515
 
      return rv;
516
 
 
517
 
    *aRequiresEncryptionWork = sendFlags &
518
 
      (nsIEnigmail::SEND_SIGNED | nsIEnigmail::SEND_ENCRYPTED);
519
 
 
520
 
  } else {
521
 
    DEBUG_LOG(("nsEnigMsgCompose::RequiresCryptoEncapsulation: no Enigmail crypto required\n"));
522
 
    *aRequiresEncryptionWork = PR_FALSE;
523
 
  }
524
 
 
525
 
  return NS_OK;
526
 
}
527
 
 
528
 
 
529
 
NS_IMETHODIMP
530
 
nsEnigMsgCompose::BeginCryptoEncapsulation(
531
 
                                        nsIOutputStream* aStream,
532
 
                                        const char* aRecipients,
533
 
                                        nsIMsgCompFields* aCompFields,
534
 
                                        nsIMsgIdentity* aIdentity,
535
 
                                        nsIMsgSendReport* sendReport,
536
 
                                        EMBool aIsDraft)
537
 
{
538
 
  nsresult rv;
539
 
 
540
 
  DEBUG_LOG(("nsEnigMsgCompose::BeginCryptoEncapsulation: %s\n", aRecipients));
541
 
 
542
 
  if (!mMsgComposeSecure) {
543
 
    ERROR_LOG(("nsEnigMsgCompose::BeginCryptoEncapsulation: ERROR MsgComposeSecure not instantiated\n"));
544
 
    return NS_ERROR_FAILURE;
545
 
  }
546
 
 
547
 
  if (mUseSMIME) {
548
 
    return mMsgComposeSecure->BeginCryptoEncapsulation(aStream, aRecipients,
549
 
                                                       aCompFields, aIdentity,
550
 
                                                       sendReport, aIsDraft);
551
 
  }
552
 
 
553
 
  if (!aStream)
554
 
    return NS_ERROR_NULL_POINTER;
555
 
 
556
 
  // Enigmail stuff
557
 
  mStream = aStream;
558
 
  mIsDraft = aIsDraft;
559
 
 
560
 
#ifdef __gen_nsIMsgSecurityInfo_h__
561
 
  nsCOMPtr<nsIMsgSecurityInfo> securityInfo;
562
 
#else
563
 
  nsCOMPtr<nsISupports> securityInfo;
564
 
#endif
565
 
 
566
 
  rv = aCompFields->GetSecurityInfo(getter_AddRefs(securityInfo));
567
 
  if (NS_FAILED(rv))
568
 
    return rv;
569
 
 
570
 
  if (!securityInfo)
571
 
    return NS_ERROR_FAILURE;
572
 
 
573
 
  nsCOMPtr<nsIEnigMsgCompFields> enigSecurityInfo = do_QueryInterface(securityInfo);
574
 
 
575
 
  if (!enigSecurityInfo)
576
 
    return NS_ERROR_FAILURE;
577
 
 
578
 
  rv = enigSecurityInfo->GetSendFlags(&mSendFlags);
579
 
  if (NS_FAILED(rv))
580
 
      return rv;
581
 
 
582
 
  rv = enigSecurityInfo->GetUIFlags(&mUIFlags);
583
 
  if (NS_FAILED(rv))
584
 
      return rv;
585
 
 
586
 
  rv = enigSecurityInfo->GetSenderEmailAddr(mSenderEmailAddr);
587
 
  if (NS_FAILED(rv))
588
 
      return rv;
589
 
 
590
 
  rv = enigSecurityInfo->GetRecipients(mRecipients);
591
 
  if (NS_FAILED(rv))
592
 
      return rv;
593
 
 
594
 
  rv = enigSecurityInfo->GetBccRecipients(mBccAddr);
595
 
  if (NS_FAILED(rv))
596
 
      return rv;
597
 
 
598
 
  rv = enigSecurityInfo->GetHashAlgorithm(mHashAlgorithm);
599
 
  if (NS_FAILED(rv))
600
 
      return rv;
601
 
 
602
 
 
603
 
  // Create listener to intercept MIME headers
604
 
  mMimeListener = do_CreateInstance(NS_ENIGMIMELISTENER_CONTRACTID, &rv);
605
 
  if (NS_FAILED(rv)) return rv;
606
 
 
607
 
  rv = mMimeListener->Init((nsIStreamListener*) this, NULL,
608
 
                           MAX_HEADER_BYTES, PR_TRUE, PR_FALSE, PR_FALSE);
609
 
  if (NS_FAILED(rv)) return rv;
610
 
 
611
 
  return NS_OK;
612
 
}
613
 
 
614
 
 
615
 
NS_IMETHODIMP
616
 
nsEnigMsgCompose::FinishCryptoEncapsulation(EMBool aAbort,
617
 
                                            nsIMsgSendReport* sendReport)
618
 
{
619
 
  nsresult rv;
620
 
 
621
 
  DEBUG_LOG(("nsEnigMsgCompose::FinishCryptoEncapsulation: \n"));
622
 
 
623
 
  if (!mMsgComposeSecure)
624
 
    return NS_ERROR_NOT_INITIALIZED;
625
 
 
626
 
  if (mUseSMIME) {
627
 
    return mMsgComposeSecure->FinishCryptoEncapsulation(aAbort, sendReport);
628
 
  }
629
 
 
630
 
  // Enigmail stuff
631
 
  if (!mInitialized || !mPipeTrans)
632
 
    return NS_ERROR_NOT_INITIALIZED;
633
 
 
634
 
  rv = FinishAux(aAbort, sendReport);
635
 
  if (NS_FAILED(rv)) {
636
 
    Finalize();
637
 
    return rv;
638
 
  }
639
 
 
640
 
  return NS_OK;
641
 
}
642
 
 
643
 
nsresult
644
 
nsEnigMsgCompose::FinishAux(EMBool aAbort,
645
 
                            nsIMsgSendReport* sendReport)
646
 
{
647
 
  nsresult rv;
648
 
 
649
 
  if (mMatchFrom > 0) {
650
 
    // Flush "buffer" for detecting lines beginning with "From "
651
 
    rv = WriteCopy(FromStr, mMatchFrom);
652
 
    if (NS_FAILED(rv)) return rv;
653
 
  }
654
 
 
655
 
  DEBUG_LOG(("nsEnigMsgCompose::FinishAux: \n"));
656
 
 
657
 
  if (mMultipartSigned) {
658
 
    rv = WriteSignedHeaders2();
659
 
    if (NS_FAILED(rv)) return rv;
660
 
  }
661
 
 
662
 
  // Wait for STDOUT to close
663
 
  rv = mPipeTrans->Join();
664
 
  if (NS_FAILED(rv)) return rv;
665
 
 
666
 
  if (aAbort) {
667
 
    // Terminate process
668
 
    mPipeTrans->Terminate();
669
 
    mPipeTrans = NULL;
670
 
 
671
 
    return NS_ERROR_FAILURE;
672
 
  }
673
 
 
674
 
  rv = WriteFinalSeparator();
675
 
  if (NS_FAILED(rv)) return rv;
676
 
 
677
 
  // Count total bytes sent to writer
678
 
  PRUint32 cmdOutputLen;
679
 
  rv = mWriter->GetBytesWritten(&cmdOutputLen);
680
 
  if (NS_FAILED(rv)) return rv;
681
 
 
682
 
  // Exclude passthru bytes to determine STDOUT bytes
683
 
  cmdOutputLen -= mOutputLen;
684
 
 
685
 
  // Close STDOUT writer
686
 
  mWriter->Close();
687
 
  mWriter = NULL;
688
 
 
689
 
  nsCOMPtr<nsIPrompt> prompter;
690
 
  nsCOMPtr <nsIMsgMailSession> mailSession (do_GetService(NS_MSGMAILSESSION_CONTRACTID));
691
 
  if (mailSession) {
692
 
    nsCOMPtr<nsIMsgWindow> msgWindow;
693
 
    mailSession->GetTopmostMsgWindow(getter_AddRefs(msgWindow));
694
 
    if (msgWindow)
695
 
      msgWindow->GetPromptDialog(getter_AddRefs(prompter));
696
 
  }
697
 
 
698
 
  nsCOMPtr<nsIEnigmail> enigmailSvc = do_GetService(NS_ENIGMAIL_CONTRACTID, &rv);
699
 
  if (NS_FAILED(rv)) return rv;
700
 
 
701
 
  PRInt32 exitCode;
702
 
  PRUint32 statusFlags;
703
 
  nsString errorMsg;
704
 
  rv = enigmailSvc->EncryptMessageEnd(NULL,
705
 
                                      prompter,
706
 
                                      mUIFlags,
707
 
                                      mSendFlags,
708
 
                                      cmdOutputLen,
709
 
                                      mPipeTrans,
710
 
                                      &statusFlags,
711
 
                                      getter_Copies(errorMsg),
712
 
                                      &exitCode);
713
 
  if (NS_FAILED(rv)) return rv;
714
 
 
715
 
  if (exitCode != 0) {
716
 
    DEBUG_LOG(("nsEnigMsgCompose::FinishAux: ERROR EXIT %d\n", exitCode));
717
 
    return NS_ERROR_FAILURE;
718
 
  }
719
 
 
720
 
  return NS_OK;
721
 
}
722
 
 
723
 
 
724
 
NS_IMETHODIMP
725
 
nsEnigMsgCompose::MimeCryptoWriteBlock(const char *aBuf, PRInt32 aLen)
726
 
{
727
 
  nsresult rv;
728
 
 
729
 
  DEBUG_LOG(("nsEnigMsgCompose::MimeCryptoWriteBlock: \n"));
730
 
 
731
 
  if (!mMsgComposeSecure)
732
 
    return NS_ERROR_FAILURE;
733
 
 
734
 
  if (mUseSMIME) {
735
 
    return mMsgComposeSecure->MimeCryptoWriteBlock(aBuf, aLen);
736
 
  }
737
 
 
738
 
  // Enigmail stuff
739
 
  nsCAutoString temStr(aBuf, aLen);
740
 
  DEBUG_LOG(("nsEnigMsgCompose::MimeCryptoWriteBlock: aBuf='%s'\n",
741
 
             temStr.get()));
742
 
 
743
 
  if (!mMultipartSigned) {
744
 
    return WriteCopy(aBuf, aLen);
745
 
  }
746
 
 
747
 
  // Mangle lines beginning with "From "
748
 
  // strip trailing whitespaces prior to signing
749
 
  PRUint32 offset = 0;
750
 
  PRUint32 writeCount = 0;
751
 
 
752
 
  for (PRUint32 j=0; j<((PRUint32) aLen); j++) {
753
 
    if ((mSpace > 0) && ((aBuf[j] == '\r') || (aBuf[j] == '\n'))) {
754
 
      // strip trailing spaces and tabs
755
 
      writeCount = j-offset-mSpace;
756
 
      WriteCopy(&aBuf[offset], writeCount);
757
 
      DEBUG_LOG(("nsEnigMsgCompose::MimeCryptoWriteBlock: stripped trailing whitespaces\n"));
758
 
      offset = j;
759
 
    }
760
 
    if (mLinebreak || (mMatchFrom > 0)) {
761
 
 
762
 
      if (aBuf[j] != FromStr[mMatchFrom]) {
763
 
        // No match; reset count
764
 
        mMatchFrom = 0;
765
 
 
766
 
      } else {
767
 
        // Increment match count
768
 
        mMatchFrom++;
769
 
 
770
 
        if (mMatchFrom >= strlen(FromStr)) {
771
 
          // Complete match found
772
 
          // Write out characters preceding match
773
 
          writeCount = j+1-offset-mMatchFrom;
774
 
 
775
 
          if (writeCount > 0) {
776
 
            rv = WriteCopy(&aBuf[offset], writeCount);
777
 
            if (NS_FAILED(rv)) return rv;
778
 
          }
779
 
 
780
 
          mMatchFrom = 0;
781
 
          offset = j+1;
782
 
 
783
 
          // Write out mangled string
784
 
          rv = WriteCopy(">", 1);
785
 
          if (NS_FAILED(rv)) return rv;
786
 
 
787
 
          rv = WriteCopy(FromStr, strlen(FromStr));
788
 
          if (NS_FAILED(rv)) return rv;
789
 
 
790
 
          DEBUG_LOG(("nsEnigMsgCompose::MimeCryptoWriteBlock: >From\n"));
791
 
        }
792
 
 
793
 
      }
794
 
    }
795
 
 
796
 
    mLinebreak = (aBuf[j] == '\r') || (aBuf[j] == '\n');
797
 
    if (mStripWhitespace && ((aBuf[j] == ' ') || (aBuf[j] == '\t'))) {
798
 
      ++mSpace;
799
 
    }
800
 
    else {
801
 
      mSpace = 0;
802
 
    }
803
 
  }
804
 
 
805
 
  if ((offset+mMatchFrom) < (PRUint32) aLen) {
806
 
    // Write out characters preceding any match
807
 
    rv = WriteCopy(&aBuf[offset], aLen-offset-mMatchFrom-mSpace);
808
 
    if (NS_FAILED(rv)) return rv;
809
 
  }
810
 
 
811
 
  return NS_OK;
812
 
}
813
 
 
814
 
 
815
 
static nsresult
816
 
EnigMsgCompose_write(const char *buf, PRInt32 size, void *closure)
817
 
{
818
 
  DEBUG_LOG(("nsEnigMsgCompose::EnigMsgCompose_write: (%p) %d\n", closure, size));
819
 
 
820
 
  if (!closure)
821
 
    return NS_ERROR_FAILURE;
822
 
 
823
 
  nsIEnigMimeWriter* enigMimeWriter = (nsIEnigMimeWriter *) closure;
824
 
 
825
 
  return enigMimeWriter->Write(buf, size);
826
 
}
827
 
 
828
 
 
829
 
nsresult
830
 
nsEnigMsgCompose::WriteOut(const char *aBuf, PRInt32 aLen)
831
 
{
832
 
  DEBUG_LOG(("nsEnigMsgCompose::WriteOut: %d\n", aLen));
833
 
 
834
 
  if (!mWriter)
835
 
    return NS_ERROR_FAILURE;
836
 
 
837
 
  if (aLen <= 0)
838
 
    return NS_OK;
839
 
 
840
 
  mOutputLen += aLen;
841
 
 
842
 
  if (mEncoderData) {
843
 
    // Encode data before transmitting to writer
844
 
    int status = MimeEncoderWrite(mEncoderData, aBuf, aLen);
845
 
    return (status == 0) ? NS_OK : NS_ERROR_FAILURE;
846
 
  }
847
 
 
848
 
  return mWriter->Write(aBuf, aLen);
849
 
}
850
 
 
851
 
nsresult
852
 
nsEnigMsgCompose::WriteToPipe(const char *aBuf, PRInt32 aLen)
853
 
{
854
 
  nsresult rv;
855
 
  DEBUG_LOG(("nsEnigMsgCompose::WriteToPipe: %d\n", aLen));
856
 
 
857
 
  nsCString tmpStr;
858
 
  tmpStr.Assign(aBuf, aLen);
859
 
  DEBUG_LOG(("nsEnigMimeWriter::WriteToPipe: data: '%s'\n", tmpStr.get()));
860
 
 
861
 
  rv = mPipeTrans->Write(aBuf, aLen);
862
 
  return rv;
863
 
}
864
 
 
865
 
nsresult
866
 
nsEnigMsgCompose::WriteCopy(const char *aBuf, PRInt32 aLen)
867
 
{
868
 
  nsresult rv;
869
 
 
870
 
  DEBUG_LOG(("nsEnigMsgCompose::WriteCopy: %d\n", aLen));
871
 
 
872
 
  if (aLen <= 0)
873
 
    return NS_OK;
874
 
 
875
 
  mInputLen += aLen;
876
 
 
877
 
  if (mMimeListener) {
878
 
    // Write to listener
879
 
    rv = mMimeListener->Write(aBuf, aLen, NULL, NULL);
880
 
    if (NS_FAILED(rv)) return rv;
881
 
 
882
 
  } else if (mPipeTrans) {
883
 
    // Write to process and copy if multipart/signed
884
 
    rv = WriteToPipe(aBuf, aLen);
885
 
    if (NS_FAILED(rv)) return rv;
886
 
 
887
 
    if (mMultipartSigned) {
888
 
      rv = WriteOut(aBuf, aLen);
889
 
      if (NS_FAILED(rv)) return rv;
890
 
    }
891
 
  }
892
 
 
893
 
  return NS_OK;
894
 
}
895
 
 
896
 
///////////////////////////////////////////////////////////////////////////////
897
 
// nsIRequestObserver methods
898
 
///////////////////////////////////////////////////////////////////////////////
899
 
 
900
 
NS_IMETHODIMP
901
 
nsEnigMsgCompose::OnStartRequest(nsIRequest *aRequest,
902
 
                                   nsISupports *aContext)
903
 
{
904
 
  nsresult rv;
905
 
  DEBUG_LOG(("nsEnigMsgCompose::OnStartRequest:\n"));
906
 
 
907
 
  nsCAutoString contentType;
908
 
  rv = mMimeListener->GetContentType(contentType);
909
 
  if (NS_FAILED(rv)) return rv;
910
 
 
911
 
  nsCAutoString contentEncoding;
912
 
  rv = mMimeListener->GetContentEncoding(contentEncoding);
913
 
  if (NS_FAILED(rv)) return rv;
914
 
 
915
 
  nsCAutoString headers;
916
 
  rv = mMimeListener->GetHeaders(headers);
917
 
  if (NS_FAILED(rv)) return rv;
918
 
 
919
 
  if (headers.IsEmpty())
920
 
    return NS_ERROR_FAILURE;
921
 
 
922
 
  DEBUG_LOG(("nsEnigMsgCompose::OnStartRequest: Content-Type: %s\n", headers.get()));
923
 
 
924
 
  EMBool encapsulate = PR_FALSE;
925
 
  if (mSendFlags & nsIEnigmail::SEND_PGP_MIME) {
926
 
    // RFC2015 crypto encapsulation
927
 
    encapsulate = PR_TRUE;
928
 
 
929
 
  } else if (!contentType.Equals("text/plain", CaseInsensitiveCompare)) {
930
 
    // Force RFC2015 crypto encapsulation for non-plaintext messages
931
 
    encapsulate = PR_TRUE;
932
 
    mSendFlags |= nsIEnigmail::SEND_PGP_MIME;
933
 
  }
934
 
 
935
 
  rv = Init();
936
 
  if (NS_FAILED(rv)) return rv;
937
 
 
938
 
  if (!mPipeTrans) return NS_OK;
939
 
 
940
 
  if (encapsulate) {
941
 
    // RFC2015 crypto encapsulation for headers
942
 
 
943
 
    // Send headers to crypto processor
944
 
    rv = WriteToPipe(headers.get(), headers.Length());
945
 
    if (NS_FAILED(rv)) return rv;
946
 
 
947
 
    if (mMultipartSigned) {
948
 
      rv = WriteSignedHeaders1( contentEncoding.Equals("8bit", CaseInsensitiveCompare) );
949
 
      if (NS_FAILED(rv)) return rv;
950
 
 
951
 
      // Copy original headers to output
952
 
      rv = WriteOut(headers.get(), headers.Length());
953
 
      if (NS_FAILED(rv)) return rv;
954
 
 
955
 
    } else {
956
 
      rv = WriteEncryptedHeaders();
957
 
      if (NS_FAILED(rv)) return rv;
958
 
    }
959
 
 
960
 
  } else {
961
 
    // No crypto encapsulation for headers
962
 
    DEBUG_LOG(("nsEnigMsgCompose::OnStartRequest: NO CRYPTO ENCAPSULATION\n"));
963
 
 
964
 
    rv = WriteOut(headers.get(), headers.Length());
965
 
    if (NS_FAILED(rv)) return rv;
966
 
 
967
 
/*
968
 
 *  not supported anymore
969
 
    if (contentEncoding.Equals("base64", CaseInsensitiveCompare)) {
970
 
 
971
 
      mEncoderData = MimeB64EncoderInit(EnigMsgCompose_write, (void*) mWriter);
972
 
 
973
 
    } else if (contentEncoding.Equals("quoted-printable", CaseInsensitiveCompare)) {
974
 
 
975
 
      mEncoderData = MimeQPEncoderInit(EnigMsgCompose_write, (void*) mWriter);
976
 
    }
977
 
*/
978
 
  }
979
 
 
980
 
  return NS_OK;
981
 
}
982
 
 
983
 
NS_IMETHODIMP
984
 
nsEnigMsgCompose::OnStopRequest(nsIRequest* aRequest,
985
 
                                  nsISupports* aContext,
986
 
                                  nsresult aStatus)
987
 
{
988
 
  DEBUG_LOG(("nsEnigMsgCompose::OnStopRequest:\n"));
989
 
 
990
 
  mRequestStopped = PR_TRUE;
991
 
 
992
 
  return NS_OK;
993
 
}
994
 
 
995
 
///////////////////////////////////////////////////////////////////////////////
996
 
// nsIStreamListener method
997
 
///////////////////////////////////////////////////////////////////////////////
998
 
 
999
 
NS_IMETHODIMP
1000
 
nsEnigMsgCompose::OnDataAvailable(nsIRequest* aRequest,
1001
 
                                  nsISupports* aContext,
1002
 
                                  nsIInputStream *aInputStream,
1003
 
#if MOZILLA_MAJOR_VERSION < 18
1004
 
                                  PRUint32 aSourceOffset,
1005
 
#else
1006
 
                                  PRUint64 aSourceOffset,
1007
 
#endif
1008
 
                                  PRUint32 aLength)
1009
 
{
1010
 
  nsresult rv;
1011
 
 
1012
 
  DEBUG_LOG(("nsEnigMsgCompose::OnDataAVailable: %d\n", aLength));
1013
 
 
1014
 
  if (!mPipeTrans)
1015
 
    return NS_ERROR_NOT_INITIALIZED;
1016
 
 
1017
 
  char buf[kCharMax];
1018
 
  PRUint32 readCount, readMax, writeCount;
1019
 
 
1020
 
  while (aLength > 0) {
1021
 
    readMax = (aLength < kCharMax) ? aLength : kCharMax;
1022
 
    rv = aInputStream->Read((char *) buf, readMax, &readCount);
1023
 
 
1024
 
    if (NS_FAILED(rv)){
1025
 
      DEBUG_LOG(("nsEnigMsgCompose::OnDataAvailable: Error in reading from input stream, %p\n", rv));
1026
 
      return rv;
1027
 
    }
1028
 
 
1029
 
    if (readCount <= 0) return NS_OK;
1030
 
 
1031
 
    writeCount = readCount;
1032
 
 
1033
 
    if (mMultipartSigned) {
1034
 
 
1035
 
      nsCString tmpStr;
1036
 
      tmpStr.Assign(buf, readCount);
1037
 
 
1038
 
      nsCString left(tmpStr);
1039
 
      left.SetLength(15);
1040
 
 
1041
 
      if (left.LowerCaseEqualsLiteral("x-mozilla-keys:")) {
1042
 
        DEBUG_LOG(("nsEnigMimeWriter::OnDataAvailable: workaround for 'X-Mozilla-Keys:' header\n"));
1043
 
 
1044
 
        tmpStr.StripWhitespace();
1045
 
        if (left == tmpStr) {
1046
 
          if (buf[readCount-2] == '\r' && buf[readCount-1] == '\n') {
1047
 
            tmpStr.Append("\r\n");
1048
 
          }
1049
 
          else
1050
 
            tmpStr.Append("\n");
1051
 
 
1052
 
          rv = WriteToPipe(tmpStr.get(), tmpStr.Length());
1053
 
          if (NS_FAILED(rv)) return rv;
1054
 
 
1055
 
          rv = WriteOut(tmpStr.get(), tmpStr.Length());
1056
 
          if (NS_FAILED(rv)) return rv;
1057
 
 
1058
 
          aLength -= readCount;
1059
 
 
1060
 
          return NS_OK;
1061
 
 
1062
 
        }
1063
 
      }
1064
 
 
1065
 
 
1066
 
      rv = WriteToPipe(buf, readCount);
1067
 
      if (NS_FAILED(rv)) return rv;
1068
 
 
1069
 
      rv = WriteOut(buf, readCount);
1070
 
      if (NS_FAILED(rv)) return rv;
1071
 
 
1072
 
    }
1073
 
    else {
1074
 
      rv = WriteToPipe(buf, readCount);
1075
 
      if (NS_FAILED(rv)) return rv;
1076
 
    }
1077
 
 
1078
 
    aLength -= readCount;
1079
 
  }
1080
 
 
1081
 
  return NS_OK;
1082
 
}