This is DisplayFilter.m in view mode; [Download] [Up]
/* -*-C-*- ******************************************************************************* * * File: DisplayFilter.m * RCS: /usr/local/sources/CVS/EnhanceMail/DisplayFilter.m,v 1.8 1998/07/12 21:21:40 tom Exp * Description: * Author: Carl Edman * Created: Fri Oct 13 11:48:05 1995 * Modified: 13-Nov-97 (Tom Hageman) * Language: C * Package: N/A * Status: Experimental (Do Not Distribute) * * (C) Copyright 1995, but otherwise this file is perfect freeware. * ******************************************************************************* */ #import "EnhanceMail.h" #import "DisplayFilter.h" #import "Preferences.h" #import "PGP.h" #import "XImageURL.h" #import "regexp.h" #ifndef EMDEDDEDCELLFIX # define EMBEDDEDCELLFIX 1 #endif #if EMBEDDEDCELLFIX /* this is an attempt to restore the textual representation of the smiley. XXX This only works with Forwarding, and copy/paste _within_ Mail, but not (yet) with Quoting (since that circumvents the copy/paste route). */ @interface EnhanceSmileyCell : Cell { char *smileyText; } - initIconCell:(const char *)iconName text:(const char *)text; @end @implementation EnhanceSmileyCell + finishLoading:(struct mach_header *)header { [Text registerDirective:"EnhanceSmileyCell" forClass:[EnhanceSmileyCell class]]; return self; } - initIconCell:(const char *)iconName text:(const char *)text { if ((self = [super initIconCell:iconName]) != nil) { if (text) smileyText = NXCopyStringBufferFromZone(text, [self zone]); } return self; } - free { free(smileyText); return [super free]; } - calcCellSize:(NXSize *)s { if ([self type] != NX_ICONCELL) { s->width = s->height = 0; return self; } return [super calcCellSize:s]; } - writeRichText:(NXStream *)stream forView:view { char c, *t = smileyText; if (t != NULL) { /* Cheat. Write out two cells for the price of one, plus the original smiley text inbetween (properly rtf-escaped). */ NXPrintf(stream, "}\n¬}"); while ((c = *t++) != '\0') { switch (c) { case '{': case '}': case '\\': NXPutc(stream, '\\'); } NXPutc(stream, c); } NXPrintf(stream, "\n{{\\EnhanceNullCell1 "); } return self; } // - readRichText inherited from Cell. @end // SmileyCell #endif // EMBEDDEDCELLFIX @implementation EnhanceDisplayFilter + finishLoading:(struct mach_header *)header { [NXApp addDisplayFilter:[[self alloc] init]]; return self; } - (BOOL)findRegionToAvoid:(int *)startP :(int *)endP inText:(Text *)txt { // XXX We should probably take these from user defaults. static const char * const rxtable[] = { "^begin[\t ][\t ]*[0-7][0-7]*[\t ][\t ]*[^\t ].*", "^end[\t ]*$", /// "^-----BEGIN PGP .*------$", "^------END PGP .*------$", NULL }; int bestStart, bestEnd; const char * const *rxP = rxtable; BOOL found = NO; bestStart = [txt textLength]; bestEnd = bestStart; while (*rxP != NULL) { const char *startrx = *rxP++; const char *endrx = *rxP++; int start1 = *startP; int end1 = *endP; if ([txt findRegExpr:startrx ignoreCase:NO loc1:&start1 loc2:&end1] == 0 && (*startP < end1)) { int start2 = end1; int end2 = end1; [txt setSel:start2:end2]; if ([txt findRegExpr:endrx ignoreCase:NO loc1:&start2 loc2:&end2] == 0 && (end1 < end2)) { end1 = end2; } else { end1 = [txt textLength]; } if (start1 < bestStart) { bestStart = start1; bestEnd = end1; found = YES; } [txt setSel:*startP:*endP]; } } *startP = bestStart; *endP = bestEnd; return found; } - (void)doSmilies:(Text *)txt { int start,end,ostart,seladjust; int avoidStart,avoidEnd; int textLength = [txt textLength]; BOOL shouldCheckAvoid = YES, firstAvoidCheck = YES; // Optimization. const char *c,*d; char *smilyreg,*smilyname; Cell *smilycell; for(c=EnhanceSmilies;*c;) { for(d=c;(*d!='\0') && (*d!='\n');d++); smilyreg=strncpy(alloca(d-c+1),c,d-c); smilyreg[d-c]='\0'; if (!*d) break; c=d+1; for(d=c;(*d!='\0') && (*d!='\n');d++); smilyname=strncpy(alloca(d-c+1),c,d-c); smilyname[d-c]='\0'; if (*d) d++; c=d; start=end=0; smilycell=nil; [txt setSel:start:end]; avoidStart = avoidEnd = 0; while (end < textLength) { ostart=start; if ([txt findRegExpr:smilyreg ignoreCase:NO loc1:&start loc2:&end]) break; if (ostart>=end) break; if (end > avoidStart && shouldCheckAvoid) { // Find avoidance region: loop until either: // - smiley inside avoidance region // -> skip to end of region and continue // or // - avoidance region found after smiley position. [txt setSel:ostart:ostart]; while (!(start < avoidEnd || end <= avoidStart)) { if (![self findRegionToAvoid:&avoidStart :&avoidEnd inText:txt]) { if (firstAvoidCheck) { firstAvoidCheck = NO; shouldCheckAvoid = NO; } break; } firstAvoidCheck = NO; } if (start < avoidEnd && !(end <= avoidStart)) { start = end = avoidStart = avoidEnd; [txt setSel:start:end]; continue; } } [txt setSel:start:end]; if (smilycell==nil) { NXImage *smilyimage=[[NXImage alloc] initNameInPath:smilyname]; if (smilyimage) { #if EMBEDDEDCELLFIX /* XXX regexp may match multiple textual representations of the smiley. Currently we're just remembering the first one we've encountered. */ // allow room for (Japanese) multi-byte characters. char *t = alloca(3 * (end - start) + 1); t[[txt getSubstring:t start:start length:end-start]] = '\0'; [smilyimage setName:smilyname]; smilycell=[[EnhanceSmileyCell alloc] initIconCell:smilyname text:t]; #else smilycell=[[Cell alloc] initIconCell:smilyname]; #endif } } if (smilycell==nil) break; [txt replaceSelWithCell:smilycell]; // This changes text length, so avoidance region will be inaccurate. // compensate for that here. // XXX although [txt selectionLength] returns 0 here, the actual // length of the cell selection seems to be 1. seladjust = (end - start) - 1; avoidStart -= seladjust; avoidEnd -= seladjust; textLength -= seladjust; } } } void colorize_quotes(Text *txt, const char *buf, int len, regexp *rx) { const char *end = buf + len; const char *s = buf; // Skip header. while (s < end-1) { if (*s++ == '\n' && *s == '\n') break; } while (s < end && *s == '\n') s++; while (s < end) { if (regexec(rx, s)) { // quote found; find quoted region. int quoteStart = (s - buf); int quoteEnd; do { // Skip to start of next line. while (s < end && *s++ != '\n') ; } while (s < end && regexec(rx, s)); quoteEnd = (s - buf); [txt setSel:quoteStart :quoteEnd]; [txt setSelColor:EnhanceQuoteColor]; } // Skip to start of next line. while (s < end && *s++ != '\n') ; } [txt setSel:0:0]; } - (void)doColorizeQuotes:(Text *)txt { regexp *quoterx = regcomp(EnhanceQuoteRegex); if (!quoterx) { [self logWarning:"-%s malformed QuoteRegex \"%s\"", sel_getName(_cmd), EnhanceQuoteRegex]; } else if (regexec(quoterx, "")) { [self logWarning:"-%s QuoteRegex \"%s\" matches empty string", sel_getName(_cmd), EnhanceQuoteRegex]; } else { int len = [txt textLength]; char *buf = NXZoneMalloc(EnhanceScratchZone(), len+1); // Use NXReadOnlyTextStream to avoid problems with Japanese. [txt openTextStream]; [txt seekToCharacterAt:0 relativeTo:NX_StreamStart]; len = [txt readCharacters:buf count:len]; [txt closeTextStream]; buf[len] = '\0'; colorize_quotes(txt, buf, len, quoterx); free(buf); } free(quoterx); } - (void)willDisplayText:(Text *)txt { if (EnhanceExpandSmilies && ([txt textLength] / 1024 < EnhanceMaxSmileyExpansionMessageSize)) { [self doSmilies:txt]; } if (EnhanceQuoteColoringInMailbox && ([txt textLength] / 1024 < EnhanceMaxQuoteColorMessageSize)) { [self doColorizeQuotes:txt]; } } - (void)willDisplayMessage:(MailMessage *)mes { if (EnhanceUsePGP) [[EnhancePGP new] decodePGP:mes]; } @end // EnhanceDisplayFilter
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.