This is PGP.m in view mode; [Download] [Up]
/* -*-C-*-
*******************************************************************************
*
* File: PGP.m
* RCS: $Header: /usr/local/lib/cvs/EnhanceMail/PGP.m,v 1.1.1.6 1996/07/01 01:10:24 cedman Exp $
* Description:
* Author: Carl Edman
* Created: Fri Oct 13 11:48:05 1995
* Modified: Sun Jun 30 13:38:57 1996 (Carl Edman) cedman@capitalist.princeton.edu
* Language: C
* Package: N/A
* Status: Experimental (Do Not Distribute)
*
* (C) Copyright 1995, but otherwise this file is perfect freeware.
*
*******************************************************************************
*/
#import "EnhanceMail.h"
#import "PGP.h"
#import "Preferences.h"
#import "XImageURL.h"
#import "regexp.h"
#define PGP_SIGNED "-----BEGIN PGP SIGNED MESSAGE-----"
#define PGP_ENCRYPTED "-----BEGIN PGP MESSAGE-----"
#define MSG_PGP_RICH NXLocalizedStringFromTableInBundle("Localizable", EnhanceBundle, "Only Plain Text messages are handled by PGP.", NULL, Error for attempt to PGP rich text messages)
#define MSG_CANCEL NXLoadLocalizedStringFromTableInBundle("Buttons", nil, "Cancel", NULL)
#define MSG_DELIVER NXLoadLocalizedStringFromTableInBundle("Buttons", nil, "Deliver Anyway", NULL)
static id mypgp=nil;
static regexp *keyrx=0, *addrrx=0;
@implementation EnhancePGP
+ new
{
if (mypgp==nil) mypgp=[[self alloc] init];
return mypgp;
}
- init
{
char path[MAXPATHLEN+1];
if ([EnhanceBundle getPath:path forResource:"EnhancePGPPanel" ofType:"nib"])
[NXApp loadNibFile:path owner:self];
passTime=0;
if (keyrx==0)
keyrx=regcomp("-----BEGIN PGP PUBLIC KEY BLOCK-----.*-----END PGP PUBLIC KEY BLOCK-----");
if (addrrx==0)
addrrx=regcomp("^[^<>]*<([^<> ]*)>[^<>]*$\n^ *([^() \t]*) *\\([^()]*\\) *$");
return self;
}
- reenter:sender
{
return [NXApp stopModal:2];
}
- ok:sender
{
return [NXApp stopModal:1];
}
- cancel:sender
{
return [NXApp stopModal:0];
}
- clobberPass
{
const char *pass;
char *c;
if (!passField) return nil;
pass=[passField stringValue];
for(c=(char *)pass;*c;c++) *c='\0';
[passField setStringValue:pass];
return self;
}
- getUser:(const char **)user pass:(const char **)pass
{
int ret;
time_t curtime=time(0);
if (curtime>passTime) [self clobberPass];
if (user && userField!=nil) *user=[userField stringValue];
if (pass && passField!=nil) *pass=[passField stringValue];
if (pass && *pass && **pass) return self;
if (passPanel==nil) return nil;
if (passField!=nil) [passField selectText:self];
ret=[NXApp runModalFor:passPanel];
[passPanel orderOut:self];
if (ret==0) { user=pass=0; return nil; }
if (user && userField) *user=[userField stringValue];
if (pass && passField) *pass=[passField stringValue];
passTime=time(0)+EnhancePGPPassTimeout*60;
return self;
}
- (int)handleError:(const char *)err ok:(BOOL)defok
{
int ret;
const char *c;
if ((errPanel==nil) || (errText==nil)) return 0;
for(c=err;*c;c++) if (*c=='\a') NXBeep();
while((*err==' ') || (*err=='\n') || (*err=='\a') || (*err==' ')) err++;
[errText setText:err];
if (defok && (errDefaultButton!=nil) && (errNonDefaultButton!=nil))
{
SEL tmpact;
char tmptitle[1024];
tmpact=[errDefaultButton action];
strcpy(tmptitle,[errDefaultButton title]);
[errDefaultButton setAction:[errNonDefaultButton action]];
[errDefaultButton setTitle:[errNonDefaultButton title]];
[errNonDefaultButton setAction:tmpact];
[errNonDefaultButton setTitle:tmptitle];
}
[errText scrollSelToVisible];
ret=[NXApp runModalFor:errPanel];
[errPanel orderOut:self];
if (defok && (errDefaultButton!=nil) && (errNonDefaultButton!=nil))
{
SEL tmpact;
char tmptitle[1024];
tmpact=[errDefaultButton action];
strcpy(tmptitle,[errDefaultButton title]);
[errDefaultButton setAction:[errNonDefaultButton action]];
[errDefaultButton setTitle:[errNonDefaultButton title]];
[errNonDefaultButton setAction:tmpact];
[errNonDefaultButton setTitle:tmptitle];
}
return ret;
}
- (int)runPGP:(SimpleString *)In to:(SimpleString *)Out error:(SimpleString *)Err args:(const char **)argv
{
int inpipe[2],outpipe[2],errpipe[2];
int ac,pid;
const char **av;
union wait status;
if (access(EnhancePGPPath,X_OK))
{
[NXApp logError:"Missing pgp binary."];
return -1;
}
for(ac=0;argv[ac];ac++);
av=alloca(sizeof(*av)*(ac+6));
ac=0;
av[ac++]="pgp";
av[ac++]="+batchmode";
av[ac++]="+force";
av[ac++]="+encrypttoself=on";
av[ac++]="-f";
while (*argv) av[ac++]=*argv++;
av[ac]=0;
if ((pipe(inpipe)<0) || (pipe(outpipe)<0) || (pipe(errpipe)<0))
{
[NXApp logError:"Failure to create pipe pairs."];
return -2;
}
if (!(pid=fork()))
{
close(inpipe[1]);
close(outpipe[0]);
close(errpipe[0]);
if (inpipe[0] != 0) { dup2(inpipe[0], 0); close(inpipe[0]); }
if (outpipe[1] != 1) { dup2(outpipe[1], 1); close(outpipe[1]); }
if (errpipe[1] != 2) { dup2(errpipe[1], 2); close(errpipe[1]); }
execv(EnhancePGPPath, av);
_exit(1);
}
if (pid==-1)
{
[NXApp logError:"Failure to fork."];
return -3;
}
close(inpipe[0]);
close(outpipe[1]);
close(errpipe[1]);
/* This is not quite proper, but if pgp works the way I think it does,
it will work and be a lot shorter and simpler than the proper solution. */
if (In!=nil) [In writeFile:inpipe[1]];
close(inpipe[1]);
if (Out!=nil) [[Out empty] appendFile:outpipe[0]];
close(outpipe[0]);
if (Err!=nil) [[Err empty] appendFile:errpipe[0]];
close(errpipe[0]);
if (wait4(pid,&status,0,0)<0)
{
[NXApp logError:"PGP process disappeared."];
return -4;
}
if (status.w_T.w_Termsig!=0)
{
[NXApp logError:"PGP process killed by signal."];
return -5;
}
return status.w_T.w_Retcode;
}
- (BOOL)grabKey:(const char *)keyid
{
int ac,ret;
const char **av=0;
char url[MAXPATHLEN+1];
id s;
if (!EnhanceRetrievePGPKeys || !EnhanceKeyServerURL) return NO;
sprintf(url,"%s%s",EnhanceKeyServerURL,keyid);
s=[[SimpleString alloc] init];
if ([NXImage grabURL:url string:s]==NO) { s=[s free]; return NO; }
if (regexec(keyrx,[s string])==NO) { s=[s free]; return NO; }
av=alloca(sizeof(*av)*2);
ac=0;
av[ac++]="-ka";
av[ac]=0;
ret=[self runPGP:s to:nil error:nil args:av];
s=[s free];
return ret==0;
}
- (BOOL)decodePGP:(MailMessage *)mes
{
id In,Out,Err;
const char **av;
int ret=0,ac;
if ([mes isRichBody])
return NO;
if ((strncmp([mes body],PGP_ENCRYPTED,sizeof(PGP_ENCRYPTED)-1)!=0)
&& (strncmp([mes body],PGP_SIGNED,sizeof(PGP_SIGNED)-1)!=0))
return NO;
In=[[SimpleString alloc] init];
[In appendString:[mes body] length:[mes bodyLength]];
Out=[[SimpleString alloc] init];
Err=[[SimpleString alloc] init];
av=alloca(sizeof(*av)*5);
restart:
ac=0;
if (strncmp([In string],PGP_ENCRYPTED,sizeof(PGP_ENCRYPTED)-1)==0)
{
const char *user, *pass;
if ([self getUser:&user pass:&pass]==NO) goto end;
if (user && *user) { av[ac++]="-u"; av[ac++]=user; }
if (pass && *pass) { av[ac++]="-z"; av[ac++]=pass; }
}
av[ac]=0;
ret=[self runPGP:In to:Out error:Err args:av];
if ((ret!=0) || ([Err length]>0)) switch([self handleError:[Err string] ok:(ret==0)])
{
case 0:
ret=-1;
break;
case 1:
ret=0;
break;
case 2:
[self clobberPass];
goto restart;
}
if (ret==0)
[mes setBody:[Out string] length:[Out length]];
end:
if (In!=nil) In=[In free];
if (Out!=nil) Out=[Out free];
if (Err!=nil) Err=[Err free];
return (ret==0);
}
- (BOOL)encodePGP:(MailMessage *)mes to:(StringList *)rcpt sign:(BOOL)sign encrypt:(BOOL)encrypt
{
int ret=0, ac;
const char **av;
id In, Out,Err;
if ([rcpt count]==0) encrypt=NO;
if (!encrypt && !sign) return YES;
if ([mes isRichBody])
{
NXBeep();
return !NXRunAlertPanel(0,MSG_PGP_RICH,MSG_CANCEL,MSG_DELIVER,0);
}
In=[[SimpleString alloc] init];
[In appendString:[mes body] length:[mes bodyLength]];
Out=[[SimpleString alloc] init];
Err=[[SimpleString alloc] init];
av=alloca(sizeof(*av)*([rcpt count]+8));
restart:
ac=0;
av[ac++]="-a";
if (sign)
{
const char *user,*pass;
if ([self getUser:&user pass:&pass]==NO) goto end;
if (user && *user) { av[ac++]="-u"; av[ac++]=user; }
if (pass && *pass) { av[ac++]="-z"; av[ac++]=pass; }
av[ac++]="-s";
}
if (encrypt)
{
int n;
const char *r;
char buf[1024];
av[ac++]="-e";
for(n=0;n<[rcpt count];n++)
{
r=[rcpt stringAt:n];
if (regexec(addrrx,r))
{
regsub(addrrx,"\\1\\2",buf);
r=strcpy(alloca(strlen(buf)+1),buf);
}
av[ac++]=r;
}
}
else
{
av[ac++]="-t";
}
av[ac]=0;
ret=[self runPGP:In to:Out error:Err args:av];
if ((ret!=0) || ([Err length]>0)) switch([self handleError:[Err string] ok:(ret==0)])
{
case 0:
ret=-1;
break;
case 1:
ret=0;
break;
case 2:
[self clobberPass];
goto restart;
}
if (ret==0) [mes setBody:[Out string] length:[Out length]];
end:
if (In!=nil) In=[In free];
if (Out!=nil) Out=[Out free];
if (Err!=nil) Err=[Err free];
return (ret==0);
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.