home *** CD-ROM | disk | FTP | other *** search
/ PC-Online 1998 February / PCOnline_02_1998.iso / filesbbs / win3x / pgpjn.exe / JNSOURCE.ZIP / PGPJN.CPP < prev    next >
C/C++ Source or Header  |  1995-12-11  |  15KB  |  467 lines

  1. //    PGPJN.CPP
  2. //    Runtime Loadable Encryptor Extension for Pegasus Mail for Windows.
  3. //    Copyright (c) 1995, David Harris, All Rights Reserved.
  4. //
  5. //    Pretty Good Privacy modifications by John Navas
  6. //    Copyright (c) 1995, John Navas, All Rights Reserved.
  7. //
  8. //    The author grants explicit permission for this source code to be
  9. //    used or modified as required, subject only to the conditions that
  10. //    the copyright notices above are preserved; that this source code
  11. //    not be used in any product distributed in competition with this
  12. //  product; that by using this code you agree that the code is
  13. //    provided without warranty of any kind, either explicit or implied,
  14. //    and you use it at your own risk.
  15. //
  16. //    This module implements an interface to Pretty Good Privacy (tm)
  17. //    and (c) Copyright 1990-1994 Philip Zimmermann. All rights reserved.
  18. //
  19. //    The Massachusetts Institute of Technology is the distributor of PGP
  20. //    version 2.6, for distribution in the USA only.  It is available from
  21. //    "net-dist.mit.edu," a controlled FTP site that has restrictions and
  22. //    limitations, similar to those used by RSA Data Security, Inc., to comply
  23. //    with export control requirements.  The software resides in the directory
  24. //    /pub/PGP.
  25.  
  26. #include "pgpjn.h"
  27. #include "resource.h"
  28.  
  29. #define VERSION    (0x100)                    // version of WinPMail Forms I work with
  30.  
  31. ///////////////////////////////////////////////////////////////////////////////
  32. // set in LibMain, used throughout the DLL
  33.  
  34. HINSTANCE hLibInstance;                    // my instance
  35. HWND hwndParent = NULL;                    // handle of WinPMail parent window
  36. MODE MyMode = PUB;                        // my Form mode
  37. char MyDir[_MAX_DRIVE+_MAX_DIR];        // my directory
  38. char PGPpath[_MAX_PATH];                // PGP executable
  39. char* TEMP;                                // TEMP directory for PGPJNDOS
  40.  
  41. char PGPEXE[_MAX_FNAME+_MAX_EXT];        // PGP executable
  42. char PGPJNDOS[_MAX_FNAME+_MAX_EXT];        // my special EXE
  43.  
  44. char PGPBegin[MAXTAG];                    // start of PGP encrypted section
  45. char PGPEnd[MAXTAG];                    // end of PGP encrypted section
  46. char PGPBeginKey[MAXTAG];                // start of PGP public key
  47. char PGPEndKey[MAXTAG];                    // end of PGP public key
  48.  
  49. char SigGood[MAXTAG];                    // PGP good sig message
  50. char SigBad[MAXTAG];                    // PGP bad sig message
  51. char SigNoKey[MAXTAG];                    // PGP missing key to verify sig
  52.  
  53. char PGPBeginAdvise[MAXTAG];            // start of PGP public key
  54. char PGPEndAdvise[MAXTAG];                // end of PGP public key
  55.  
  56. char PGPJNKey[128] = { '\0' };            // Master Key option
  57.  
  58. ///////////////////////////////////////////////////////////////////////////////
  59.  
  60. static BOOL Ctl3D = FALSE;                // whether or not CTL3D registered
  61.  
  62. ///////////////////////////////////////////////////////////////////////////////
  63.  
  64. #ifdef _DEBUG
  65. void
  66. _cdecl
  67. MyDebugOutput(
  68. LPCSTR lpszFmt,
  69. ...
  70. )
  71. {
  72.     char buf[256];
  73.     va_list arg;
  74.  
  75.     va_start(arg, lpszFmt);
  76.     wvsprintf(buf, lpszFmt, &va_arg(arg, int));
  77.     OutputDebugString(buf);
  78.     va_end(arg);
  79. }
  80. #endif // _DEBUG
  81.  
  82. ///////////////////////////////////////////////////////////////////////////////
  83. // CHECK (SYSTEM) RESOURCES
  84.  
  85. BOOL                                    // FALSE if OK; TRUE if too low
  86. CheckResources()
  87. {
  88.     // check system resources
  89.     typedef struct {
  90.         UINT type;                UINT min;
  91.     } RESOURCE;
  92.     RESOURCE res[] = {
  93.         { GFSR_SYSTEMRESOURCES,    MINRES },
  94.         { GFSR_GDIRESOURCES,    MINRES },
  95.         { GFSR_USERRESOURCES,    MINRES }
  96.     };
  97.     for (int n = 0; n < sizeof(res)/sizeof(res[0]); ++n)
  98.         if (GetFreeSystemResources(res[n].type) < res[n].min)
  99.             return TRUE;
  100.     
  101.     // check heap space
  102.     {
  103.         void* ptr = malloc(16000);
  104.         
  105.         if (! ptr)
  106.             return TRUE;
  107.         free(ptr);
  108.     }
  109.  
  110.     // check DOS memory
  111.     {
  112.         DWORD mem = GlobalDosAlloc(1024);
  113.         
  114.         if (! mem)
  115.             return TRUE;
  116.         GlobalDosFree((UINT) mem);
  117.     }
  118.     
  119.     // made it!
  120.     return FALSE;
  121. }
  122.  
  123. ///////////////////////////////////////////////////////////////////////////////
  124. // ADD FILENAME TO AN EXISTING PATH
  125.  
  126. char*                                    // complete pathname
  127. AddFileName(
  128. char* path,                                // directory path
  129. const char* file                        // filename to add
  130. )
  131. {
  132.     char drive[_MAX_DRIVE];
  133.     char dir[_MAX_DIR];
  134.     char fname[_MAX_FNAME];
  135.     char ext[_MAX_EXT];
  136.  
  137.     _splitpath(path, drive, dir, fname, ext);    // check dir
  138.  
  139.     if (*fname) {                        // logic was fooled, thinks dir is file
  140.         lstrcat(dir, fname);            // fixup path
  141.         lstrcat(dir, ext);
  142.     }
  143.  
  144.     _splitpath(file, NULL, NULL, fname, ext);    // get real file
  145.  
  146.     _makepath(path, drive, dir, fname, ext);    // make pathname
  147.  
  148.     return path;
  149. }
  150.  
  151. ///////////////////////////////////////////////////////////////////////////////
  152. // FIND OUT IF PATH IS EXECUTABLE OR DIRECTORY
  153.  
  154. static
  155. enum {OTHER, DIR, EXE}
  156. GetMode(const char* path)
  157. {
  158.     struct _stat fil;
  159.  
  160.     if (_stat(path, &fil))
  161.         return OTHER;
  162.  
  163.     if (fil.st_mode & _S_IFCHR)
  164.         return OTHER;
  165.  
  166.     if (fil.st_mode & _S_IFREG)
  167.         if (fil.st_mode & _S_IEXEC)
  168.             return EXE;
  169.  
  170.     if (fil.st_mode & _S_IFDIR)
  171.         return DIR;
  172.  
  173.     return OTHER;
  174. }
  175.  
  176. ///////////////////////////////////////////////////////////////////////////////
  177. // FIND PGP EXECUTABLE
  178.  
  179. static
  180. char*                                    // path of PGP exe or NULL if not found
  181. FindPGP(char* PGPpath)                    // store PGP path here
  182. {
  183.     // first check PGPPATH environment variable
  184.     char* path = getenv("PGPPATH");        // it's supposed to be here
  185.  
  186.     if (path) {                         // if PGPPATH set
  187.         lstrcpy(PGPpath, path);            // get it
  188.  
  189.         switch (GetMode(PGPpath)) {        // and check it
  190.         case EXE:
  191.             return PGPpath;                // EXE found
  192.         case DIR:
  193.             AddFileName(PGPpath, PGPEXE);    // DIR found, so add filename
  194.             if (GetMode(PGPpath) == EXE)    // and check it again
  195.                 return PGPpath;                // yes it was there
  196.         }
  197.     }
  198.  
  199.     // next see if saved in WIN.INI [programs]
  200.     if (GetProfileString("[programs]", PGPEXE, "", PGPpath, _MAX_PATH)) {
  201.         if (GetMode(PGPpath) == EXE)
  202.             return PGPpath;
  203.     }
  204.  
  205.     {    // next, check to see if PGP extension registered
  206.         char buf[_MAX_PATH + 4];
  207.         LONG lbuf = sizeof(buf);
  208.  
  209.         if (RegQueryValue(HKEY_CLASSES_ROOT, ".PGP\\shell\\open\\command", buf, &lbuf)
  210.         == ERROR_SUCCESS) {
  211.             char* ptr = strchr(buf, ' ');    // check for arguments
  212.  
  213.             if (ptr)
  214.                 *ptr = '\0';                // separate arguments
  215.  
  216.             lstrcpy(PGPpath, buf);            // get execution command
  217.  
  218.             if (GetMode(PGPpath) == EXE)    // and check it
  219.                 return PGPpath;
  220.         }
  221.     }
  222.  
  223.     // finally, search the path
  224.     _searchenv(PGPEXE, "PATH", PGPpath);
  225.     return *PGPpath ? PGPpath : NULL ;
  226. }
  227.  
  228. ///////////////////////////////////////////////////////////////////////////////
  229.  
  230. //    FORMINIT: Runtime Loadable Encryptors are simply a specialised form of
  231. //    WinPMail Extension. As such, they must follow the standard rules for
  232. //    such Extensions, including having an .FFF file to describe their char-
  233. //    acteristics to the Extensions Manager, and a routine called FORMINIT
  234. //    that is called when the module is loaded. For more information on
  235. //    Extensions, examine the files WPMFORMS.TXT and WPMFORMS.TXT supplied in
  236. //    the "FORMS" subdirectory of the WinPMail install directory. Note that
  237. //    an encryptor module can use the entire family of Extension Manager
  238. //    interface calls except those specific to READER Extensions.
  239. //
  240. //    In short, FORMINIT must take the following form:
  241. //
  242. //    WORD FAR PASCAL _export FORMINIT (WORD version, int variant, HWND hParent,
  243. //        char *data, HWND *hDialog, char *callback_name);
  244. //
  245. //    "version" is passed in with the version of the WinPMail forms
  246. //        manager which is running.
  247. //    "variant" indicates what type of form is required - the following
  248. //        values are currently defined:
  249. //            0: Create a form for composing a message
  250. //            1: Create a form for reading a message
  251. //    "hParent" contains the handle of the WinPMail MDI child window
  252. //        which is to contain the form. For encryptor modules this window
  253. //        will almost always be hidden.
  254. //    "data" contains any string defined as being required for the
  255. //        form in the menu interface.
  256. //    "hDialog" should be filled in with the window handle of the
  257. //        modeless dialog created within the MDI child window.
  258. //    "callback_name" (optional) should be filled in with the name of the
  259. //        function in the DLL of the exported function to which messages
  260. //        should be sent or NULL if there is none. If NULL, messages are
  261. //        sent to the dialog returned in "hDialog". You will use an
  262. //        indirect callback of this kind when your extension does not
  263. //        create a dialog within the enclosing parent window.
  264. //
  265. //    When forminit is called, the DLL should register any window
  266. //    classes it needs then create the dialog within the MDI parent
  267. //    window and size it to the correct size. On return WinPMail will
  268. //    resize the parent window to enclose the dialog correctly. The
  269. //    DLL should NOT make the dialog visible - WinPMail will do that
  270. //    as required.
  271.  
  272. extern "C"
  273. WORD
  274. FAR PASCAL _export
  275. FORMINIT(
  276. WORD version,
  277. int variant,
  278. HWND hParent,
  279. char *data,
  280. HWND *hDialog,
  281. FORM_CALLBACK *callback
  282. )
  283. {
  284.     char buf[128], *p;                    // used for parsing
  285.     const char delim[] = " \t,;";
  286.     
  287. #ifdef _DEBUG
  288.     MyDebugOutput("FORMINIT called with data '%s'\n", data);
  289. #endif // _DEBUG
  290.  
  291.     //    First, check to see if the version of the form manager is
  292.     //    one we can work with. This check is pretty arbitrary - you
  293.     //    should probably assume that you may not work with any version
  294.     //    where the major version number is higher than the original
  295.     //    version you targeted.
  296.  
  297.     if ((version & 0xFF00) > VERSION) {
  298.         MessageBox(
  299.             NULL,                            /* handle of parent window    */
  300.             "You need an updated version of the PGP interface"
  301.                 "to work with this version of WinPMail!",    /* address of text in message box    */
  302.             "PGP Interface",                /* address of title of message box    */
  303.             MB_ICONSTOP | MB_OK);            /* style of message box    */
  304.         return 0;
  305.     }
  306.     
  307.     hwndParent = hParent;                // save parent window handle
  308.     *hDialog = NULL;                    // i'm not going to use this
  309.     
  310.     // parse the data string
  311.     lstrcpy(buf, data);
  312.     for (p = strtok(buf, delim); p; p = strtok(NULL, delim)) {
  313.         // set the mode switch; PUB is the default
  314.         if (! lstrcmpi(p, "SIG"))
  315.             MyMode = SIG;
  316.     }
  317.  
  318.     return 1;
  319. }
  320.  
  321. ///////////////////////////////////////////////////////////////////////////////
  322.  
  323. static
  324. BOOL                                    // FALSE = failure; TRUE = OK
  325. InitInstance(
  326. HINSTANCE hInst
  327. )
  328. {
  329.     char path[_MAX_PATH];
  330.     char drive[_MAX_DRIVE];
  331.     char dir[_MAX_DIR];
  332.     
  333.     // check system for adequate resources
  334.     if (CheckResources()) {
  335.         MessageBox(
  336.             NULL,                        /* handle of parent window    */
  337.             "Insufficient memory or system resources!\r\n"    /* address of text in message box    */
  338.                 "(Close an application and try again.)",
  339.             "PGP Interface",            /* address of title of message box    */
  340.             MB_ICONSTOP | MB_OK);        /* style of message box    */
  341.         return FALSE;
  342.     }
  343.     
  344.     // register CTL3D if Windows 3.1x
  345.     {
  346.         WORD winver = LOWORD(GetVersion());
  347.         
  348.         if (3 == LOBYTE(winver) && HIBYTE(winver) >= 10 && HIBYTE(winver) < 95)
  349.             if ((Ctl3D = Ctl3dRegister(hInst)))
  350.                 Ctl3dAutoSubclass(hInst);
  351.     }
  352.     
  353.     // get my directory ('cause I have stuff stored there)
  354.     GetModuleFileName(hInst, path, sizeof(path));
  355.     _splitpath(path, drive, dir, NULL, NULL);
  356.     _makepath(path, drive, dir, NULL, NULL);
  357.     _fullpath(MyDir, path, sizeof(MyDir));    // get rid of trailing backslash
  358.     // load my strings
  359.     _makepath(path, drive, dir, "PGPJN", ".INI");    // for my strings
  360.     typedef struct {
  361.         char* tag;            char* def;                                    char* str;        int len;
  362.     } VINI;
  363.     static const VINI vINI[] = {
  364.         { "PGPEXE",            "PGP.EXE",                                     PGPEXE,            sizeof(PGPEXE) },
  365.         { "PGPJNDOS",        "PGPJNDOS.EXE",                             PGPJNDOS,        sizeof(PGPJNDOS) },
  366.         { "BeginPGP",        "-----BEGIN PGP MESSAGE",                    PGPBegin,        sizeof(PGPBegin) },
  367.         { "EndPGP",            "-----END PGP MESSAGE",                        PGPEnd,            sizeof(PGPEnd) },
  368.         { "BeginPGPKey",    "-----BEGIN PGP PUBLIC KEY BLOCK-----",        PGPBeginKey,    sizeof(PGPBeginKey) },
  369.         { "EndPGPKey",        "-----END PGP PUBLIC KEY BLOCK-----",        PGPEndKey,        sizeof(PGPEndKey) },
  370.         { "GoodSig",        "Good signature from",                        SigGood,        sizeof(SigGood) },
  371.         { "BadSig",            "WARNING: Bad signature",                    SigBad,            sizeof(SigBad) },
  372.         { "NoKeySig",        "WARNING: Can't find the right public key",    SigNoKey,        sizeof(SigNoKey) },
  373.         { "BeginPGPAdvise",    "-----BEGIN PGPJN SIGNATURE ADVISORY-----",    PGPBeginAdvise,    sizeof(PGPBeginAdvise) },
  374.         { "EndPGPAdvise",    "-----END PGPJN SIGNATURE ADVISORY-----",    PGPEndAdvise,    sizeof(PGPEndAdvise) }
  375.     };
  376.     for (int n = 0; n < sizeof(vINI)/sizeof(vINI[0]); ++n)
  377.         GetPrivateProfileString("General",
  378.             vINI[n].tag, vINI[n].def, vINI[n].str, vINI[n].len, path);
  379.  
  380.     // find the PGP executable
  381.     if (! FindPGP(PGPpath)) {
  382.         MessageBox(
  383.             NULL,                        /* handle of parent window    */
  384.             "PGP executable not found!",    /* address of text in message box    */
  385.             "PGP Interface",            /* address of title of message box    */
  386.             MB_ICONSTOP | MB_OK);        /* style of message box    */
  387.         return FALSE;                    // failure!
  388.     }
  389.  
  390.     // save TEMP environment variable
  391.     TEMP = getenv("TEMP");
  392.     if (! TEMP || GetMode(TEMP) != DIR) {
  393.         TEMP = getenv("TMP");
  394.         if (! TEMP || GetMode(TEMP) != DIR) {
  395.             MessageBox(
  396.                 NULL,                    /* handle of parent window    */
  397.                 "TEMP environment variable not set properly!",    /* address of text in message box    */
  398.                 "PGP Interface",        /* address of title of message box    */
  399.                 MB_ICONSTOP | MB_OK);    /* style of message box    */
  400.             return FALSE;                // failure!
  401.         }
  402.     }
  403.  
  404.     // get PGPJNKEY option if set
  405.     {
  406.         char* key = getenv("PGPJNKEY");
  407.         
  408.         if (key) {
  409.             lstrcpyn(PGPJNKey, key, sizeof(PGPJNKey) - 3);
  410.             FrameIt(PGPJNKey);
  411.         }
  412.     }
  413.  
  414.     return TRUE;                        // success
  415. }
  416.  
  417. ///////////////////////////////////////////////////////////////////////////////
  418.  
  419. extern "C"
  420. BOOL
  421. FAR PASCAL
  422. LibMain(
  423. HINSTANCE hInst,
  424. WORD wDataSeg,
  425. WORD cbHeapSize,
  426. LPSTR lpszCmdLine
  427. )
  428. {
  429. #ifdef _DEBUG
  430.     MyDebugOutput("LIBMAIN called with args '%s'\n", lpszCmdLine);
  431. #endif // _DEBUG
  432.  
  433.     //    This particular encryptor has no user interface as such
  434.     //    so we don't have to register any window classes or anything.
  435.  
  436.     // unlock my data segment
  437.     if (cbHeapSize > 0)
  438.         UnlockData(0);
  439.     
  440.     // initialize my instance
  441.     if (! hLibInstance)
  442.         if (InitInstance(hInst))
  443.             hLibInstance = hInst;
  444.         else
  445.             return FALSE;                // initialization failed
  446.  
  447.     return TRUE;                        // Initialization went OK
  448. }
  449.  
  450. ///////////////////////////////////////////////////////////////////////////////
  451.  
  452. extern "C"
  453. int
  454. FAR PASCAL
  455. _WEP(int val)
  456. {
  457.     /* Your WEP functionality goes here */
  458.     if (Ctl3D)
  459.         Ctl3dUnregister(hLibInstance);
  460.  
  461.     return 1;
  462. }
  463.  
  464. ///////////////////////////////////////////////////////////////////////////////
  465.  
  466. //    PGPJN.CPP
  467.