Thread View: comp.sys.next.programmer
1 messages
1 total messages
Started by simsong Simson L. Garfinkel
Mon, 13 Apr 1992 12:28
Cracking NeXTmail (with source)
Author: simsong Simson L. Garfinkel
Date: Mon, 13 Apr 1992 12:28
Date: Mon, 13 Apr 1992 12:28
282 lines
6828 bytes
6828 bytes
I'm writing an incredible address-book program (due out in a few months) and
one of the things that I have to be able to do is to send out NeXTmail, both
regular NeXTmail and NeXTmail with attachments.
Cracking the attachments format was easy; I had already done that a long time
ago and posted a few shell scripts to help out with the task.
Cracking Non-NeXT mail format was much harder, though. You see, it isn't just
plain ASCII. NeXTmail hides stuff in the data so that when Non-NeXT mail is
read by a NeXT mail reader, it will automatically put back together the
paragraph breaks so that your paragraphs will properly flow.
After spending a night working on this problem, I came up with the methods,
shown below.
Basically, NeXTmail looks for th presence of a magic header (Received: by NeXT
Mailer) to know that it is message that originated from NeXTmail. It then
combines the lines into paragraphs that have more than one space at the end of
the line; furthermore, the number of characters in the line has to be divisible
by two.
Anyway, here is the code. Please DO NOT SEND ME QUESTIONS about the format,
becuase I don't have any documentation either. But if you find bugs in my
code, please post them to comp.sys.next.programmer.
CODE FOLLOWS:
#import "Subprocess.h"
#import <appkit/appkit.h>
#import <stdlib.h>
#import <string.h>
#import <libc.h>
@implementation Logger
- sendNextMailToProc:mailProc forText:mailText
{
/* NeXT mail */
char dir[256];
char fname[256];
char *outname;
char outfile[256];
char command[1024];
char uufile[1024];
char NextMailLine[1024];
struct stat sbuf;
FILE *f;
NXStream *str;
strcpy(dir,"/tmp/LogdirXXXXXX");
mktemp(dir);
strcpy(uufile,"/tmp/uufileXXXXXX");
mktemp(uufile);
if(mkdir(dir,0700)){
NXRunAlertPanel(0,"Could not create %s: %s",
0,0,0,dir,strerror(errno));
[window setTitle:"mail failed"];
return self;
}
strcpy(fname,dir);
strcat(fname,"//");
strcat(fname,"index.rtf");
strcpy(outfile,"/tmp/.tar.XXXXXX.fromLogger.attach");
NXGetTempFilename(outfile,10);
outname = index(outfile,'.');
str = NXOpenMemory(0,0,NX_WRITEONLY);
[mailText writeRichText:str];
NXSaveToFile(str,fname);
NXCloseMemory(str,NX_FREEBUFFER);
sprintf(command,
"cd %s;tar cf - index.rtf|compress|uuencode %s > %s",
dir,outname,uufile);
system(command);
if(stat(uufile,&sbuf)){
NXRunAlertPanel(0,"stat: %s:%s",
0,0,0,uufile,strerror(errno));
[window setTitle:"mail failed"];
return self;
}
sprintf(NextMailLine,"Next-Attachment: %s, %d, 1/1, 660, 0",
outname,sbuf.st_size);
[mailProc send:NextMailLine];
[mailProc send:""];
/* Now send the file */
f = fopen(uufile,"r");
if(!f){
NXRunAlertPanel(0,"%s:%s",0,0,0,strerror(errno));
[window setTitle:"mail failed"];
return self;
}
while(!feof(f)){
char buf[1024];
buf[0] = 0;
fgets(buf,sizeof(buf),f);
if(buf[0]){
[mailProc send:buf withNewline:NO];
}
}
return self;
}
- sendMailToProc:mailProc forText:mailText
{
int line;
int pos;
NXBreakArray *theBreaks=0;
int nbreaks;
NXLineDesc *breaks;
int length = [mailText textLength];
[mailProc send:""];
object_getInstanceVariable(mailText,"theBreaks",(void **)&theBreaks);
nbreaks = theBreaks->chunk.used;
breaks = theBreaks->breaks;
for(pos=0,line=0;line<nbreaks && pos<length;line++){
int lineChange;
int endParagraph;
int len,nlen;
char *buf;
int measured_len;
lineChange = breaks[line] & 0x8000;
endParagraph = breaks[line] & 0x4000;
len = breaks[line] & 0x2fff;
buf = malloc(len+16);
nlen = [mailText getSubstring:buf start:pos length:len];
buf[nlen] = '\000';
measured_len = strlen(buf);
if(measured_len>0){
if(buf[measured_len-1]=='\n'){
buf[measured_len-1]='\000';
}
}
strcat(buf," ");
while((strlen(buf) % 2) !=1 ){ /* the NeXTmail secret */
strcat(buf," ");
}
[mailProc send:buf];
free(buf);
pos += len;
if(lineChange!=0){
/* "if the line change bit is set, the descriptor is
* the first field of a NXHeightChange...."
*/
line += sizeof(NXHeightInfo)/sizeof(NXLineDesc);
}
}
return self;
}
- log:sender
{
[window setTitle:"Sending mail"];
proc = [[Subprocess alloc] init:"/usr/lib/sendmail -t"
withDelegate:self
andPtySupport:NO
andStdErr:YES];
[proc send:"From: " withNewline:NO];
[proc send:[fromCell stringValue]];
[proc send:"Received: by NeXT Mailer (1.63)"];
[proc send:"To: " withNewline:NO];
[proc send:[toCell stringValue]];
[proc send:"Subject: " withNewline:NO];
[proc send:[subjectCell stringValue]];
if([nextMailSwitch intValue]==1){
[self sendNextMailToProc:proc forText:text];
}
else{
[self sendMailToProc:proc forText:text];
}
[proc terminateInput];
return self;
}
- setScroller:aScroller
{
scroller = aScroller;
text = [scroller docView];
[text setDelegate:self];
[text setSelProp:NX_LEFTMARGIN to:5.0];
return self;
}
/* Delegate methods */
- makeRich
{
[nextMailSwitch setIntValue:1];
return self;
}
- textDidChange:sender
{
[[sender window] setDocEdited:YES];
return self;
}
- textWillConvert:sender fromFont:fnt toFont:fnt2
{
[self makeRich];
return fnt2;
}
- nextMailSwitchChanged:sender
{
/* If we are changing from NeXTmail to non-NeXTmail, get rid of
* all font information in the scroller...
*/
if([sender intValue]==0){
NXStream *str;
char *addr;
int len,maxlen;
str = NXOpenMemory(0,0,NX_READWRITE);
[text writeText:str];
NXGetMemoryBuffer(str,&addr,&len,&maxlen);
[text setText:""];
[text setText:addr];
[text display];
NXCloseMemory(str,NX_FREEBUFFER);
}
return self;
}
/* Subprocess delegate methods */
- subprocessDone
{
[window performClose:self];
return self;
}
- subprocessOut:(char *)buf
{
NXRunAlertPanel("Logger","sendmail: %s\n",0,0,0,buf);
return self;
}
- subprocessError:(char *)buf
{
NXRunAlertPanel("Error","sendmail: %s\n",0,0,0,buf);
return self;
}
@end
--
................................................................simson
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads