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

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Chris Coulson
  • Date: 2012-04-30 01:08:44 UTC
  • mfrom: (0.12.10)
  • Revision ID: package-import@ubuntu.com-20120430010844-i4a0z0d73kgrah49
Tags: 2:1.4.1-0ubuntu0.11.10.2
* New upstream release v1.4.1
  - LP: #987305
  - Fix LP: #968122 - localization messed up

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 protoZilla.
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) 2000 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
 
 
37
 
// Logging of debug output
38
 
// The following define statement should occur before any include statements
39
 
#define FORCE_PR_LOG       /* Allow logging even in release build */
40
 
 
41
 
#include "enigmail.h"
42
 
#include "prlog.h"
43
 
#include "nsCOMPtr.h"
44
 
#include "mozilla/Mutex.h"
45
 
#include "nsIInputStream.h"
46
 
#include "nsIThread.h"
47
 
#include "nsIHttpChannel.h"
48
 
#include "nsIURI.h"
49
 
#include "nsNetUtil.h"
50
 
#include "nsStringGlue.h"
51
 
 
52
 
#ifdef XP_WIN
53
 
#include <windows.h>
54
 
#include <shellapi.h>
55
 
#endif
56
 
 
57
 
#include "nsPipeConsole.h"
58
 
 
59
 
#ifdef PR_LOGGING
60
 
PRLogModuleInfo* gPipeConsoleLog = NULL;
61
 
#endif
62
 
 
63
 
#define ERROR_LOG(args)    PR_LOG(gPipeConsoleLog,PR_LOG_ERROR,args)
64
 
#define WARNING_LOG(args)  PR_LOG(gPipeConsoleLog,PR_LOG_WARNING,args)
65
 
#define DEBUG_LOG(args)    PR_LOG(gPipeConsoleLog,PR_LOG_DEBUG,args)
66
 
 
67
 
#define NS_PIPE_CONSOLE_BUFFER_SIZE   (1024)
68
 
 
69
 
static const PRUint32 kCharMax = NS_PIPE_CONSOLE_BUFFER_SIZE;
70
 
 
71
 
///////////////////////////////////////////////////////////////////////////////
72
 
 
73
 
using namespace mozilla;
74
 
 
75
 
// nsPipeConsole implementation
76
 
 
77
 
// nsISupports implementation
78
 
NS_IMPL_THREADSAFE_ISUPPORTS4(nsPipeConsole,
79
 
                              nsIStreamListener,
80
 
                              nsIPipeListener,
81
 
                              nsIPipeConsole,
82
 
                              nsIRunnable)
83
 
 
84
 
 
85
 
// nsPipeConsole implementation
86
 
nsPipeConsole::nsPipeConsole()
87
 
  : mFinalized(PR_FALSE),
88
 
    mJoinable(PR_FALSE),
89
 
    mThreadJoined(PR_FALSE),
90
 
    mOverflowed(PR_FALSE),
91
 
 
92
 
    mLock("nsPipeConsole.lock"),
93
 
    mConsoleBuf(""),
94
 
    mConsoleMaxLines(0),
95
 
    mConsoleMaxCols(0),
96
 
 
97
 
    mByteCount(0),
98
 
    mConsoleLines(0),
99
 
    mConsoleLineLen(0),
100
 
    mConsoleNewChars(0),
101
 
 
102
 
    mPipeWrite(IPC_NULL_HANDLE),
103
 
    mPipeRead(IPC_NULL_HANDLE),
104
 
 
105
 
    mPipeThread(nsnull)
106
 
{
107
 
    NS_INIT_ISUPPORTS();
108
 
 
109
 
#ifdef PR_LOGGING
110
 
  if (gPipeConsoleLog == nsnull) {
111
 
    gPipeConsoleLog = PR_NewLogModule("nsPipeConsole");
112
 
  }
113
 
#endif
114
 
 
115
 
#ifdef FORCE_PR_LOG
116
 
  nsresult rv;
117
 
  nsCOMPtr<nsIThread> myThread;
118
 
  rv = ENIG_GET_THREAD(myThread);
119
 
  DEBUG_LOG(("nsPipeConsole:: <<<<<<<<< CTOR(%p): myThread=%p\n",
120
 
         this, myThread.get()));
121
 
#endif
122
 
}
123
 
 
124
 
 
125
 
nsPipeConsole::~nsPipeConsole()
126
 
{
127
 
  nsresult rv;
128
 
#ifdef FORCE_PR_LOG
129
 
  nsCOMPtr<nsIThread> myThread;
130
 
  rv = ENIG_GET_THREAD(myThread);
131
 
  DEBUG_LOG(("nsPipeConsole:: >>>>>>>>> DTOR(%p): myThread=%p\n",
132
 
         this, myThread.get()));
133
 
#endif
134
 
 
135
 
  if (mPipeThread) {
136
 
    DEBUG_LOG(("nsPipeConsole::destructor: terminating mPipeTread\n"));
137
 
    mPipeThread->Shutdown(); // ignore result, we need to shutdown anyway
138
 
    DEBUG_LOG(("nsPipeConsole::destructor: done\n"));
139
 
    mPipeThread = nsnull;
140
 
 }
141
 
 
142
 
  Finalize(PR_TRUE);
143
 
 
144
 
}
145
 
 
146
 
///////////////////////////////////////////////////////////////////////////////
147
 
// static functions used here
148
 
///////////////////////////////////////////////////////////////////////////////
149
 
 
150
 
PRStatus CreateInheritablePipe(IPCFileDesc* *readPipe,
151
 
                               IPCFileDesc* *writePipe,
152
 
                               EMBool readInherit,
153
 
                               EMBool writeInherit)
154
 
{
155
 
#ifndef XP_WIN
156
 
  PRStatus status;
157
 
 
158
 
  //status = PR_NewTCPSocketPair(fd);
159
 
  status = PR_CreatePipe(readPipe, writePipe);
160
 
  if (status != PR_SUCCESS)
161
 
    return status;
162
 
 
163
 
  status = PR_SetFDInheritable(*readPipe, readInherit);
164
 
  if (status != PR_SUCCESS)
165
 
    return status;
166
 
 
167
 
  status = PR_SetFDInheritable(*writePipe, writeInherit);
168
 
  if (status != PR_SUCCESS)
169
 
    return status;
170
 
 
171
 
  return PR_SUCCESS;
172
 
#else  // XPWIN
173
 
  BOOL bRetVal;
174
 
 
175
 
  // Security attributes for inheritable handles
176
 
  SECURITY_ATTRIBUTES securityAttr;
177
 
  securityAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
178
 
  securityAttr.lpSecurityDescriptor = NULL;
179
 
  securityAttr.bInheritHandle = TRUE;
180
 
 
181
 
  // Create pipe
182
 
  HANDLE hReadPipe, hWritePipe;
183
 
  bRetVal = CreatePipe( &hReadPipe, &hWritePipe,
184
 
                        &securityAttr, 0);
185
 
  if (!bRetVal)
186
 
    return PR_FAILURE;
187
 
 
188
 
  HANDLE hPipeTem;
189
 
 
190
 
  if (!readInherit) {
191
 
    // Make read handle uninheritable
192
 
    bRetVal = DuplicateHandle( GetCurrentProcess(),
193
 
                               hReadPipe,
194
 
                               GetCurrentProcess(),
195
 
                               &hPipeTem,
196
 
                               0,
197
 
                               FALSE,
198
 
                               DUPLICATE_SAME_ACCESS);
199
 
    CloseHandle(hReadPipe);
200
 
 
201
 
    if (!bRetVal) {
202
 
      CloseHandle(hWritePipe);
203
 
      return PR_FAILURE;
204
 
    }
205
 
    hReadPipe = hPipeTem;
206
 
  }
207
 
 
208
 
  if (!writeInherit) {
209
 
    // Make write handle uninheritable
210
 
    bRetVal = DuplicateHandle( GetCurrentProcess(),
211
 
                               hWritePipe,
212
 
                               GetCurrentProcess(),
213
 
                               &hPipeTem,
214
 
                               0,
215
 
                               FALSE,
216
 
                               DUPLICATE_SAME_ACCESS);
217
 
    CloseHandle(hWritePipe);
218
 
 
219
 
    if (!bRetVal) {
220
 
      CloseHandle(hReadPipe);
221
 
      return PR_FAILURE;
222
 
    }
223
 
    hWritePipe = hPipeTem;
224
 
  }
225
 
 
226
 
  *readPipe  = (void*) hReadPipe;
227
 
  *writePipe = (void*) hWritePipe;
228
 
#endif // XP_WIN
229
 
 
230
 
  return PR_SUCCESS;
231
 
}
232
 
 
233
 
#ifndef XP_WIN
234
 
#define EnigRead PR_Read
235
 
#else // XP_WIN
236
 
PRInt32 EnigRead(IPCFileDesc* fd, void *buf, PRInt32 amount)
237
 
{
238
 
  unsigned long bytes;
239
 
 
240
 
  if (ReadFile((HANDLE) fd,
241
 
               (LPVOID) buf,
242
 
               amount,
243
 
               &bytes,
244
 
               NULL)) {
245
 
    return bytes;
246
 
  }
247
 
 
248
 
  DWORD dwLastError = GetLastError();
249
 
 
250
 
  if (dwLastError == ERROR_BROKEN_PIPE)
251
 
    return 0;
252
 
 
253
 
  return -1;
254
 
}
255
 
#endif // XP_WIN
256
 
 
257
 
#ifndef XP_WIN
258
 
#define EnigClose PR_Close
259
 
#else // XP_WIN
260
 
PRStatus EnigClose(IPCFileDesc* fd)
261
 
{
262
 
  return (CloseHandle((HANDLE) fd)) ? PR_SUCCESS : PR_FAILURE;
263
 
}
264
 
#endif // XP_WIN
265
 
 
266
 
///////////////////////////////////////////////////////////////////////////////
267
 
// nsPipeConsole methods:
268
 
///////////////////////////////////////////////////////////////////////////////
269
 
 
270
 
nsresult
271
 
nsPipeConsole::Finalize(EMBool destructor)
272
 
{
273
 
  DEBUG_LOG(("nsPipeConsole::Finalize: \n"));
274
 
 
275
 
  if (mFinalized)
276
 
    return NS_OK;
277
 
 
278
 
  mFinalized = PR_TRUE;
279
 
 
280
 
  nsCOMPtr<nsIPipeConsole> self;
281
 
  if (!destructor) {
282
 
    // Hold a reference to ourselves to prevent our DTOR from being called
283
 
    // while finalizing. Automatically released upon returning.
284
 
    self = this;
285
 
  }
286
 
 
287
 
  // Close write pipe
288
 
  if (mPipeWrite) {
289
 
    EnigClose(mPipeWrite);
290
 
    mPipeWrite = IPC_NULL_HANDLE;
291
 
  }
292
 
 
293
 
  // Release owning refs
294
 
  mObserver = nsnull;
295
 
  mObserverContext = nsnull;
296
 
 
297
 
  // Clear console
298
 
  mConsoleBuf.Assign("");
299
 
  mConsoleLines = 0;
300
 
  mConsoleLineLen = 0;
301
 
  mConsoleNewChars = 0;
302
 
 
303
 
  mConsoleMaxLines = 0;
304
 
  mConsoleMaxCols = 0;
305
 
 
306
 
  return NS_OK;
307
 
}
308
 
 
309
 
nsresult
310
 
nsPipeConsole::Init()
311
 
{
312
 
  DEBUG_LOG(("nsPipeConsole::Init: \n"));
313
 
 
314
 
  // add shutdown observer
315
 
 
316
 
  nsCOMPtr<nsIObserverService> observ(do_GetService("@mozilla.org/observer-service;1"));
317
 
  if (observ)
318
 
    observ->AddObserver((nsIObserver*)(this),
319
 
                        NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_FALSE);
320
 
 
321
 
  return NS_OK;
322
 
}
323
 
 
324
 
///////////////////////////////////////////////////////////////////////////////
325
 
// nsIPipeConsole methods (thread-safe)
326
 
///////////////////////////////////////////////////////////////////////////////
327
 
 
328
 
NS_IMETHODIMP
329
 
nsPipeConsole::Open(PRInt32 maxRows, PRInt32 maxCols, EMBool joinable)
330
 
{
331
 
  nsresult rv;
332
 
 
333
 
  DEBUG_LOG(("nsPipeConsole::Open: %d, %d, %d\n", maxRows, maxCols,
334
 
                                                  (int) joinable));
335
 
  rv = Init();
336
 
  NS_ENSURE_SUCCESS(rv, rv);
337
 
 
338
 
  mJoinable = joinable;
339
 
 
340
 
  if ((maxRows < 0) || (maxCols < 0))
341
 
    return NS_ERROR_FAILURE;
342
 
 
343
 
  mConsoleMaxLines = maxRows;
344
 
  mConsoleMaxCols  = ((maxCols > 0) && (maxCols < 3)) ? 3: maxCols;
345
 
 
346
 
  // Create pipe pair
347
 
  PRStatus status = CreateInheritablePipe(&mPipeRead, &mPipeWrite,
348
 
                                              PR_FALSE, PR_TRUE);
349
 
  if (status != PR_SUCCESS) {
350
 
    ERROR_LOG(("nsPipeConsole::Open: CreateInheritablePipe failed\n"));
351
 
    return NS_ERROR_FAILURE;
352
 
  }
353
 
 
354
 
  // Spin up a new thread to handle STDOUT polling
355
 
  rv = NS_NewThread(getter_AddRefs(mPipeThread), this);
356
 
  DEBUG_LOG(("nsPipeConsole::Open: created new thread: %d", rv));
357
 
  NS_ENSURE_SUCCESS(rv, rv);
358
 
 
359
 
  return NS_OK;
360
 
}
361
 
 
362
 
 
363
 
 
364
 
NS_IMETHODIMP
365
 
nsPipeConsole::HasNewData(EMBool *_retval)
366
 
{
367
 
  MutexAutoLock lock(mLock);
368
 
 
369
 
  //DEBUG_LOG(("nsPipeConsole::HasNewData:\n"));
370
 
 
371
 
  *_retval = (mConsoleNewChars > 0);
372
 
 
373
 
  return NS_OK;
374
 
}
375
 
 
376
 
 
377
 
NS_IMETHODIMP
378
 
nsPipeConsole::GetData(char** _retval)
379
 
{
380
 
  DEBUG_LOG(("nsPipeConsole::GetData:\n"));
381
 
 
382
 
  mConsoleNewChars = mConsoleBuf.Length();
383
 
 
384
 
  return GetNewData(_retval);
385
 
}
386
 
 
387
 
 
388
 
NS_IMETHODIMP
389
 
nsPipeConsole::GetNewData(char** _retval)
390
 
{
391
 
  MutexAutoLock lock(mLock);
392
 
 
393
 
  DEBUG_LOG(("nsPipeConsole::GetNewData:\n"));
394
 
 
395
 
  if (!_retval)
396
 
    return NS_ERROR_NULL_POINTER;
397
 
 
398
 
  // Compute offset of "new" portion of string
399
 
  PRInt32 consoleLen = mConsoleBuf.Length();
400
 
  PRInt32 offset = consoleLen - mConsoleNewChars;
401
 
 
402
 
  if ((offset < 0) || (offset > consoleLen)) {
403
 
    ERROR_LOG(("nsPipeConsole::GetData: Internal error - Invalid console offset"));
404
 
    return NS_ERROR_FAILURE;
405
 
  }
406
 
 
407
 
  // Copy portion of console data to be returned
408
 
  nsCAutoString consoleCopy (mConsoleBuf);
409
 
  if (offset)
410
 
    consoleCopy.Cut(0,offset);
411
 
 
412
 
  // Replace any NULs with '0'
413
 
  PRInt32 nulIndex = 0;
414
 
  while (nulIndex != -1) {
415
 
    nulIndex = consoleCopy.FindChar(char(0));
416
 
    if (nulIndex != -1) {
417
 
      consoleCopy.Replace(nulIndex, 1, "0", 1);
418
 
    }
419
 
  }
420
 
 
421
 
  // Duplicate new C string
422
 
  *_retval = ToNewCString(consoleCopy);
423
 
  if (!*_retval)
424
 
    return NS_ERROR_OUT_OF_MEMORY;
425
 
 
426
 
  mConsoleNewChars = 0;
427
 
 
428
 
  return NS_OK;
429
 
}
430
 
 
431
 
///////////////////////////////////////////////////////////////////////////////
432
 
// nsIPipeListener methods (thread-safe)
433
 
///////////////////////////////////////////////////////////////////////////////
434
 
 
435
 
NS_IMETHODIMP
436
 
nsPipeConsole::Observe(nsIRequestObserver* observer, nsISupports* context)
437
 
{
438
 
  MutexAutoLock lock(mLock);
439
 
  DEBUG_LOG(("nsPipeConsole::Observe: %p, %p\n", observer, context));
440
 
 
441
 
  mObserver = observer;
442
 
  mObserverContext = context;
443
 
 
444
 
  return NS_OK;
445
 
}
446
 
 
447
 
 
448
 
NS_IMETHODIMP
449
 
nsPipeConsole::GetJoinable(EMBool *_retval)
450
 
{
451
 
  DEBUG_LOG(("nsPipeConsole::GetJoinable: %d\n", (int) mJoinable));
452
 
 
453
 
  *_retval = mJoinable;
454
 
 
455
 
  return NS_OK;
456
 
}
457
 
 
458
 
 
459
 
NS_IMETHODIMP
460
 
nsPipeConsole::Join()
461
 
{
462
 
  nsresult rv;
463
 
 
464
 
  if (!mJoinable)
465
 
    return NS_ERROR_FAILURE;
466
 
 
467
 
  {
468
 
    // Nested lock to avoid deadlock while waiting for Join
469
 
    MutexAutoLock lock(mLock);
470
 
    DEBUG_LOG(("nsPipeConsole::Join:\n"));
471
 
 
472
 
    if (mThreadJoined || !mPipeThread)
473
 
      return NS_OK;
474
 
 
475
 
    if (mPipeWrite) {
476
 
      // Close write pipe before joining
477
 
      EnigClose(mPipeWrite);
478
 
      mPipeWrite = IPC_NULL_HANDLE;
479
 
    }
480
 
 
481
 
    // Assume that this join will succeed to prevent double joining
482
 
    mThreadJoined = PR_TRUE;
483
 
  }
484
 
 
485
 
  DEBUG_LOG(("nsPipeConsole::terminating thread\n"));
486
 
  rv = mPipeThread->Shutdown();
487
 
  NS_ENSURE_SUCCESS(rv, rv);
488
 
 
489
 
  if (rv == NS_OK) mPipeThread=nsnull;
490
 
 
491
 
  return NS_OK;
492
 
}
493
 
 
494
 
 
495
 
NS_IMETHODIMP
496
 
nsPipeConsole::Shutdown()
497
 
{
498
 
  MutexAutoLock lock(mLock);
499
 
  DEBUG_LOG(("nsPipeConsole::Shutdown:\n"));
500
 
 
501
 
  Finalize(PR_FALSE);
502
 
 
503
 
  nsCOMPtr<nsIObserverService> observerSvc =
504
 
           do_GetService("@mozilla.org/observer-service;1");
505
 
 
506
 
  if (observerSvc) {
507
 
    observerSvc->RemoveObserver((nsIObserver*)(this),
508
 
                                NS_XPCOM_SHUTDOWN_OBSERVER_ID);
509
 
  }
510
 
 
511
 
  return NS_OK;
512
 
}
513
 
 
514
 
 
515
 
NS_IMETHODIMP
516
 
nsPipeConsole::GetFileDesc(IPCFileDesc* *_retval)
517
 
{
518
 
  MutexAutoLock lock(mLock);
519
 
 
520
 
  DEBUG_LOG(("nsPipeConsole::GetFileDesc:\n"));
521
 
 
522
 
  if (!_retval)
523
 
    return NS_ERROR_NULL_POINTER;
524
 
 
525
 
  if (mPipeWrite == IPC_NULL_HANDLE)
526
 
    return NS_ERROR_FAILURE;
527
 
 
528
 
  *_retval = mPipeWrite;
529
 
  return NS_OK;
530
 
}
531
 
 
532
 
 
533
 
NS_IMETHODIMP
534
 
nsPipeConsole::GetOverflowed(EMBool *_retval)
535
 
{
536
 
  MutexAutoLock lock(mLock);
537
 
 
538
 
  DEBUG_LOG(("nsPipeConsole::GetOverflowed: %d\n", (int) mOverflowed));
539
 
 
540
 
  *_retval = mOverflowed;
541
 
 
542
 
  return NS_OK;
543
 
}
544
 
 
545
 
 
546
 
NS_IMETHODIMP
547
 
nsPipeConsole::GetByteData(PRUint32 *count, char **data)
548
 
{
549
 
  MutexAutoLock lock(mLock);
550
 
 
551
 
  DEBUG_LOG(("nsPipeConsole::GetByteData:\n"));
552
 
 
553
 
  if (!count || !data)
554
 
    return NS_ERROR_NULL_POINTER;
555
 
 
556
 
  // Copy bytes
557
 
  *count = mConsoleBuf.Length();
558
 
  *data = reinterpret_cast<char*>(nsMemory::Alloc((*count)+1));
559
 
  if (!*data)
560
 
    return NS_ERROR_OUT_OF_MEMORY;
561
 
 
562
 
  memcpy(*data, mConsoleBuf.get(), *count);
563
 
 
564
 
  // NUL terminate byte array(just to be safe!)
565
 
  (*data)[*count] = '\0';
566
 
 
567
 
  mConsoleNewChars = 0;
568
 
 
569
 
  return NS_OK;
570
 
}
571
 
 
572
 
 
573
 
NS_IMETHODIMP
574
 
nsPipeConsole::Write(const char* str)
575
 
{
576
 
  // Note: Locking occurs in WriteBuf
577
 
 
578
 
  DEBUG_LOG(("nsPipeConsole::Write: %s\n", str));
579
 
 
580
 
  PRUint32 len = strlen(str);
581
 
  if (!len)
582
 
    return NS_OK;
583
 
 
584
 
  return WriteBuf(str, len);
585
 
}
586
 
 
587
 
NS_METHOD
588
 
nsPipeConsole::WriteBuf(const char* buf, PRUint32 count)
589
 
{
590
 
  MutexAutoLock lock(mLock);
591
 
 
592
 
  DEBUG_LOG(("nsPipeConsole::WriteBuf: %d\n", count));
593
 
 
594
 
  mByteCount += count;
595
 
 
596
 
  if ((count <= 0) || !mConsoleMaxLines)
597
 
    return NS_OK;
598
 
 
599
 
  PRInt32 consoleOldLen = mConsoleBuf.Length();
600
 
 
601
 
  PRInt32 appendOffset = 0;
602
 
 
603
 
  PRInt32 j;
604
 
 
605
 
  // Count and append new lines (folding extra-long lines)
606
 
  for (j=0; j<(PRInt32)count; j++) {
607
 
    if (buf[j] == '\n') {
608
 
      // End-of-line
609
 
      mConsoleLineLen = 0;
610
 
      mConsoleLines++;
611
 
 
612
 
    } else if (mConsoleMaxCols &&
613
 
               ((int)mConsoleLineLen >= mConsoleMaxCols)) {
614
 
      // Fold line
615
 
      mConsoleLineLen = 1;
616
 
      mConsoleLines++;
617
 
 
618
 
      // Append characters upto this point
619
 
      if (j > appendOffset)
620
 
        mConsoleBuf.Append(buf+appendOffset, j-appendOffset);
621
 
 
622
 
      // Append newline
623
 
      mConsoleBuf.Append('\n');
624
 
 
625
 
      appendOffset = j;
626
 
 
627
 
    } else {
628
 
      // Extend line
629
 
      mConsoleLineLen++;
630
 
    }
631
 
  }
632
 
 
633
 
  // Append all remaining characters
634
 
  mConsoleBuf.Append(buf+appendOffset, count-appendOffset);
635
 
 
636
 
  PRInt32 deleteLines = mConsoleLines - mConsoleMaxLines;
637
 
 
638
 
  PRInt32 consoleLen = mConsoleBuf.Length();
639
 
  mConsoleNewChars += consoleLen - consoleOldLen;
640
 
 
641
 
  if (deleteLines > 0) {
642
 
    PRInt32 newOffset;
643
 
    PRInt32 linesLocated = 0;
644
 
    PRInt32 offset = 0;
645
 
 
646
 
    mOverflowed = PR_TRUE;
647
 
 
648
 
    while ((offset < consoleLen) && (linesLocated < deleteLines)) {
649
 
      newOffset = mConsoleBuf.FindChar('\n', offset);
650
 
      if (newOffset == -1) break;
651
 
      offset = newOffset + 1;
652
 
      linesLocated++;
653
 
    }
654
 
 
655
 
    if (linesLocated != deleteLines) {
656
 
 
657
 
      ERROR_LOG(("nsPipeConsole::WriteBuf: linesLocated(%d) != deleteLines(%d)\n", linesLocated, deleteLines));
658
 
 
659
 
      return NS_ERROR_FAILURE;
660
 
    }
661
 
 
662
 
    mConsoleBuf.Cut(0,offset);
663
 
    mConsoleLines -= deleteLines;
664
 
  }
665
 
 
666
 
  if (mConsoleNewChars > mConsoleBuf.Length())
667
 
    mConsoleNewChars = mConsoleBuf.Length();
668
 
 
669
 
  return NS_OK;
670
 
}
671
 
 
672
 
///////////////////////////////////////////////////////////////////////////////
673
 
// nsIRequestObserver methods
674
 
///////////////////////////////////////////////////////////////////////////////
675
 
 
676
 
NS_IMETHODIMP
677
 
nsPipeConsole::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext)
678
 
{
679
 
  DEBUG_LOG(("nsPipeConsole::OnStartRequest:\n"));
680
 
 
681
 
  nsCOMPtr<nsIRequestObserver> observer;
682
 
  nsCOMPtr<nsISupports> observerContext;
683
 
  {
684
 
    MutexAutoLock lock(mLock);
685
 
 
686
 
    if (!mObserver)
687
 
      return NS_OK;
688
 
 
689
 
    observer = mObserver;
690
 
    observerContext = mObserverContext;
691
 
  }
692
 
 
693
 
  return observer->OnStartRequest(aRequest, observerContext);
694
 
}
695
 
 
696
 
NS_IMETHODIMP
697
 
nsPipeConsole::OnStopRequest(nsIRequest* aRequest, nsISupports* aContext,
698
 
                             nsresult aStatus)
699
 
{
700
 
  DEBUG_LOG(("nsPipeConsole::OnStopRequest:\n"));
701
 
 
702
 
  nsCOMPtr<nsIRequestObserver> observer;
703
 
  nsCOMPtr<nsISupports> observerContext;
704
 
  {
705
 
    MutexAutoLock lock(mLock);
706
 
 
707
 
    if (!mObserver)
708
 
      return NS_OK;
709
 
 
710
 
    observer = mObserver;
711
 
    observerContext = mObserverContext;
712
 
  }
713
 
 
714
 
  return observer->OnStopRequest(aRequest, observerContext, aStatus);
715
 
}
716
 
 
717
 
///////////////////////////////////////////////////////////////////////////////
718
 
// nsIStreamListener method
719
 
///////////////////////////////////////////////////////////////////////////////
720
 
 
721
 
NS_IMETHODIMP
722
 
nsPipeConsole::OnDataAvailable(nsIRequest* aRequest, nsISupports* aContext,
723
 
                              nsIInputStream *aInputStream,
724
 
                              PRUint32 aSourceOffset,
725
 
                              PRUint32 aLength)
726
 
{
727
 
  nsresult rv = NS_OK;
728
 
 
729
 
  DEBUG_LOG(("nsPipeConsole::OnDataAVailable: %d\n", aLength));
730
 
 
731
 
  char buf[kCharMax];
732
 
  PRUint32 readCount, readMax;
733
 
 
734
 
  while (aLength > 0) {
735
 
    readMax = (aLength < kCharMax) ? aLength : kCharMax;
736
 
    rv = aInputStream->Read((char *) buf, readMax, &readCount);
737
 
    if (NS_FAILED(rv)){
738
 
      ERROR_LOG(("nsPipeConsole::OnDataAvailable: Error in reading from input stream, %x\n", rv));
739
 
      return rv;
740
 
    }
741
 
 
742
 
    if (readCount <= 0) return NS_OK;
743
 
 
744
 
    rv = WriteBuf(buf, readCount);
745
 
    NS_ENSURE_SUCCESS(rv, rv);
746
 
 
747
 
    aLength -= readCount;
748
 
  }
749
 
 
750
 
  return NS_OK;
751
 
}
752
 
 
753
 
///////////////////////////////////////////////////////////////////////////////
754
 
// nsIRunnable methods:
755
 
// (runs as a new thread)
756
 
///////////////////////////////////////////////////////////////////////////////
757
 
 
758
 
NS_IMETHODIMP
759
 
nsPipeConsole::Run()
760
 
{
761
 
  nsresult rv = NS_OK;
762
 
 
763
 
#ifdef FORCE_PR_LOG
764
 
  nsCOMPtr<nsIThread> myThread;
765
 
  rv = ENIG_GET_THREAD(myThread);
766
 
  DEBUG_LOG(("nsPipeConsole::Run: myThread=%p\n", myThread.get()));
767
 
#endif
768
 
 
769
 
  // Blocked read loop
770
 
  while (1) {
771
 
    char buf[kCharMax];
772
 
    PRInt32 readCount;
773
 
 
774
 
    // Read data from pipe (blocking)
775
 
    readCount = EnigRead(mPipeRead, (char *) buf, kCharMax);
776
 
 
777
 
    DEBUG_LOG(("nsPipeConsole::Run: Read %d chars\n", readCount));
778
 
 
779
 
    if (readCount <= 0)
780
 
      break;
781
 
 
782
 
    // Append data read to console
783
 
    WriteBuf(buf, readCount);
784
 
  }
785
 
 
786
 
  // Clear any NSPR interrupt
787
 
  PR_ClearInterrupt();
788
 
 
789
 
  // Close read pipe
790
 
  EnigClose(mPipeRead);
791
 
  mPipeRead = IPC_NULL_HANDLE;
792
 
 
793
 
  return NS_OK;
794
 
}
795
 
 
796
 
//-----------------------------------------------------------------------------
797
 
// nsIObserver impl
798
 
//-----------------------------------------------------------------------------
799
 
 
800
 
NS_IMETHODIMP
801
 
nsPipeConsole::Observe(nsISupports *subject, const char *aTopic, const PRUnichar *data)
802
 
{
803
 
    DEBUG_LOG(("nsPipeConsole::Observe: topic=%s\n", aTopic));
804
 
 
805
 
    if (!PL_strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
806
 
      Shutdown();
807
 
    }
808
 
    return NS_OK;
809
 
}