xref: /trunk/main/extensions/workben/testpgp.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_extensions.hxx"
26 #include <sal/types.h>
27 #include <rtl/memory.h>
28 #ifndef _RTL_WSTRING_
29 #include <rtl/wstring>
30 #endif
31 #include <vos/macros.hxx>
32 
33 #ifndef _USR_SMARTSERVICES_HXX_
34 #include <usr/smartservices.hxx>
35 #endif
36 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
37 #include <com/sun/star/io/XInputStream.hpp>
38 #include <com/sun/star/io/XOutputStream.hpp>
39 #include <com/sun/star/pgp/RecipientsEvent.hpp>
40 #include <com/sun/star/pgp/SignatureEvent.hpp>
41 #include <com/sun/star/pgp/XPGPDecoder.hpp>
42 #include <com/sun/star/pgp/XPGPDecoderListener.hpp>
43 #include <com/sun/star/pgp/XPGPEncoder.hpp>
44 #include <com/sun/star/pgp/XPGPPreferences.hpp>
45 #include <com/sun/star/uno/XInterface.hpp>
46 #include <com/sun/star/uno/Any.h>
47 #include <com/sun/star/uno/Reference.h>
48 #include <com/sun/star/uno/Sequence.hxx>
49 #include <cppuhelper/weak.hxx>
50 
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <string.h>
54 
55 #include <fcntl.h>
56 #include <io.h>
57 
58 using namespace com::sun::star::lang;
59 using namespace com::sun::star::io;
60 using namespace com::sun::star::pgp;
61 using namespace com::sun::star::uno;
62 
63 /*========================================================================
64  *
65  * DataSource_Impl interface.
66  *
67  *======================================================================*/
68 class DataSource_Impl :
69     public OWeakObject,
70     public XInputStream
71 {
72     Sequence<sal_Int8> m_buffer;
73     sal_Int32          m_position;
74     int                m_fd;
75 
76 public:
77     DataSource_Impl (int fd = 0);
78     virtual ~DataSource_Impl (void);
79 
80     void setBuffer (const Sequence<sal_Int8> &rBuffer);
81 
82     /** XInterface.
83      */
84     virtual sal_Bool SAL_CALL queryInterface (
85         const Uik &rUik, Any &rIfc);
86 
87     virtual void SAL_CALL acquire (void);
88 
89     virtual void SAL_CALL release (void);
90 
91     /** XInputStream.
92      */
93     virtual sal_Int32 SAL_CALL readBytes (
94         Sequence<sal_Int8> &rData, sal_Int32 nBytesToRead);
95 
96     virtual sal_Int32 SAL_CALL readSomeBytes (
97         Sequence<sal_Int8> &rData, sal_Int32 nMaxBytesToRead);
98 
99     virtual void SAL_CALL skipBytes (sal_Int32 nBytesToSkip);
100 
101     virtual sal_Int32 SAL_CALL available (void);
102 
103     virtual void SAL_CALL closeInput (void);
104 };
105 
106 /*========================================================================
107  *
108  * DataSink_Impl interface.
109  *
110  *======================================================================*/
111 class DataSink_Impl :
112     public OWeakObject,
113     public XOutputStream
114 {
115     Sequence<sal_Int8> m_buffer;
116 
117 public:
118     DataSink_Impl (void);
119     virtual ~DataSink_Impl (void);
120 
getBuffer(void) const121     const Sequence<sal_Int8>& getBuffer (void) const { return m_buffer; }
122 
123     /** XInterface.
124      */
125     virtual sal_Bool SAL_CALL queryInterface (
126         const Uik &rUik, Any &rIfc);
127 
128     virtual void SAL_CALL acquire (void);
129     virtual void SAL_CALL release (void);
130 
131     /** XOutputStream.
132      */
133     virtual void SAL_CALL writeBytes (
134         const Sequence<sal_Int8> &rBuffer);
135 
136     virtual void SAL_CALL flush (void);
137 
138     virtual void SAL_CALL closeOutput (void);
139 };
140 
141 /*========================================================================
142  *
143  * DecoderListener_Impl interface.
144  *
145  *======================================================================*/
146 class DecoderListener_Impl :
147     public OWeakObject,
148     public XPGPDecoderListener
149 {
150 public:
151     DecoderListener_Impl (void);
152     virtual ~DecoderListener_Impl (void);
153 
154     /** XInterface.
155      */
156     virtual sal_Bool SAL_CALL queryInterface (
157         const Uik &rUik, Any &rIfc);
158 
159     virtual void SAL_CALL acquire (void);
160 
161     virtual void SAL_CALL release (void);
162 
163     /** XEventListener.
164      */
165     virtual void SAL_CALL disposing (const EventObject &rSource);
166 
167     /** XPGPDecoderListener.
168      */
169     virtual void SAL_CALL decrypted (const RecipientsEvent &rEvent);
170     virtual void SAL_CALL verified  (const SignatureEvent &rEvent);
171 };
172 
173 /*========================================================================
174  *
175  * DataSource_Impl implementation.
176  *
177  *======================================================================*/
178 /*
179  * DataSource_Impl.
180  */
DataSource_Impl(int fd)181 DataSource_Impl::DataSource_Impl (int fd)
182     : m_fd (fd), m_position (0)
183 {
184 }
185 
186 /*
187  * ~DataSource_Impl.
188  */
~DataSource_Impl(void)189 DataSource_Impl::~DataSource_Impl (void)
190 {
191 }
192 
193 /*
194  * DataSource_Impl: setBuffer.
195  */
setBuffer(const Sequence<sal_Int8> & rBuffer)196 void DataSource_Impl::setBuffer (const Sequence<sal_Int8> &rBuffer)
197 {
198     m_buffer = rBuffer;
199     if (!m_buffer.getLength())
200     {
201         // Fill buffer from file descriptor.
202         char buffer[1024];
203         rtl_zeroMemory (buffer, sizeof(buffer));
204 
205         int k = read (m_fd, buffer, sizeof(buffer));
206         while (k > 0)
207         {
208             sal_Int32 n = m_buffer.getLength();
209             m_buffer.realloc (n + k);
210 
211             rtl_copyMemory (m_buffer.getArray() + n, buffer, k);
212             n += k;
213 
214             rtl_zeroMemory (buffer, k);
215             k = read (m_fd, buffer, sizeof(buffer));
216         }
217     }
218     m_position = 0;
219 }
220 
221 /*
222  * XInterface: queryInterface.
223  */
queryInterface(const Uik & rUik,Any & rIfc)224 sal_Bool SAL_CALL DataSource_Impl::queryInterface (
225     const Uik &rUik, Any &rIfc)
226 {
227     if (com::sun::star::uno::queryInterface (
228         rUik, rIfc,
229         SAL_STATIC_CAST (XInputStream*, this)))
230         return sal_True;
231     else
232         return OWeakObject::queryInterface (rUik, rIfc);
233 }
234 
235 /*
236  * XInterface: acquire.
237  */
acquire(void)238 void SAL_CALL DataSource_Impl::acquire (void)
239 {
240     OWeakObject::acquire();
241 }
242 
243 /*
244  * XInterface: release.
245  */
release(void)246 void SAL_CALL DataSource_Impl::release (void)
247 {
248     OWeakObject::release();
249 }
250 
251 /*
252  * XInputStream: readBytes.
253  */
readBytes(Sequence<sal_Int8> & rData,sal_Int32 nBytesToRead)254 sal_Int32 SAL_CALL DataSource_Impl::readBytes (
255     Sequence<sal_Int8> &rData, sal_Int32 nBytesToRead)
256 {
257     if (nBytesToRead < 0)
258         throw IOException();
259 
260     sal_Int32 k = m_buffer.getLength() - m_position;
261     k = VOS_BOUND(k, 0, nBytesToRead);
262     if (k > 0)
263     {
264         rData.realloc(k);
265         rtl_copyMemory (
266             rData.getArray(), m_buffer.getConstArray() + m_position, k);
267         m_position += k;
268     }
269     return k;
270 }
271 
272 /*
273  * XInputStream: readSomeBytes.
274  */
readSomeBytes(Sequence<sal_Int8> & rData,sal_Int32 nMaxBytesToRead)275 sal_Int32 SAL_CALL DataSource_Impl::readSomeBytes (
276     Sequence<sal_Int8> &rData, sal_Int32 nMaxBytesToRead)
277 {
278     return readBytes (rData, nMaxBytesToRead);
279 }
280 
281 /*
282  * XInputStream: skipBytes.
283  */
skipBytes(sal_Int32 nBytesToSkip)284 void SAL_CALL DataSource_Impl::skipBytes (sal_Int32 nBytesToSkip)
285 {
286     if (nBytesToSkip < 0)
287         throw IOException();
288 
289     m_position += nBytesToSkip;
290 }
291 
292 /*
293  * XInputStream: available.
294  */
available(void)295 sal_Int32 SAL_CALL DataSource_Impl::available (void)
296 {
297     sal_Int32 k = m_buffer.getLength() - m_position;
298     return ((k > 0) ? k : 0);
299 }
300 
301 /*
302  * XInputStream: closeInput.
303  */
closeInput(void)304 void SAL_CALL DataSource_Impl::closeInput (void)
305 {
306 }
307 
308 /*========================================================================
309  *
310  * DataSink_Impl implementation.
311  *
312  *======================================================================*/
313 /*
314  * DataSink_Impl.
315  */
DataSink_Impl(void)316 DataSink_Impl::DataSink_Impl (void)
317 {
318 }
319 
320 /*
321  * ~DataSink_Impl.
322  */
~DataSink_Impl(void)323 DataSink_Impl::~DataSink_Impl (void)
324 {
325 }
326 
327 /*
328  * XInterface: queryInterface.
329  */
queryInterface(const Uik & rUik,Any & rIfc)330 sal_Bool SAL_CALL DataSink_Impl::queryInterface (
331     const Uik &rUik, Any &rIfc)
332 {
333     if (com::sun::star::uno::queryInterface (
334         rUik, rIfc,
335         SAL_STATIC_CAST (XOutputStream*, this)))
336         return sal_True;
337     else
338         return OWeakObject::queryInterface (rUik, rIfc);
339 }
340 
341 /*
342  * XInterface: acquire.
343  */
acquire(void)344 void SAL_CALL DataSink_Impl::acquire (void)
345 {
346     OWeakObject::acquire();
347 }
348 
349 /*
350  * XInterface: release.
351  */
release(void)352 void SAL_CALL DataSink_Impl::release (void)
353 {
354     OWeakObject::release();
355 }
356 
357 /*
358  * XOutputStream: writeBytes.
359  */
writeBytes(const Sequence<sal_Int8> & rBuffer)360 void SAL_CALL DataSink_Impl::writeBytes (const Sequence<sal_Int8> &rBuffer)
361 {
362     if (rBuffer.getLength())
363     {
364         sal_Int32 n = m_buffer.getLength();
365         m_buffer.realloc (n + rBuffer.getLength());
366 
367         rtl_copyMemory (
368             m_buffer.getArray() + n,
369             rBuffer.getConstArray(),
370             rBuffer.getLength());
371     }
372 }
373 
374 /*
375  * XOutputStream: flush.
376  */
flush(void)377 void SAL_CALL DataSink_Impl::flush (void)
378 {
379     if (m_buffer.getLength())
380     {
381         // Write data to stdout.
382         const sal_Int8 *pData = m_buffer.getConstArray();
383         sal_Int32       nData = m_buffer.getLength();
384 
385         int prev = ::setmode (1, O_BINARY);
386         if (!(prev < 0))
387         {
388             int k = ::write (1, pData, nData);
389             if (k > 0)
390                 ::write (1, "\n", 1);
391             ::setmode (1, prev);
392         }
393     }
394 }
395 
396 /*
397  * XOutputStream: closeOutput.
398  */
closeOutput(void)399 void SAL_CALL DataSink_Impl::closeOutput (void)
400 {
401     flush();
402 }
403 
404 /*========================================================================
405  *
406  * DecoderListener_Impl implementation.
407  *
408  *======================================================================*/
409 /*
410  * DecoderListener_Impl.
411  */
DecoderListener_Impl(void)412 DecoderListener_Impl::DecoderListener_Impl (void)
413 {
414 }
415 
416 /*
417  * ~DecoderListener_Impl.
418  */
~DecoderListener_Impl(void)419 DecoderListener_Impl::~DecoderListener_Impl (void)
420 {
421 }
422 
423 /*
424  * XInterface: queryInterface.
425  */
queryInterface(const Uik & rUik,Any & rIfc)426 sal_Bool SAL_CALL DecoderListener_Impl::queryInterface (
427     const Uik &rUik, Any &rIfc)
428 {
429     if (com::sun::star::uno::queryInterface (
430         rUik, rIfc,
431         SAL_STATIC_CAST (XEventListener*, this),
432         SAL_STATIC_CAST (XPGPDecoderListener*, this)))
433         return sal_True;
434     else
435         return OWeakObject::queryInterface (rUik, rIfc);
436 }
437 
438 /*
439  * XInterface: acquire.
440  */
acquire(void)441 void SAL_CALL DecoderListener_Impl::acquire (void)
442 {
443     OWeakObject::acquire();
444 }
445 
446 /*
447  * XInterface: release.
448  */
release(void)449 void SAL_CALL DecoderListener_Impl::release (void)
450 {
451     OWeakObject::release();
452 }
453 
454 /*
455  * XEventListener: disposing.
456  */
disposing(const EventObject & rSource)457 void SAL_CALL DecoderListener_Impl::disposing (const EventObject &rSource)
458 {
459 }
460 
461 /*
462  * XPGPDecoderListener: decrypted.
463  */
decrypted(const RecipientsEvent & rEvent)464 void SAL_CALL DecoderListener_Impl::decrypted (const RecipientsEvent &rEvent)
465 {
466 }
467 
468 /*
469  * XPGPDecoderListener: verified.
470  */
verified(const SignatureEvent & rEvent)471 void SAL_CALL DecoderListener_Impl::verified (const SignatureEvent &rEvent)
472 {
473 }
474 
475 /*========================================================================
476  *
477  * Main.
478  *
479  *======================================================================*/
S2U(const sal_Char * ascii)480 inline rtl::OWString S2U (const sal_Char *ascii)
481 {
482     return rtl::OWString::createFromAscii (ascii);
483 }
484 
485 #if 0  /* OLD */
486 
487 /*
488  * queryModuleActivator.
489  */
490 BOOL queryModuleActivator (
491     const XServiceManagerRef &rxManager,
492     XServiceActivatorRef     &rxActivator)
493 {
494     XServiceProviderRef xProv;
495     XInterfaceRef       xProvInst;
496 
497     xProv = rxManager->queryServiceProvider (
498         L"stardiv.uno.ServiceActivator.module");
499     if (!xProv.is())
500     {
501         printf ("Error: no ServiceActivator service.\n");
502         return FALSE;
503     }
504 
505     xProvInst = xProv->createInstance();
506     if (!xProvInst.is())
507     {
508         printf ("Error: no ServiceActivator instance.\n");
509         return FALSE;
510     }
511 
512     return xProvInst->queryInterface (
513         XServiceActivator::getSmartUik(), rxActivator);
514 }
515 
516 /*
517  * install.
518  */
519 BOOL install (
520     const XServiceActivatorRef &rxActivator,
521     const char                 *prefix)
522 {
523     String aModule ("module://");
524     char   pBuffer[1024];
525 
526     vos::ORealDynamicLoader::computeModuleName (
527         prefix, pBuffer, sizeof(pBuffer));
528     aModule += pBuffer;
529 
530     return rxActivator->install (
531         StringToUString (aModule, CHARSET_SYSTEM));
532 }
533 
534 /*
535  * uninstall.
536  */
537 BOOL uninstall (
538     const XServiceActivatorRef &rxActivator,
539     const char                 *prefix)
540 {
541     String aModule ("module://");
542     char   pBuffer[1024];
543 
544     vos::ORealDynamicLoader::computeModuleName (
545         prefix, pBuffer, sizeof(pBuffer));
546     aModule += pBuffer;
547 
548     return rxActivator->deinstall (
549         StringToUString (aModule, CHARSET_SYSTEM));
550 }
551 
552 #endif /* OLD */
553 
554 /*
555  * main.
556  */
main(int argc,char ** argv)557 int SAL_CALL main (int argc, char **argv)
558 {
559     enum Option
560     {
561         OPTION_INSTALL   = 0x01,
562         OPTION_UNINSTALL = 0x02,
563 
564         OPTION_DECRYPT   = 0x04,
565         OPTION_ENCRYPT   = 0x08,
566         OPTION_SIGN      = 0x10,
567 
568         OPTION_FILE      = 0x20,
569         OPTION_HELP      = 0x40
570     };
571 
572     int fd = 0;
573     unsigned long nOptions = 0;
574 
575     for (int i = 1; i < argc; i++)
576     {
577         const char *opt = argv[i];
578         if (opt[0] == '-')
579         {
580             switch (opt[1])
581             {
582                 case 'i':
583                     nOptions |= OPTION_INSTALL;
584                     break;
585 
586                 case 'u':
587                     nOptions |= OPTION_UNINSTALL;
588                     break;
589 
590                 case 'd':
591                     nOptions |= OPTION_DECRYPT;
592                     break;
593 
594                 case 'e':
595                     nOptions |= OPTION_ENCRYPT;
596                     break;
597 
598                 case 's':
599                     nOptions |= OPTION_SIGN;
600                     break;
601 
602                 case 'f':
603                     nOptions |= OPTION_FILE;
604                     break;
605 
606                 case 'h':
607                 default:
608                     nOptions |= OPTION_HELP;
609                     break;
610             }
611         }
612         else
613         {
614             if (nOptions & OPTION_FILE)
615             {
616                 if ((fd = open (argv[i], O_RDONLY | O_BINARY)) < 0)
617                 {
618                     printf ("Error: can't open file: %s\n", argv[i]);
619                     exit (0);
620                 }
621             }
622         }
623     }
624 
625     if ((nOptions == 0) || (nOptions & OPTION_HELP))
626     {
627         printf ("Options:\n");
628         printf ("-i\tinstall module\n");
629         printf ("-u\tuninstall module\n");
630         printf ("-d\tdecrypt and verify\n");
631         printf ("-e\tencrypt test pattern\n");
632         printf ("-s\tsign test pattern\n");
633         printf ("-h\thelp\n");
634         exit (0);
635     }
636 
637     Reference<XMultiServiceFactory> xManager (
638         usr::createDefaultSmartRegistryServiceFactory());
639     if (!xManager.is())
640     {
641         printf ("Error: no ProcessServiceManager.\n");
642         exit (1);
643     }
644     usr::setProcessServiceFactory (xManager);
645 
646     if (nOptions & OPTION_INSTALL)
647     {
648 #if 0  /* OLD */
649         XServiceActivatorRef xActivator;
650         if (queryModuleActivator (xManager, xActivator))
651         {
652             if (install (xActivator, "pgp"))
653                 printf ("Module PGP installed.\n");
654             else
655                 printf ("Error: module PGP not installed.\n");
656         }
657         nOptions &= ~OPTION_INSTALL;
658 #endif /* OLD */
659     }
660 
661     if (nOptions & (OPTION_DECRYPT | OPTION_ENCRYPT | OPTION_SIGN))
662     {
663         Reference<XMultiServiceFactory> xProv (
664             xManager->createInstance (
665                 S2U("com.sun.star.pgp.PGPFactory")),
666             UNO_QUERY);
667         if (!xProv.is())
668         {
669             printf ("Error: no PGPFactory service.\n");
670             exit (1);
671         }
672 
673         Reference<XInterface> xProvInst (
674             xProv->createInstance (
675                 S2U("com.sun.star.pgp.SimplePGPMailer")));
676         if (!xProvInst.is())
677         {
678             printf ("Error: no SimplePGPMailer service.\n");
679             exit (2);
680         }
681 
682         Reference<XPGPPreferences> xPrefs (xProvInst, UNO_QUERY);
683         if (xPrefs.is())
684         {
685             unsigned long nDefaults = 0;
686 
687             if (xPrefs->getEncryptByDefault())
688                 nDefaults |= OPTION_ENCRYPT;
689             if (xPrefs->getSignByDefault())
690                 nDefaults |= OPTION_SIGN;
691             if (xPrefs->getAutoDecrypt())
692                 nDefaults |= OPTION_DECRYPT;
693 
694             if (nDefaults)
695             {
696             }
697         }
698 
699         static const sal_Int8 pData[] = "" /* "Hello PGP World." */;
700         Sequence<sal_Int8> buffer (pData, sizeof (pData) - 1);
701 
702         if (nOptions & (OPTION_ENCRYPT | OPTION_SIGN))
703         {
704             Reference<XPGPEncoder> xEncoder (xProvInst, UNO_QUERY);
705             if (!xEncoder.is())
706             {
707                 printf ("Error: no PGPEncoder interface.\n");
708                 exit (4);
709             }
710 
711             DataSource_Impl *source = new DataSource_Impl (fd);
712             source->setBuffer (buffer);
713 
714             DataSink_Impl *sink = new DataSink_Impl;
715 
716             Reference<XInputStream>  xPlainText  (source);
717             Reference<XOutputStream> xCipherText (sink);
718 
719             if (nOptions & OPTION_ENCRYPT)
720             {
721                 rtl::OWString aRecipients[] =
722                 {
723                     S2U("er@stardiv.de"),
724                     // L"mhu@stardivision.de",
725                     S2U("mhu@rabbit")
726                 };
727 
728                 sal_Int32 nRecipients =
729                     sizeof(aRecipients) / sizeof(aRecipients[0]);
730 
731                 if (nOptions & OPTION_SIGN)
732                 {
733                     xEncoder->encryptAndSign (
734                         Sequence<rtl::OWString>(aRecipients, nRecipients),
735                         xPlainText,
736                         xCipherText);
737                     nOptions &= ~OPTION_SIGN;
738                 }
739                 else
740                 {
741                     xEncoder->encrypt (
742                         Sequence<rtl::OWString>(aRecipients, nRecipients),
743                         xPlainText,
744                         xCipherText);
745                 }
746                 nOptions &= ~OPTION_ENCRYPT;
747             }
748 
749             if (nOptions & OPTION_SIGN)
750             {
751                 sal_Bool bDataIsAscii = (fd == 0); // stdin.
752 
753                 xEncoder->sign (
754                     bDataIsAscii,
755                     xPlainText,
756                     xCipherText);
757                 nOptions &= ~OPTION_SIGN;
758             }
759 
760             buffer = sink->getBuffer();
761         }
762 
763         if (nOptions & OPTION_DECRYPT)
764         {
765             Reference<XPGPDecoder> xDecoder (xProvInst, UNO_QUERY);
766             if (!xDecoder.is())
767             {
768                 printf ("Error: no PGPDecoder interface.\n");
769                 exit (5);
770             }
771 
772             DataSource_Impl *source = new DataSource_Impl;
773             source->setBuffer (buffer);
774 
775             DataSink_Impl *sink = new DataSink_Impl;
776 
777             Reference<XInputStream>  xCipherText (source);
778             Reference<XOutputStream> xPlainText  (sink);
779 
780             Reference<XPGPDecoderListener> xListener (
781                 new DecoderListener_Impl);
782             xDecoder->addDecoderListener (xListener);
783 
784             xDecoder->decryptAndVerify (
785                 xCipherText,
786                 xPlainText);
787             nOptions &= ~OPTION_DECRYPT;
788 
789             xDecoder->removeDecoderListener (xListener);
790 
791             buffer = sink->getBuffer();
792         }
793     }
794 
795     if (nOptions & OPTION_UNINSTALL)
796     {
797 #if 0  /* OLD */
798         XServiceActivatorRef xActivator;
799         if (queryModuleActivator (xManager, xActivator))
800         {
801             if (uninstall (xActivator, "pgp"))
802                 printf ("Module PGP uninstalled.\n");
803             else
804                 printf ("Error: module PGP not uninstalled.\n");
805         }
806         nOptions &= ~OPTION_UNINSTALL;
807 #endif /* OLD */
808     }
809 
810     return 0;
811 }
812