This is Send.m in view mode; [Download] [Up]
/* -*-C-*- ******************************************************************************* * * File: Send.m * RCS: $Header: /usr/local/lib/cvs/EnhanceMail/Send.m,v 1.1.1.26 1996/07/01 01:10:28 cedman Exp $ * Description: * Author: Carl Edman * Created: Fri Oct 13 11:48:05 1995 * Modified: Sat Jun 29 15:01:43 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 <ctype.h> #import "EnhanceMail.h" #import "Send.h" #import "SimpleString.h" #import "Preferences.h" #import "XFace.h" #import "regexp.h" static HashTable *QuotationHash=nil; static HashTable *ReplyBoxHash=nil; static HashTable *InReplyToHash=nil; /* RFC822 Date: ^( *(Mon|Tue|Wed|Thu|Fri|Sat|Sun) *, )? *([0-9][0-9]?) +(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) +([0-9][0-9][0-9]?[0-9]?) +([0-9]?[0-9]:[0-9][0-9](:[0-9][0-9])?) +(UT|GMT|EST|EDT|CST|CDT|MST|MDT|PST|PDT|1[A-Z]|\+[0-9][0-9][0-9][0-9]|-[0-9][0-9][0-9][0-9]) */ static id interpret_escapes(const char *c, id mes, regexp *rx) { id s=[[SimpleString alloc] init]; const char *end=c+strlen(c),*d; char *m; int n; static regexp *daterx=0, *addrrx=0; if (!daterx) daterx=regcomp("^(([ \t]*(Mon|Tue|Wed|Thu|Fri|Sat|Sun)[ \t]*,[ \t])?[ \t]*([0-9][0-9]?)[ \t]+(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[ \t]+([0-9][0-9][0-9]?[0-9]?))[ \t]+([0-9]?[0-9]:[0-9][0-9](:[0-9][0-9])?)"); if (!addrrx) addrrx=regcomp("^[ \t]*(([^ \t].*)?[^ \t])[ \t]+<.*>[ \t]*$"); while(c<end) if ((*c=='%')) switch((++c<end) ? *c++ : '%') { case '{': for(d=c;(c<end) && (*c!='}');c++); m=alloca(c-d+1); strncpy(m,d,c-d); m[c-d]='\0'; c++; if (!(d=[mes headerValueForKey:m])) break; [s appendString:d]; break; case 'd': if ((d=[mes headerValueForKey:"Date"])==0) break; if (daterx && regexec(daterx,d)) [s appendString:daterx->startp[1] length:daterx->endp[1]-daterx->startp[1]]; break; case 't': if ((d=[mes headerValueForKey:"Date"])==0) break; if (daterx && regexec(daterx,d)) [s appendString:daterx->startp[7] length:daterx->endp[7]-daterx->startp[7]]; break; case 'f': if (!(d=[mes headerValueForKey:"From"])) break; if (addrrx && regexec(addrrx,d)) [s appendString:addrrx->startp[1] length:addrrx->endp[1]-addrrx->startp[1]]; else [s appendString:d]; break; case 'n': [s appendChar:'\n']; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': for(n=*(c-1)-'0';isdigit(*c) && (c<end);c++) n=n*10+(*c-'0'); if (n<NSUBEXP && rx && rx->startp[n] && rx->endp[n]) [s appendString:rx->startp[n] length:rx->endp[n]-rx->startp[n]]; break; default: [s appendChar:*(c-1)]; } else [s appendChar:*(c++)]; return s; } #ifndef KANJI static id quote_text(const char *text,int length,id mes) { id s=[[SimpleString alloc] init],prefix=nil; int linebeg=0,i; int maxlen=[MailMessage lineLength]; const char *line,*end,*word,*tmp,*prebeg,*preend; regexp *rx=regcomp(EnhanceQuoteRegex); if (!rx) return s; prebeg=preend=line=text; end=line+length; while(line<end) { if (!regexec(rx,line)) for(i=0;i<NSUBEXP;i++) rx->startp[i]=rx->endp[i]=line; word=rx->endp[0]; if ((prefix==nil) || ((word-line)!=(preend-prebeg)) || (strncmp(line,prebeg,preend-prebeg)!=0)) { prebeg=line; preend=word; if (prefix!=nil) prefix=[prefix free]; prefix=interpret_escapes(EnhanceQuotePrefix, mes, rx); if (linebeg!=[s length]) linebeg=[s appendChar:'\n']; } while((word<end) && ((*word==' ')||(*word=='\t'))) word++; for(line=word;(line<end)&&(*line!='\n')&&(*line!='\r');line++); if ((*word=='\n')||(*word=='\r')) { if (linebeg!=[s length]) [s appendChar:'\n']; [s appendSimpleString:prefix]; linebeg=[s appendChar:'\n']; } else if ([s length]-linebeg+(line-word)+ (([s length]==linebeg) ? [prefix length] : 1)<maxlen) { if ([s length]==linebeg) [s appendSimpleString:prefix]; else [s appendChar:' ']; [s appendString:word length:(line-word)]; linebeg=[s appendChar:'\n']; } else while(word<line) { for(tmp=word;(tmp<line)&&!((*tmp==' ')||(*tmp=='\t'));tmp++); if (!isascii(*tmp)) tmp++; if ([s length]-linebeg+(tmp-word)+1>=maxlen) linebeg=[s appendChar:'\n']; if ([s length]==linebeg) [s appendSimpleString:prefix]; else [s appendChar:' ']; for(;word<tmp;word++) [s appendChar:*word]; for(;(word<line)&&((*word==' ')||(*word=='\t'));word++); } if (line<end) line++; if ((line<end)&&((*line=='\n')||(*line=='\r'))&&(*line!=*(line-1))) line++; } if (linebeg!=[s length]) [s appendChar:'\n']; if (rx) free(rx); if (prefix!=nil) [prefix free]; return s; } #else /* KANJI */ static int iseow(const char *d) { static char *oldd; static int gotFirstByte=0; if (d==0) { gotFirstByte=0; return 0; } if (isascii(*d)) { if ((*d==' ')||(*d=='\t')) return 1; else return 0; } else { if (gotFirstByte) { if (oldd != d) gotFirstByte=0; oldd = (char *)d; return 1; } else { if (oldd != d) gotFirstByte=1; oldd = (char *)d; if (isascii(*(d-1))&&(*(d-1)!='\n')&&(*(d-1)!='\r')&&(*(d-1)!=' ')&&(*(d-1)!='\t')) return 1; else return 0; } } } static id quote_text(const char *text,int length,id mes) { id s=[[SimpleString alloc] init],prefix=nil; int linebeg=0,i; int maxlen=[MailMessage lineLength]; const char *line,*end,*word,*tmp,*prebeg,*preend; regexp *rx=regcomp(EnhanceQuoteRegex); char *lasteow; if (!rx) return s; prebeg=preend=line=text; end=line+length; iseow(0); tmp=0; while(line<end) { if (!regexec(rx,line)) for(i=0;i<NSUBEXP;i++) rx->startp[i]=rx->endp[i]=line; word=rx->endp[0]; if ((prefix==nil) || ((word-line)!=(preend-prebeg)) || (strncmp(line,prebeg,preend-prebeg)!=0)) { prebeg=line; preend=word; if (prefix!=nil) prefix=[prefix free]; prefix=interpret_escapes(EnhanceQuotePrefix, mes, rx); if (linebeg!=[s length]) linebeg=[s appendChar:'\n']; } while((word<end) && iseow(word)) word++; for(line=word;(line<end)&&(*line!='\n')&&(*line!='\r');line++); if ((*word=='\n')||(*word=='\r')) { if (linebeg!=[s length]) [s appendChar:'\n']; [s appendSimpleString:prefix]; linebeg=[s appendChar:'\n']; iseow(0); } else if ([s length]-linebeg+(line-word)+ (([s length]==linebeg) ? [prefix length] : 1)<maxlen) { if ([s length]==linebeg) [s appendSimpleString:prefix]; else if (isascii(*(word-2))) [s appendChar:' ']; [s appendString:word length:(line-word)]; linebeg=[s appendChar:'\n']; iseow(0); } else { while(word<line) { lasteow=(char *)tmp; for(tmp=word;(tmp<line)&&!iseow(tmp);tmp++); if (!isascii(*tmp)) tmp++; if ([s length]-linebeg+(tmp-word)+1>=maxlen) { if (!isascii(*lasteow)) [s appendChar:*lasteow]; linebeg=[s appendChar:'\n']; } if ([s length]==linebeg) [s appendSimpleString:prefix]; else { if (!isascii(*lasteow)&&(*(lasteow+1)!='\n')&&(*(lasteow+1)!='\r')) [s appendString:lasteow length:word-lasteow]; else if (isascii(*lasteow)) [s appendChar:' ']; } for(;word<tmp;word++) [s appendChar:*word]; for(;(word<line)&&iseow(word);word++); } if (!isascii(*tmp)&&(*(tmp+1)=='\n')) [s appendChar:*tmp]; iseow(0); } if (line<end) line++; if ((line<end)&&((*line=='\n')||(*line=='\r'))&&(*line!=*(line-1))) line++; } if (linebeg!=[s length]) [s appendChar:'\n']; if (rx) free(rx); if (prefix!=nil) [prefix free]; return s; } #endif /* KANJI */ @implementation EnhanceSend + finishLoading:(struct mach_header *)header { [self poseAs:[self superclass]]; QuotationHash=[[HashTable alloc] initKeyDesc:"@" valueDesc:"i"]; ReplyBoxHash=[[HashTable alloc] initKeyDesc:"@" valueDesc:"%"]; InReplyToHash=[[HashTable alloc] initKeyDesc:"@" valueDesc:"%"]; return self; } + startUnloading { QuotationHash=[QuotationHash free]; ReplyBoxHash=[ReplyBoxHash free]; InReplyToHash=[InReplyToHash free]; return self; } - initSendWindow:fp16 { id ret=[super initSendWindow:fp16]; id oreader=[self getMailbox]; id obox=oreader ? [oreader mailbox] : nil; char path[FILENAME_MAX]; const char *home=NXHomeDirectory(); const char *box=obox ? [obox dirname] : 0; BOOL success=NO; [QuotationHash insertKey:self value:(void *)(NO)]; [ReplyBoxHash insertKey:self value:0]; [InReplyToHash insertKey:self value:0]; if (!(EnhanceInsertSignature^EnhanceControlP()) ||!EnhanceSignatureFilename) return ret; if (box && !success) { sprintf(path,"%s/%s.rtfd",box,EnhanceSignatureFilename); if (([text openRTFDFrom:path]==NX_RTFDErrorNone)) success=YES; sprintf(path,"%s/%s.rtf",box,EnhanceSignatureFilename); if (!success && sendFormat!=0 && ([text openRichFrom:path]!=nil)) success=YES; sprintf(path,"%s/%s",box,EnhanceSignatureFilename); if (!success && ([text openFrom:path]!=nil)) success=YES; } if (home && !success) { sprintf(path,"%s/%s.rtfd",home,EnhanceSignatureFilename); if (([text openRTFDFrom:path]==NX_RTFDErrorNone)) success=YES; sprintf(path,"%s/%s.rtf",home,EnhanceSignatureFilename); if (!success && sendFormat!=0 && ([text openRichFrom:path]!=nil)) success=YES; sprintf(path,"%s/%s",home,EnhanceSignatureFilename); if (!success && ([text openFrom:path]!=nil)) success=YES; } if (success) { [text setSel:0:0]; [text replaceSel:EnhanceSignatureSeparator]; } if (sendFormat==0) [self makeAscii:self]; [self updateSpecialDelivery]; [self updateSize:self]; [form selectTextAt:0]; return ret; } - free { [QuotationHash removeKey:self]; [ReplyBoxHash removeKey:self]; [InReplyToHash removeKey:self]; return [super free]; } - deliver:button { id ret, def; NXAtom replybox, origbox; if (EnhanceAutoSpellCheck ^ EnhanceAlternateP()) { id spell=[NXSpellChecker sharedInstance]; id panel=(spell!=nil) ? [spell spellingPanel] : nil; if ((spell!=nil) &&[spell checkSpelling:NX_CheckSpellingFromStart of:self]) { if (panel!=nil) [panel orderFront:self]; return nil; } else { if (panel!=nil) [panel orderOut:self]; } } def=[Defaults new]; origbox=NXUniqueString([def outgoingMailbox]); replybox=[ReplyBoxHash valueForKey:self]; if (EnhanceRepliesWithOriginals && replybox) [def setOutgoingMailbox:replybox]; ret=[super deliver:button]; if (EnhanceRepliesWithOriginals && replybox) [def setOutgoingMailbox:origbox]; return ret; } - mailMessage { id mes=[super mailMessage]; id ximage; char buf[1024],*tmp; sprintf(buf,"Mail 4.0 (Enhance %s)",EnhanceVersion); [mes setHeaderKey:"X-Nextstep-Mailer" value:buf]; if (tmp=[InReplyToHash valueForKey:self]) [mes setHeaderKey:"In-Reply-To" value:tmp]; if (EnhanceInsertXFace && EnhanceXFace && (ximage=[[NXImage alloc] initFromFile:EnhanceXFace])) { tmp=[ximage xFace]; ximage=[ximage free]; if (tmp) { [mes setHeaderKey:"X-Face" value:tmp]; free(tmp); } } if (EnhanceInsertXImageURL && EnhanceXImageURL) [mes setHeaderKey:"X-Image-URL" value:strcpy(alloca(strlen(EnhanceXImageURL)+1),EnhanceXImageURL)]; return mes; } - restoreDraftFromMessage:message { #if 0 if (EnhanceRestoreDeletesDraft) { [toc setState:'d' forMsg:number flush:YES]; } #endif [text setText:""]; [self updateSpecialDelivery]; return [super restoreDraftFromMessage:message]; } - replyHelper:(BOOL)flag { id oreader=[self getMailbox]; id obox=oreader ? [oreader mailbox] : nil; id orig=oreader ? [oreader mailMessage] : nil; id otext=oreader ? [oreader text] : nil; id s; int start,len; NXSelPt beg,end; const char *new; char *buf,*c; [super replyHelper:flag]; if ((orig!=nil)&&EnhanceFlagReplies) [oreader setFlagged:YES]; if ((obox!=nil) && ((new=[obox dirname])!=0)) [ReplyBoxHash insertKey:self value:(void *)NXUniqueString(new)]; else [ReplyBoxHash removeKey:self]; if ((orig!=nil) && ((new=[orig headerValueForKey:"Message-Id"])!=0)) [InReplyToHash insertKey:self value:(void *)NXUniqueString(new)]; else [InReplyToHash removeKey:self]; if ([QuotationHash valueForKey:self] || (orig==nil) || (otext==nil) || !(EnhanceQuoteReplies^EnhanceControlP())) return self; s=[[SimpleString alloc] init]; if (EnhanceQuoteIntro) { [s includeSimpleString:interpret_escapes(EnhanceQuoteIntro,orig,0)]; [s appendChar:'\n']; } [otext getSel:&beg:&end]; if (beg.cp!=end.cp) { start=beg.cp; len=end.cp-beg.cp; buf=alloca(len); [otext getSubstring:buf start:start length:len]; } else { start=0; len=[otext byteLength]; buf=alloca(len); [otext getSubstring:buf start:start length:len]; for(c=buf;c<buf+len-1;c++) if ((c[0]=='\n') && (c[1]=='\n')) break; while ((c<buf+len) && (*c=='\n')) c++; len-=(c-buf); buf=c; } start=[s length]; [s includeSimpleString:quote_text(buf,len,orig)]; len=[s length]-start; [text setSel:0:0]; [text replaceSel:[s string] length:[s length]]; if ((sendFormat!=0) && EnhanceQuoteColoring) { [text setSel:start:start+len]; [text setSelColor:EnhanceQuoteColor]; } if (sendFormat==0) [self makeAscii:self]; [self updateSpecialDelivery]; [text setSel:start:start]; s=[s free]; [QuotationHash insertKey:self value:(void *)YES]; return self; } - openTextStream { [text openTextStream]; return self; } - (BOOL)seekToCharacterAt:(int)offset relativeTo:(int)seekMode { return [text seekToCharacterAt:offset relativeTo:seekMode]; } - (int)readCharacters:(char *)buffer count:(int)count { return [text readCharacters:buffer count:count]; } - (int)currentCharacterOffset { return [text currentCharacterOffset]; } - (BOOL)isAtEOTS { return [text isAtEOTS]; } - closeTextStream { [text closeTextStream]; return self; } - (void)selectCharactersFrom:(int)start to:(int)end { [text selectCharactersFrom:start to:end]; } - (int)selectionCharacterCount { return [text selectionCharacterCount]; } - (int)readCharactersFromSelection:(char *)buffer count:(int)count { return [text readCharactersFromSelection:buffer count:count]; } - (void)makeSelectionVisible { [text makeSelectionVisible]; } - changeSpelling:sender { return ([text changeSpelling:sender]==nil) ? nil : self; } - (int)spellDocumentTag { return [text spellDocumentTag]; } @end @implementation MediaText(EnhanceSend) - openFrom:(const char *)file { BOOL ok=YES; NXStream *s=0; if (ok && !(s=NXMapFile(file,NX_READONLY))) ok=NO; if (ok && ([self readText:s]==nil)) ok=NO; if (s) NXClose(s); return ok ? self : nil; } - openRichFrom:(const char *)file { BOOL ok=YES; NXStream *s=0; if (ok && !(s=NXMapFile(file,NX_READONLY))) ok=NO; if (ok && ([self readRichText:s]==nil)) ok=NO; if (s) NXClose(s); return ok ? self : nil; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.