~ubuntu-branches/ubuntu/oneiric/enigmail/oneiric-updates

« back to all changes in this revision

Viewing changes to extensions/enigmail/ipc/src/nsIPCBuffer.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Alexander Sack
  • Date: 2010-04-10 01:42:24 UTC
  • Revision ID: james.westby@ubuntu.com-20100410014224-fbq9ui5x3b0h2t36
Tags: 2:1.0.1-0ubuntu1
* First releaase of enigmail 1.0.1 for tbird/icedove 3
  (LP: #527138)
* redo packaging from scratch 
  + add debian/make-orig target that uses xulrunner provided
    buildsystem + enigmail tarball to produce a proper orig.tar.gz
  + use debhelper 7 with mozilla-devscripts
  + use debian source format 3.0 (quilt)
  + patch enigmail to use frozen API only
    - add debian/patches/frozen_api.diff
  + patch build system to not link against -lxul - which isnt
    available for sdks produced by all-static apps like tbird
    - add debian/patches/build_system_dont_link_libxul.diff
  + add minimal build-depends to control

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * The contents of this file are subject to the Mozilla Public
 
3
 * License Version 1.1 (the "MPL"); you may not use this file
 
4
 * except in compliance with the MPL. You may obtain a copy of
 
5
 * the MPL at http://www.mozilla.org/MPL/
 
6
 *
 
7
 * Software distributed under the MPL is distributed on an "AS
 
8
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 
9
 * implied. See the MPL for the specific language governing
 
10
 * rights and limitations under the MPL.
 
11
 *
 
12
 * The Original Code is protoZilla.
 
13
 *
 
14
 * The Initial Developer of the Original Code is Ramalingam Saravanan.
 
15
 * Portions created by Ramalingam Saravanan <svn@xmlterm.org> are
 
16
 * Copyright (C) 2000 Ramalingam Saravanan. All Rights Reserved.
 
17
 *
 
18
 * Contributor(s):
 
19
 * Patrick Brunschwig <patrick@mozilla-enigmail.org>
 
20
 *
 
21
 * Alternatively, the contents of this file may be used under the
 
22
 * terms of the GNU General Public License (the "GPL"), in which case
 
23
 * the provisions of the GPL are applicable instead of
 
24
 * those above. If you wish to allow use of your version of this
 
25
 * file only under the terms of the GPL and not to allow
 
26
 * others to use your version of this file under the MPL, indicate
 
27
 * your decision by deleting the provisions above and replace them
 
28
 * with the notice and other provisions required by the GPL.
 
29
 * If you do not delete the provisions above, a recipient
 
30
 * may use your version of this file under either the MPL or the
 
31
 * GPL.
 
32
 */
 
33
 
 
34
// Logging of debug output
 
35
// The following define statement should occur before any include statements
 
36
#define FORCE_PR_LOG       /* Allow logging even in release build */
 
37
 
 
38
#include "ipc.h"
 
39
#include "prlog.h"
 
40
#include "nsCOMPtr.h"
 
41
#include "nsAutoLock.h"
 
42
#include "nsIInputStream.h"
 
43
#include "nsIThread.h"
 
44
#include "nsIHttpChannel.h"
 
45
#include "nsNetUtil.h"
 
46
#include "nsDirectoryServiceUtils.h"
 
47
#include "nsDirectoryServiceDefs.h"
 
48
#include "nsNetCID.h"
 
49
 
 
50
#ifndef _IPC_FORCE_INTERNAL_API
 
51
#include "nsStringAPI.h"
 
52
#else
 
53
#include "nsString.h"
 
54
#endif
 
55
 
 
56
#include "nsIPCBuffer.h"
 
57
 
 
58
#ifdef PR_LOGGING
 
59
PRLogModuleInfo* gIPCBufferLog = NULL;
 
60
#endif
 
61
 
 
62
#define ERROR_LOG(args)    PR_LOG(gIPCBufferLog,PR_LOG_ERROR,args)
 
63
#define WARNING_LOG(args)  PR_LOG(gIPCBufferLog,PR_LOG_WARNING,args)
 
64
#define DEBUG_LOG(args)    PR_LOG(gIPCBufferLog,PR_LOG_DEBUG,args)
 
65
 
 
66
#define NS_PIPE_CONSOLE_BUFFER_SIZE   (1024)
 
67
 
 
68
static const PRUint32 kCharMax = NS_PIPE_CONSOLE_BUFFER_SIZE;
 
69
 
 
70
///////////////////////////////////////////////////////////////////////////////
 
71
 
 
72
// nsIPCBuffer implementation
 
73
 
 
74
// nsISupports implementation
 
75
NS_IMPL_THREADSAFE_ISUPPORTS5(nsIPCBuffer,
 
76
                              nsIStreamListener,
 
77
                              nsIPipeListener,
 
78
                              nsIIPCBuffer,
 
79
                              nsIInputStream,
 
80
                              nsIRunnable)
 
81
 
 
82
 
 
83
// nsIPCBuffer implementation
 
84
nsIPCBuffer::nsIPCBuffer()
 
85
  : mFinalized(PR_FALSE),
 
86
    mThreadJoined(PR_FALSE),
 
87
    mOverflowed(PR_FALSE),
 
88
    mOverflowFile(PR_FALSE),
 
89
 
 
90
    mRequestStarted(PR_FALSE),
 
91
    mRequestStopped(PR_FALSE),
 
92
 
 
93
    mLock(nsnull),
 
94
 
 
95
    mMaxBytes(0),
 
96
    mByteCount(0),
 
97
 
 
98
    mByteBuf(""),
 
99
 
 
100
    mPipeWrite(IPC_NULL_HANDLE),
 
101
    mPipeRead(IPC_NULL_HANDLE),
 
102
 
 
103
    mTempFile(nsnull),
 
104
    mTempOutStream(nsnull),
 
105
    mTempInStream(nsnull),
 
106
 
 
107
    mPipeThread(nsnull),
 
108
    mObserver(nsnull),
 
109
    mObserverContext(nsnull)
 
110
{
 
111
    NS_INIT_ISUPPORTS();
 
112
 
 
113
#ifdef PR_LOGGING
 
114
  if (gIPCBufferLog == nsnull) {
 
115
    gIPCBufferLog = PR_NewLogModule("nsIPCBuffer");
 
116
  }
 
117
#endif
 
118
 
 
119
#ifdef FORCE_PR_LOG
 
120
  nsresult rv;
 
121
  nsCOMPtr<nsIThread> myThread;
 
122
  rv = IPC_GET_THREAD(myThread);
 
123
  DEBUG_LOG(("nsIPCBuffer:: <<<<<<<<< CTOR(%p): myThread=%p\n",
 
124
         this, myThread.get()));
 
125
#endif
 
126
}
 
127
 
 
128
 
 
129
nsIPCBuffer::~nsIPCBuffer()
 
130
{
 
131
  nsresult rv;
 
132
#ifdef FORCE_PR_LOG
 
133
  nsCOMPtr<nsIThread> myThread;
 
134
  rv = IPC_GET_THREAD(myThread);
 
135
  DEBUG_LOG(("nsIPCBuffer:: >>>>>>>>> DTOR(%p): myThread=%p\n",
 
136
         this, myThread.get()));
 
137
#endif
 
138
 
 
139
  Finalize(PR_TRUE);
 
140
 
 
141
  if (mLock)
 
142
    PR_DestroyLock(mLock);
 
143
}
 
144
 
 
145
 
 
146
///////////////////////////////////////////////////////////////////////////////
 
147
// nsIPCBuffer methods:
 
148
///////////////////////////////////////////////////////////////////////////////
 
149
 
 
150
nsresult
 
151
nsIPCBuffer::Finalize(PRBool destructor)
 
152
{
 
153
  DEBUG_LOG(("nsIPCBuffer::Finalize: \n"));
 
154
 
 
155
  if (mFinalized)
 
156
    return NS_OK;
 
157
 
 
158
  mFinalized = PR_TRUE;
 
159
 
 
160
  nsCOMPtr<nsIIPCBuffer> self;
 
161
  if (!destructor) {
 
162
    // Hold a reference to ourselves to prevent our DTOR from being called
 
163
    // while finalizing. Automatically released upon returning.
 
164
    self = this;
 
165
  }
 
166
 
 
167
  // Close write pipe
 
168
  if (mPipeWrite) {
 
169
    IPC_Close(mPipeWrite);
 
170
    mPipeWrite = IPC_NULL_HANDLE;
 
171
  }
 
172
 
 
173
  // Release owning refs
 
174
  mPipeThread = nsnull;
 
175
  mObserver = nsnull;
 
176
  mObserverContext = nsnull;
 
177
 
 
178
  RemoveTempFile();
 
179
 
 
180
  // Clear console
 
181
  mByteBuf.Assign("");
 
182
 
 
183
  return NS_OK;
 
184
}
 
185
 
 
186
nsresult
 
187
nsIPCBuffer::Init()
 
188
{
 
189
  DEBUG_LOG(("nsIPCBuffer::Init: \n"));
 
190
 
 
191
  if (mLock == nsnull) {
 
192
    mLock = PR_NewLock();
 
193
    if (mLock == nsnull)
 
194
      return NS_ERROR_OUT_OF_MEMORY;
 
195
  }
 
196
 
 
197
  return NS_OK;
 
198
}
 
199
 
 
200
NS_IMETHODIMP
 
201
nsIPCBuffer::Open(PRUint32 maxBytes, PRBool overflowFile)
 
202
{
 
203
  nsresult rv;
 
204
 
 
205
  DEBUG_LOG(("nsIPCBuffer::Open: %d, %d\n", maxBytes, (int) overflowFile));
 
206
  rv = Init();
 
207
  NS_ENSURE_SUCCESS(rv, rv);
 
208
 
 
209
  if (maxBytes == -1) {
 
210
    mMaxBytes = PR_INT32_MAX;
 
211
  }
 
212
  else {
 
213
    mMaxBytes = maxBytes;
 
214
  }
 
215
  mOverflowFile = overflowFile;
 
216
 
 
217
  return NS_OK;
 
218
}
 
219
 
 
220
 
 
221
NS_IMETHODIMP
 
222
nsIPCBuffer::OpenURI(nsIURI* aURI, PRInt32 maxBytes, PRBool synchronous,
 
223
                     nsIRequestObserver* observer, nsISupports* context)
 
224
{
 
225
  DEBUG_LOG(("nsIPCBuffer::OpenURI: \n"));
 
226
 
 
227
  nsresult rv;
 
228
 
 
229
  rv = Init();
 
230
  NS_ENSURE_SUCCESS(rv, rv);
 
231
 
 
232
  mMaxBytes = maxBytes;
 
233
 
 
234
  mObserver = observer;
 
235
  mObserverContext = context;
 
236
 
 
237
  nsCOMPtr<nsIIOService> ioService(do_GetService(NS_IOSERVICE_CONTRACTID, &rv));
 
238
  NS_ENSURE_SUCCESS(rv, rv);
 
239
 
 
240
  nsCOMPtr<nsIChannel> channel;
 
241
  rv = ioService->NewChannelFromURI(aURI, getter_AddRefs(channel));
 
242
  NS_ENSURE_SUCCESS(rv, rv);
 
243
 
 
244
  nsCOMPtr<nsISupports> ctxt = do_QueryInterface(aURI);
 
245
 
 
246
  if (!synchronous) {
 
247
    // Initiate asynchronous loading of URI
 
248
    rv = channel->AsyncOpen( (nsIStreamListener*) this, ctxt );
 
249
    NS_ENSURE_SUCCESS(rv, rv);
 
250
 
 
251
    DEBUG_LOG(("nsIPCBuffer::OpenURI: Starting asynchronous load ...\n"));
 
252
    return NS_OK;
 
253
  }
 
254
 
 
255
  // Synchronous loading (DOESN'T USUALLY WORK!!!)
 
256
  DEBUG_LOG(("nsIPCBuffer::OpenURI: Starting synchronous load ...\n"));
 
257
  nsCOMPtr<nsIInputStream> inputStream;
 
258
  rv = channel->Open(getter_AddRefs(inputStream));
 
259
  NS_ENSURE_SUCCESS(rv, rv);
 
260
 
 
261
  OnStartRequest(nsnull, mObserverContext);
 
262
 
 
263
  PRUint32 readCount;
 
264
  char buf[1024];
 
265
 
 
266
  while (1) {
 
267
    // Read and append output until end-of-file
 
268
    rv = inputStream->Read((char *) buf, 1024, &readCount);
 
269
    NS_ENSURE_SUCCESS(rv, rv);
 
270
 
 
271
    if (!readCount) break;
 
272
 
 
273
    rv = WriteBuf(buf, readCount);
 
274
    NS_ENSURE_SUCCESS(rv, rv);
 
275
  }
 
276
 
 
277
  // Close input stream
 
278
  inputStream->Close();
 
279
 
 
280
  OnStopRequest(nsnull, mObserverContext, 0);
 
281
 
 
282
  return NS_OK;
 
283
}
 
284
 
 
285
 
 
286
NS_IMETHODIMP
 
287
nsIPCBuffer::GetStopped(PRBool* _retval)
 
288
{
 
289
  NS_ENSURE_ARG(_retval);
 
290
  *_retval = mRequestStopped;
 
291
  return NS_OK;
 
292
}
 
293
 
 
294
 
 
295
NS_IMETHODIMP
 
296
nsIPCBuffer::GetTotalBytes(PRUint32* _retval)
 
297
{
 
298
  NS_ENSURE_ARG(_retval);
 
299
  *_retval = mByteCount;
 
300
  return NS_OK;
 
301
}
 
302
 
 
303
 
 
304
NS_IMETHODIMP
 
305
nsIPCBuffer::OpenInputStream(nsIInputStream** result)
 
306
{
 
307
  nsresult rv;
 
308
 
 
309
  DEBUG_LOG(("nsIPCBuffer::OpenInputStream: \n"));
 
310
 
 
311
  if (!mRequestStopped) {
 
312
    ERROR_LOG(("nsIPCBuffer::OpenInputStream: ERROR - request not stopped\n"));
 
313
    return NS_ERROR_NOT_INITIALIZED;
 
314
  }
 
315
 
 
316
  mStreamOffset = 0;
 
317
 
 
318
  if (mByteCount && mTempFile) {
 
319
    rv = OpenTempInStream();
 
320
    NS_ENSURE_SUCCESS(rv, rv);
 
321
  }
 
322
 
 
323
  return this->QueryInterface(NS_GET_IID(nsIInputStream), (void**)result);
 
324
}
 
325
 
 
326
 
 
327
#define SAFE_TMP_FILENAME "nsenig.tmp"
 
328
 
 
329
NS_IMETHODIMP
 
330
nsIPCBuffer::CreateTempFile()
 
331
{
 
332
  nsresult rv;
 
333
 
 
334
  DEBUG_LOG(("nsIPCBuffer::CreateTempFile: \n"));
 
335
 
 
336
  if (mTempFile)
 
337
    return NS_ERROR_FAILURE;
 
338
 
 
339
  nsCOMPtr<nsIProperties> directoryService =
 
340
    do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
 
341
  directoryService->Get(NS_OS_TEMP_DIR, NS_GET_IID(nsIFile), getter_AddRefs(mTempFile));
 
342
 
 
343
  if (! mTempFile)
 
344
    return NS_ERROR_OUT_OF_MEMORY;
 
345
 
 
346
  mTempFile->AppendNative(nsDependentCString(SAFE_TMP_FILENAME));
 
347
  if (NS_FAILED(mTempFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 00600))) {
 
348
    return NS_ERROR_FAILURE;
 
349
  }
 
350
 
 
351
  nsCAutoString nativePath;
 
352
  mTempFile->GetNativePath(nativePath);
 
353
 
 
354
  DEBUG_LOG(("nsIPCBuffer::CreateTempFile: %s\n",
 
355
            nativePath.get()));
 
356
 
 
357
  mTempOutStream  = do_CreateInstance("@mozilla.org/network/file-output-stream;1", &rv);
 
358
  NS_ENSURE_SUCCESS(rv, rv);
 
359
 
 
360
  rv = mTempOutStream->Init(mTempFile, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 00600, 0);
 
361
  return rv;
 
362
}
 
363
 
 
364
 
 
365
NS_IMETHODIMP
 
366
nsIPCBuffer::WriteTempOutStream(const char* buf, PRUint32 count)
 
367
{
 
368
  if (!mTempOutStream)
 
369
    return NS_ERROR_FAILURE;
 
370
 
 
371
  if (!count)
 
372
    return NS_OK;
 
373
 
 
374
  PRUint32 writeCount;
 
375
  nsresult rv = mTempOutStream->Write(buf, count, &writeCount);
 
376
 
 
377
  if (writeCount != count)
 
378
    return NS_ERROR_FAILURE;
 
379
 
 
380
  return rv;
 
381
}
 
382
 
 
383
NS_IMETHODIMP
 
384
nsIPCBuffer::CloseTempOutStream()
 
385
{
 
386
  nsresult rv = NS_OK;
 
387
 
 
388
  DEBUG_LOG(("nsIPCBuffer::CloseTempOutStream: \n"));
 
389
 
 
390
  if (mTempOutStream) {
 
391
    if (NS_FAILED(mTempOutStream->Flush())) {
 
392
      rv = NS_ERROR_FAILURE;
 
393
    }
 
394
 
 
395
    if (NS_FAILED(mTempOutStream->Close())) {
 
396
      rv = NS_ERROR_FAILURE;
 
397
    }
 
398
    mTempOutStream = nsnull;
 
399
  }
 
400
 
 
401
  return rv;
 
402
}
 
403
 
 
404
NS_IMETHODIMP
 
405
nsIPCBuffer::OpenTempInStream()
 
406
{
 
407
  nsresult rv;
 
408
 
 
409
  DEBUG_LOG(("nsIPCBuffer::OpenTempInStream: \n"));
 
410
 
 
411
  if (!mTempFile)
 
412
    return NS_ERROR_FAILURE;
 
413
 
 
414
  if (mTempOutStream) {
 
415
    ERROR_LOG(("nsIPCBuffer::OpenTempInStream: ERROR - TempOutStream still open!\n"));
 
416
    return NS_ERROR_FAILURE;
 
417
  }
 
418
 
 
419
  mTempInStream  = do_CreateInstance("@mozilla.org/network/file-input-stream;1", &rv);
 
420
  NS_ENSURE_SUCCESS(rv, rv);
 
421
 
 
422
  rv = mTempInStream->Init(mTempFile, PR_RDONLY, 00600, 0);
 
423
  return rv;
 
424
}
 
425
 
 
426
 
 
427
NS_IMETHODIMP
 
428
nsIPCBuffer::CloseTempInStream()
 
429
{
 
430
  DEBUG_LOG(("nsIPCBuffer::CloseTempInStream: \n"));
 
431
  nsresult rv = NS_OK;
 
432
 
 
433
  if (mTempInStream) {
 
434
    rv = mTempInStream->Close();
 
435
    //delete mTempInStream;
 
436
    mTempInStream = nsnull;
 
437
  }
 
438
 
 
439
  return rv;
 
440
}
 
441
 
 
442
 
 
443
 
 
444
NS_IMETHODIMP
 
445
nsIPCBuffer::RemoveTempFile()
 
446
{
 
447
  DEBUG_LOG(("nsIPCBuffer::RemoveTempFile: \n"));
 
448
 
 
449
  if (mTempOutStream) {
 
450
    // Close overflow file
 
451
    CloseTempOutStream();
 
452
  }
 
453
 
 
454
  if (mTempInStream) {
 
455
    // Close overflow file
 
456
    CloseTempInStream();
 
457
  }
 
458
 
 
459
  if (mTempFile) {
 
460
    // delete temp file
 
461
    nsCAutoString nativePath;
 
462
    mTempFile->GetNativePath(nativePath);
 
463
    DEBUG_LOG(("nsIPCBuffer::RemoveTempFile: Removing %s\n",
 
464
                nativePath.get()));
 
465
 
 
466
    if (NS_FAILED(mTempFile->Remove(PR_FALSE))) {
 
467
      return NS_ERROR_FAILURE;
 
468
    }
 
469
 
 
470
    mTempFile = nsnull;
 
471
  }
 
472
 
 
473
  return NS_OK;
 
474
}
 
475
 
 
476
 
 
477
NS_IMETHODIMP
 
478
nsIPCBuffer::GetData(char** _retval)
 
479
{
 
480
  nsAutoLock lock(mLock);
 
481
 
 
482
  if (!_retval)
 
483
    return NS_ERROR_NULL_POINTER;
 
484
 
 
485
  // Copy portion of console data to be returned
 
486
  nsCAutoString bufCopy (mByteBuf);
 
487
 
 
488
  // Replace any NULs with '0'
 
489
  PRInt32 nulIndex = 0;
 
490
  while (nulIndex != -1) {
 
491
    nulIndex = bufCopy.FindChar(char(0));
 
492
    if (nulIndex != -1) {
 
493
      bufCopy.Replace(nulIndex, 1, "0", 1);
 
494
    }
 
495
  }
 
496
 
 
497
  // Duplicate new C string
 
498
  *_retval = ToNewCString(bufCopy);
 
499
  if (!*_retval)
 
500
    return NS_ERROR_OUT_OF_MEMORY;
 
501
 
 
502
  return NS_OK;
 
503
}
 
504
 
 
505
 
 
506
///////////////////////////////////////////////////////////////////////////////
 
507
// nsIPipeListener methods (thread-safe)
 
508
///////////////////////////////////////////////////////////////////////////////
 
509
 
 
510
NS_IMETHODIMP
 
511
nsIPCBuffer::Observe(nsIRequestObserver* observer, nsISupports* context)
 
512
{
 
513
  nsAutoLock lock(mLock);
 
514
  DEBUG_LOG(("nsIPCBuffer::Observe: %p, %p\n", observer, context));
 
515
 
 
516
  mObserver = observer;
 
517
  mObserverContext = context;
 
518
 
 
519
  return NS_OK;
 
520
}
 
521
 
 
522
 
 
523
NS_IMETHODIMP
 
524
nsIPCBuffer::GetJoinable(PRBool *_retval)
 
525
{
 
526
  DEBUG_LOG(("nsIPCBuffer::GetJoinable: 1\n"));
 
527
 
 
528
  *_retval = PR_TRUE;
 
529
 
 
530
  return NS_OK;
 
531
}
 
532
 
 
533
 
 
534
NS_IMETHODIMP
 
535
nsIPCBuffer::Shutdown()
 
536
{
 
537
  nsAutoLock lock(mLock);
 
538
  DEBUG_LOG(("nsIPCBuffer::Shutdown:\n"));
 
539
 
 
540
  Finalize(PR_FALSE);
 
541
 
 
542
  return NS_OK;
 
543
}
 
544
 
 
545
 
 
546
 
 
547
NS_IMETHODIMP
 
548
nsIPCBuffer::GetByteData(PRUint32 *count, char **data)
 
549
{
 
550
  nsAutoLock lock(mLock);
 
551
 
 
552
  DEBUG_LOG(("nsIPCBuffer::GetByteData:\n"));
 
553
 
 
554
  if (!count || !data)
 
555
    return NS_ERROR_NULL_POINTER;
 
556
 
 
557
  // Copy bytes
 
558
  *count = mByteBuf.Length();
 
559
  *data = reinterpret_cast<char*>(nsMemory::Alloc((*count)+1));
 
560
  if (!*data)
 
561
    return NS_ERROR_OUT_OF_MEMORY;
 
562
 
 
563
  memcpy(*data, mByteBuf.get(), *count);
 
564
 
 
565
  // NUL terminate byte array (just to be safe!)
 
566
  (*data)[*count] = '\0';
 
567
 
 
568
  return NS_OK;
 
569
}
 
570
 
 
571
 
 
572
NS_IMETHODIMP
 
573
nsIPCBuffer::GetOverflowed(PRBool *_retval)
 
574
{
 
575
  nsAutoLock lock(mLock);
 
576
 
 
577
  DEBUG_LOG(("nsIPCBuffer::GetOverflowed: %d\n", (int) mOverflowed));
 
578
 
 
579
  *_retval = mOverflowed;
 
580
 
 
581
  return NS_OK;
 
582
}
 
583
 
 
584
 
 
585
NS_IMETHODIMP
 
586
nsIPCBuffer::Write(const char* str)
 
587
{
 
588
  // Note: Locking occurs in WriteBuf
 
589
 
 
590
  DEBUG_LOG(("nsIPCBuffer::Write: %s\n", str));
 
591
 
 
592
  PRUint32 len = strlen(str);
 
593
  if (!len)
 
594
    return NS_OK;
 
595
 
 
596
  return WriteBuf(str, len);
 
597
}
 
598
 
 
599
 
 
600
NS_IMETHODIMP
 
601
nsIPCBuffer::WriteBuf(const char* buf, PRUint32 count)
 
602
{
 
603
  nsresult rv;
 
604
  nsAutoLock lock(mLock);
 
605
 
 
606
  DEBUG_LOG(("nsIPCBuffer::WriteBuf: %d (%d)\n", count, mByteCount));
 
607
 
 
608
  if (count <= 0)
 
609
    return NS_OK;
 
610
 
 
611
  mByteCount += count;
 
612
 
 
613
  if (mOverflowed) {
 
614
    if (!mOverflowFile)
 
615
      return NS_OK;
 
616
 
 
617
    rv = WriteTempOutStream(buf, count);
 
618
 
 
619
    return rv;
 
620
  }
 
621
 
 
622
  // Find space available in buffer
 
623
  PRInt32 nAvail = mMaxBytes - mByteBuf.Length();
 
624
 
 
625
  if (nAvail >= (int) count) {
 
626
    mByteBuf.Append(buf, count);
 
627
    return NS_OK;
 
628
  }
 
629
 
 
630
  if (nAvail > 0) {
 
631
    mByteBuf.Append(buf, nAvail);
 
632
  }
 
633
 
 
634
  mOverflowed = PR_TRUE;
 
635
  DEBUG_LOG(("nsIPCBuffer::WriteBuf: buffer overflow\n"));
 
636
 
 
637
  if (!mOverflowFile)
 
638
    return NS_OK;
 
639
 
 
640
  CreateTempFile();
 
641
 
 
642
  // Write out previously buffered data first
 
643
  rv = WriteTempOutStream(mByteBuf.get(), mByteBuf.Length());
 
644
  NS_ENSURE_SUCCESS(rv, rv);
 
645
 
 
646
  rv = WriteTempOutStream(buf+nAvail, count-nAvail);
 
647
  return rv;
 
648
}
 
649
 
 
650
NS_IMETHODIMP
 
651
nsIPCBuffer::Join()
 
652
{
 
653
  nsresult rv;
 
654
 
 
655
  {
 
656
    // Nested lock to avoid deadlock while waiting for Join
 
657
    nsAutoLock lock(mLock);
 
658
    DEBUG_LOG(("nsIPCBuffer::Join:\n"));
 
659
 
 
660
    if (mThreadJoined || !mPipeThread)
 
661
      return NS_OK;
 
662
 
 
663
    if (mPipeWrite) {
 
664
      // Close write pipe before joining
 
665
      IPC_Close(mPipeWrite);
 
666
      mPipeWrite = IPC_NULL_HANDLE;
 
667
    }
 
668
  }
 
669
 
 
670
  rv = mPipeThread->Shutdown();
 
671
 
 
672
  NS_ENSURE_SUCCESS(rv, rv);
 
673
 
 
674
  mThreadJoined = PR_TRUE;
 
675
  return NS_OK;
 
676
}
 
677
 
 
678
 
 
679
NS_IMETHODIMP
 
680
nsIPCBuffer::GetFileDesc(IPCFileDesc* *_retval)
 
681
{
 
682
  nsresult rv;
 
683
 
 
684
  nsAutoLock lock(mLock);
 
685
 
 
686
  DEBUG_LOG(("nsIPCBuffer::GetFileDesc:\n"));
 
687
 
 
688
  if (!_retval)
 
689
    return NS_ERROR_NULL_POINTER;
 
690
 
 
691
  if (!mFinalized && !mPipeThread) {
 
692
    // Create pipe pair
 
693
    PRStatus status = IPC_CreateInheritablePipe(&mPipeRead, &mPipeWrite,
 
694
                                              PR_FALSE, PR_TRUE);
 
695
    if (status != PR_SUCCESS) {
 
696
      ERROR_LOG(("nsIPCBuffer::GetFileDesc: IPC_CreateInheritablePipe failed\n"));
 
697
      return NS_ERROR_FAILURE;
 
698
    }
 
699
 
 
700
    // Spin up a new thread to handle STDOUT polling
 
701
    rv = NS_NewThread(getter_AddRefs(mPipeThread), this);
 
702
 
 
703
    NS_ENSURE_SUCCESS(rv, rv);
 
704
  }
 
705
 
 
706
  if (mPipeWrite == IPC_NULL_HANDLE)
 
707
    return NS_ERROR_FAILURE;
 
708
 
 
709
  *_retval = mPipeWrite;
 
710
  return NS_OK;
 
711
}
 
712
 
 
713
///////////////////////////////////////////////////////////////////////////////
 
714
// nsIRequestObserver methods
 
715
///////////////////////////////////////////////////////////////////////////////
 
716
 
 
717
NS_IMETHODIMP
 
718
nsIPCBuffer::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext)
 
719
{
 
720
  DEBUG_LOG(("nsIPCBuffer::OnStartRequest:\n"));
 
721
 
 
722
  nsCOMPtr<nsIRequestObserver> observer;
 
723
  nsCOMPtr<nsISupports> observerContext;
 
724
  {
 
725
    nsAutoLock lock(mLock);
 
726
 
 
727
    mRequestStarted = PR_TRUE;
 
728
 
 
729
    if (!mObserver)
 
730
      return NS_OK;
 
731
 
 
732
    observer = mObserver;
 
733
    observerContext = mObserverContext;
 
734
  }
 
735
 
 
736
  return observer->OnStartRequest(aRequest, observerContext);
 
737
}
 
738
 
 
739
NS_IMETHODIMP
 
740
nsIPCBuffer::OnStopRequest(nsIRequest* aRequest, nsISupports* aContext,
 
741
                             nsresult aStatus)
 
742
{
 
743
  DEBUG_LOG(("nsIPCBuffer::OnStopRequest:\n"));
 
744
 
 
745
  nsCOMPtr<nsIRequestObserver> observer;
 
746
  nsCOMPtr<nsISupports> observerContext;
 
747
  {
 
748
    nsAutoLock lock(mLock);
 
749
 
 
750
    mRequestStopped = PR_TRUE;
 
751
    CloseTempOutStream();
 
752
 
 
753
    if (!mObserver)
 
754
      return NS_OK;
 
755
 
 
756
    observer = mObserver;
 
757
    observerContext = mObserverContext;
 
758
  }
 
759
 
 
760
  return observer->OnStopRequest(aRequest, observerContext, aStatus);
 
761
}
 
762
 
 
763
///////////////////////////////////////////////////////////////////////////////
 
764
// nsIStreamListener method
 
765
///////////////////////////////////////////////////////////////////////////////
 
766
 
 
767
NS_IMETHODIMP
 
768
nsIPCBuffer::OnDataAvailable(nsIRequest* aRequest, nsISupports* aContext,
 
769
                              nsIInputStream *aInputStream,
 
770
                              PRUint32 aSourceOffset,
 
771
                              PRUint32 aLength)
 
772
{
 
773
  nsresult rv = NS_OK;
 
774
 
 
775
  DEBUG_LOG(("nsIPCBuffer::OnDataAVailable: %d\n", aLength));
 
776
 
 
777
  char buf[kCharMax];
 
778
  PRUint32 readCount, readMax;
 
779
 
 
780
  while (aLength > 0) {
 
781
    readMax = (aLength < kCharMax) ? aLength : kCharMax;
 
782
    rv = aInputStream->Read((char *) buf, readMax, &readCount);
 
783
    if (NS_FAILED(rv)){
 
784
      ERROR_LOG(("nsIPCBuffer::OnDataAvailable: Error in reading from input stream, %x\n", rv));
 
785
      return rv;
 
786
    }
 
787
 
 
788
    if (readCount <= 0) return NS_OK;
 
789
 
 
790
    rv = WriteBuf(buf, readCount);
 
791
    if (NS_FAILED(rv)) return rv;
 
792
 
 
793
    aLength -= readCount;
 
794
  }
 
795
 
 
796
  return NS_OK;
 
797
}
 
798
 
 
799
///////////////////////////////////////////////////////////////////////////////
 
800
// nsIRunnable methods:
 
801
// (runs as a new thread)
 
802
///////////////////////////////////////////////////////////////////////////////
 
803
 
 
804
NS_IMETHODIMP
 
805
nsIPCBuffer::Run()
 
806
{
 
807
  nsresult rv = NS_OK;
 
808
 
 
809
#ifdef FORCE_PR_LOG
 
810
  nsCOMPtr<nsIThread> myThread;
 
811
  rv = IPC_GET_THREAD(myThread);
 
812
  DEBUG_LOG(("nsIPCBuffer::Run: myThread=%p\n", myThread.get()));
 
813
#endif
 
814
 
 
815
  // Blocked read loop
 
816
  while (1) {
 
817
    char buf[kCharMax];
 
818
    PRInt32 readCount;
 
819
 
 
820
    // Read data from pipe (blocking)
 
821
    readCount = IPC_Read(mPipeRead, (char *) buf, kCharMax);
 
822
 
 
823
    DEBUG_LOG(("nsIPCBuffer::Run: Read %d chars\n", readCount));
 
824
 
 
825
    if (readCount <= 0)
 
826
      break;
 
827
 
 
828
#if 0
 
829
    // Debugging code
 
830
    if (readCount < (int) kCharMax) {
 
831
      buf[readCount] = '\0';
 
832
      DEBUG_LOG(("nsIPCBuffer::Run: buf='%s'\n", buf));
 
833
    }
 
834
#endif
 
835
 
 
836
    // Append data read to console
 
837
    WriteBuf(buf, readCount);
 
838
  }
 
839
 
 
840
  // Clear any NSPR interrupt
 
841
  PR_ClearInterrupt();
 
842
 
 
843
  // Close read pipe
 
844
  IPC_Close(mPipeRead);
 
845
  mPipeRead = IPC_NULL_HANDLE;
 
846
 
 
847
  return NS_OK;
 
848
}
 
849
 
 
850
///////////////////////////////////////////////////////////////////////////////
 
851
// nsIInputStream methods
 
852
///////////////////////////////////////////////////////////////////////////////
 
853
 
 
854
NS_IMETHODIMP
 
855
nsIPCBuffer::Available(PRUint32* _retval)
 
856
{
 
857
  if (!_retval)
 
858
    return NS_ERROR_NULL_POINTER;
 
859
 
 
860
  *_retval = (mByteCount > mStreamOffset) ?
 
861
              mByteCount - mStreamOffset : 0;
 
862
 
 
863
  DEBUG_LOG(("nsIPCBuffer::Available: %d (%d)\n", *_retval, mByteCount));
 
864
 
 
865
  return NS_OK;
 
866
}
 
867
 
 
868
NS_IMETHODIMP
 
869
nsIPCBuffer::Read(char* buf, PRUint32 count,
 
870
                         PRUint32 *readCount)
 
871
{
 
872
  DEBUG_LOG(("nsIPCBuffer::Read: %d\n", count));
 
873
 
 
874
  nsresult rv;
 
875
 
 
876
  if (!buf || !readCount)
 
877
    return NS_ERROR_NULL_POINTER;
 
878
 
 
879
  PRInt32 avail = (mByteCount > mStreamOffset) ?
 
880
                   mByteCount - mStreamOffset : 0;
 
881
 
 
882
  PRUint32 readyCount = ((PRUint32) avail > count) ? count : avail;
 
883
 
 
884
  if (readyCount) {
 
885
    if (mTempInStream) {
 
886
      rv = mTempInStream->Read((char *)buf, readyCount, readCount);
 
887
      NS_ENSURE_SUCCESS(rv, rv);
 
888
    } else {
 
889
      memcpy(buf, mByteBuf.get()+mStreamOffset, readyCount);
 
890
      *readCount = readyCount;
 
891
    }
 
892
  }
 
893
 
 
894
  mStreamOffset += *readCount;
 
895
 
 
896
  if (mStreamOffset >= mByteCount) {
 
897
    Close();
 
898
  }
 
899
 
 
900
  return NS_OK;
 
901
}
 
902
 
 
903
NS_IMETHODIMP
 
904
nsIPCBuffer::ReadSegments(nsWriteSegmentFun writer,
 
905
                          void * aClosure, PRUint32 count,
 
906
                          PRUint32 *readCount)
 
907
{
 
908
  nsresult rv;
 
909
  DEBUG_LOG(("nsIPCBuffer::ReadSegments: %d\n", count));
 
910
 
 
911
  if (!readCount)
 
912
    return NS_ERROR_NULL_POINTER;
 
913
 
 
914
  PRUint32 avail, readyCount, writeCount;
 
915
 
 
916
  *readCount = 0;
 
917
  if (!mTempInStream) {
 
918
 
 
919
    while ((count > 0) && (mStreamOffset < mByteCount)) {
 
920
      avail = mByteCount - mStreamOffset;
 
921
      readyCount = ((PRUint32) avail > count) ? count : avail;
 
922
 
 
923
      rv = writer((nsIInputStream*)(this),
 
924
                  aClosure, mByteBuf.get()+mStreamOffset,
 
925
                  mStreamOffset, readyCount, &writeCount);
 
926
      NS_ENSURE_SUCCESS(rv, rv);
 
927
 
 
928
      if (!writeCount)
 
929
        return (NS_ERROR_FAILURE);
 
930
 
 
931
      DEBUG_LOG(("nsIPCBuffer::ReadSegments: writer %d\n", writeCount));
 
932
 
 
933
      *readCount    += writeCount;
 
934
      mStreamOffset += writeCount;
 
935
      count         -= writeCount;
 
936
    }
 
937
 
 
938
  } else {
 
939
    char buf[kCharMax];
 
940
 
 
941
    while ((count > 0) && (mStreamOffset < mByteCount)) {
 
942
      avail = (count < kCharMax) ? count : kCharMax;
 
943
      rv = mTempInStream->Read((char *) buf, avail, &readyCount);
 
944
      NS_ENSURE_SUCCESS(rv, rv);
 
945
 
 
946
      if (!readyCount) {
 
947
        ERROR_LOG(("nsIPCBuffer::ReadSegments: Error in reading from TempInputStream\n"));
 
948
        return NS_ERROR_FAILURE;
 
949
      }
 
950
 
 
951
      rv = writer((nsIInputStream*)(this),
 
952
                  aClosure, buf,
 
953
                  mStreamOffset, readyCount, &writeCount);
 
954
      NS_ENSURE_SUCCESS(rv, rv);
 
955
      if (!writeCount)
 
956
        return NS_ERROR_FAILURE;
 
957
 
 
958
      DEBUG_LOG(("nsIPCBuffer::ReadSegments: writer %d (Temp)\n", writeCount));
 
959
 
 
960
      *readCount    += writeCount;
 
961
      mStreamOffset += writeCount;
 
962
      count         -= writeCount;
 
963
    }
 
964
  }
 
965
 
 
966
  if (mStreamOffset >= mByteCount) {
 
967
    // End-of-file
 
968
    Close();
 
969
  }
 
970
 
 
971
  return NS_OK;
 
972
}
 
973
 
 
974
NS_IMETHODIMP
 
975
nsIPCBuffer::IsNonBlocking(PRBool *aNonBlocking)
 
976
{
 
977
  DEBUG_LOG(("nsIPCBuffer::IsNonBlocking: \n"));
 
978
 
 
979
  *aNonBlocking = (mTempInStream == nsnull);
 
980
  return NS_OK;
 
981
}
 
982
 
 
983
NS_IMETHODIMP
 
984
nsIPCBuffer::Close()
 
985
{
 
986
  DEBUG_LOG(("nsIPCBuffer::Close: \n"));
 
987
  mStreamOffset = 0;
 
988
  mByteCount = 0;
 
989
  mByteBuf.Assign("");
 
990
 
 
991
  RemoveTempFile();
 
992
  return NS_OK;
 
993
}