This is Preferences.m in view mode; [Download] [Up]
/* -*-ObjC-*- ******************************************************************************* * * File: Preferences.m * RCS: /usr/local/sources/CVS/EnhanceMail/Preferences.m,v 1.25 1998/07/12 10:55:53 tom Exp * Description: * Author: Carl Edman * Created: Wed Nov 1 09:58:01 1995 * Modified: 1-Jun-98 (Tom Hageman) * Language: C * Package: N/A * Status: Experimental (Do Not Distribute) * * (C) Copyright 1995, but otherwise this file is perfect freeware. * ******************************************************************************* */ #define PREFEXTERN #import "Preferences.h" #undef PREFEXTERN #import "EnhanceMail.h" #import "PGP.h" #import "XFace.h" #import "XImageURL.h" #import "regexp.h" #import <ctype.h> #import <math.h> #import <netdb.h> #define NOTYET 0 #define MSG_OK NXLoadLocalizedStringFromTableInBundle("Buttons", nil, "OK", NULL) #define MSG_BAD_XFACE NXLocalizedStringFromTableInBundle("Localizable", EnhanceBundle, "%s does not contain monochrome 48x48 image.", NULL, Error message for bad XFace) #define MSG_BAD_REGEXP NXLocalizedStringFromTableInBundle("Localizable", EnhanceBundle, "%s is not a valid regular expression.", NULL, Error message for bad Regexp) #define DEFAULT_QUOTE_INTRO NXLocalizedStringFromTableInBundle("Localizable", EnhanceBundle, "You wrote:", NULL, Default introduction to quotes in replies) #define DEFAULT_FLAG_SEARCH (EnhanceUseKanji() ? " «" : "«") #define DEFAULT_SMILIES NXLoadLocalized\ StringFromTableInBundle("Localizable", EnhanceBundle, "Smilies", \ ":-\\]\nFaceGrinning.tiff\n\ :-[oO]\nFaceStartled.tiff\n\ :-[)>]\nFaceHappy.tiff\n\ ;-[>)]\nFaceWinking.tiff\n\ :-[/\\\\]\nFaceIronic.tiff\n\ :-|\nFaceStraight.tiff\n\ [>}]-[(<]\nFaceAngry.tiff\n\ [:&]-[(<]\nFaceSad.tiff\n\ :-d\nFaceTasty.tiff\n\ :-[pP]\nFaceYukky.tiff\n\ :-[yY]\nFaceWry.tiff\n\ [X8]-|\nFaceKOed.tiff\n\ }-)\nFaceEvilGrin.tiff\n\ }->\nFaceSatanicGrin.tiff") static struct PrefDefault { struct PrefDefault *next; enum PrefDefaultType { bool=1, string, integer, color } type; union { BOOL *bool; const char **string; int *integer; NXColor *color; } location; id control; char name[0]; } *prefroot=0; static struct PrefDefault *allocPrefDefault(id self, const char *name, const char *con, enum PrefDefaultType type); static void savePrefs(id self); static void loadPrefs(id self); static void downloadPrefsFromPanel(id prefPanel); static void uploadPrefsIntoPanel(id prefPanel); static HashTable *PanelHash=nil; static NXImage *delete_image=nil; static id XImageURLButton=nil; static id XFaceButton=nil; @implementation EnhancePreferences + finishLoading:(struct mach_header *)header { id pref; char path[MAXPATHLEN+1]; EnhanceBundleInit(); [self poseAs:[self superclass]]; if ([EnhanceBundle getPath:path forResource:"delete" ofType:"tiff"]) delete_image=[[NXImage alloc] initFromFile:path]; pref=[Preferences new]; if ([EnhanceBundle getPath:path forResource:"EnhancePreferences" ofType:"nib"]) [NXApp loadNibFile:path owner:pref]; [pref addPanel:NXGetNamedObject("Quoting_Box2",pref)]; [pref addPanel:NXGetNamedObject("Mailboxes_Box2",pref)]; [pref addPanel:NXGetNamedObject("Images_Box2",pref)]; [pref addPanel:NXGetNamedObject("PGP_Box2",pref)]; [pref addPanel:NXGetNamedObject("Options_Box2",pref)]; [pref registerBool:"QuoteReplies" location:&EnhanceQuoteReplies control:"Quoting_Box2_Quoting_Quote Replies" default:NO]; [pref registerString:"QuoteIntro" location:&EnhanceQuoteIntro control:"Quoting_Box2_Quoting_Form_Introduction" default:DEFAULT_QUOTE_INTRO]; [pref registerString:"QuotePrefix" location:&EnhanceQuotePrefix control:"Quoting_Box2_Quoting_Form_Prefix" default:"> %0"]; [pref registerString:"QuoteRegex" location:&EnhanceQuoteRegex control:"Quoting_Box2_Quoting_Form_Regex" default:"^[>:# ]*[>:#] ?"]; [pref registerBool:"QuoteColoring" location:&EnhanceQuoteColoring control:"Quoting_Box2_Quoting_Color Quotes" default:NO]; [pref registerBool:"QuoteColoringInMailbox" location:&EnhanceQuoteColoringInMailbox control:"Quoting_Box2_Quoting_Color Quotes1" default:NO]; [pref registerColor:"QuoteColor" location:&EnhanceQuoteColor control:"Quoting_Box2_Quoting_Color" default:NX_COLORBLACK]; [pref registerBool:"QuoteRemoveCellDroppingHack" location:&EnhanceRemoveCellDroppings control:0 default:NO]; [pref registerBool:"InsertSignature" location:&EnhanceInsertSignature control:"Quoting_Box2_Signatures_Insert Signatures" default:NO]; [pref registerString:"SignatureFilename" location:&EnhanceSignatureFilename control:"Quoting_Box2_Signatures_Form_Filename" default:".signature"]; [pref registerString:"SignatureSeparator" location:&EnhanceSignatureSeparator control:"Quoting_Box2_Signatures_Form_Separator" default:"---\n"]; [pref registerBool:"InsertXFace" location:&EnhanceInsertXFace control:"Images_Box2_XFace_Form_Send XFace" default:NO]; [pref registerBool:"ShowXFace" location:&EnhanceShowXFace control:"Images_Box2_XFace_Form_Show XFace" default:NO]; XFaceButton=NXGetNamedObject("Images_Box2_XFace_Box_Image",pref); [pref registerString:"XFace" location:&EnhanceXFace control:"Images_Box2_XFace_Path" default:""]; [pref registerBool:"InsertXImageURL" location:&EnhanceInsertXImageURL control:"Images_Box2_XImageURL_Form_Send XImageURL" default:NO]; [pref registerBool:"ShowXImageURL" location:&EnhanceShowXImageURL control:"Images_Box2_XImageURL_Form_Show XImageURL" default:NO]; XImageURLButton=NXGetNamedObject("Images_Box2_XImageURL_Box_Image",pref); [pref registerString:"XImageURL" location:&EnhanceXImageURL control:"Images_Box2_XImageURL_Path" default:""]; [pref registerBool:"UsePGP" location:&EnhanceUsePGP control:"PGP_Box2_PGP_Use PGP" default:NO]; [pref registerInteger:"PGPPassTimeout" location:&EnhancePGPPassTimeout control:"PGP_Box2_PGP1_Pass Timeout" default:0]; [pref registerBool:"PGPPassAlwaysAskForSigning" location:&EnhancePGPPassAskForSigning control:"PGP_Box2_PGP1_Always Ask" default:YES]; [pref registerBool:"RetrievePGPKeys" location:&EnhanceRetrievePGPKeys control:NOTYET//"PGP_Box2_PGP2_Retrieve PGP Keys" default:NO]; [pref registerBool:"PGPSign" location:&EnhancePGPSign control:"PGP_Box2_PGP_Buttons_Sign" default:NO]; [pref registerBool:"PGPEncrypt" location:&EnhancePGPEncrypt control:"PGP_Box2_PGP_Buttons_Encrypt" default:NO]; [pref registerString:"PGPPath" location:&EnhancePGPPath control:"PGP_Box2_PGP_Texts_PGP Path" default:"/usr/local/bin/pgp"]; [pref registerInteger:"PGPVersion" location:&EnhancePGPVersion control:"PGP_Box2_PGP_Versions" default:PGP_VERSION_2_6]; [pref registerString:"KeyServerURL" location:&EnhanceKeyServerURL control:"PGP_Box2_PGP2_Key Server URL" default:"http://wwwkeys.pgp.net/pks/lookup?op=get&search="]; [pref registerBool:"PGPFancyDisplay" location:&EnhancePGPFancyStatusDisplay control:NOTYET//"PGP_Box2_PGP_Buttons_Fancy Status Display" default:NO]; [pref registerBool:"RepliesWithOriginals" location:&EnhanceRepliesWithOriginals control:"Options_Box2_Other_Form_Keep Replies with Originals" default:NO]; [pref registerBool:"AutoSpellCheck" location:&EnhanceAutoSpellCheck control:"Options_Box2_Other_Form_Automatically spell check messages" default:NO]; [pref registerBool:"AutoCompact" location:&EnhanceAutoCompact control:"Options_Box2_Other_Form_Automatically compact mailboxes" default:NO]; [pref registerBool:"LaunchMailboxes" location:&EnhanceLaunchMailboxes control:"Mailboxes_Box2_Launch_Form_Mailboxes" default:NO]; [pref registerBool:"LaunchAddresses" location:&EnhanceLaunchAddresses control:"Mailboxes_Box2_Launch_Form_Addresses" default:NO]; [pref registerBool:"FlagReplies" location:&EnhanceFlagReplies control:"Options_Box2_Other_Form_Flag Replies" default:NO]; [pref registerBool:"ExpandSmilies" location:&EnhanceExpandSmilies control:"Options_Box2_Other_Form_Expand Smilies" default:NO]; [pref registerInteger:"MaxTocCheckSize" location:&EnhanceMaxTocCheckSize control:"Mailboxes_Box2_Mailboxes_MaxTocCheckSize" default:100]; [pref registerInteger:"MaxSmileyExpansionMessageSize" location:&EnhanceMaxSmileyExpansionMessageSize control:0 default:-1]; [pref registerInteger:"MaxQuoteColorMessageSize" location:&EnhanceMaxQuoteColorMessageSize control:0 default:-1]; [pref registerBool:"RestoreDeletesDraft" location:&EnhanceRestoreDeletesDraft control:0 default:NO]; [pref registerBool:"BackSpaceBackPages" location:&EnhanceBackSpaceBackPages control:0 default:NO]; [pref registerString:"HTTPProxy" location:&EnhanceHTTPProxy control:"Images_Box2_Proxy_HTTP Proxy" default:""]; [pref registerString:"Smilies" location:&EnhanceSmilies control:"EnhanceSmileyTableViewController" default:DEFAULT_SMILIES]; [pref registerBool:"SilentNewMail" location:&EnhanceSilentNewMail control:"Mailboxes_Box2_Mailboxes_Form_SilentNewMail" default:NO]; [pref registerBool:"CheckPendingAppnmail" location:&EnhanceCheckPendingAppnmail control:"Mailboxes_Box2_Mailboxes_Form_CheckPendingAppnmail" default:YES]; [pref registerBool:"ReallyUseFixedPitchFontForPlainMessages" location:&EnhanceUseFixedPitchFontForPlainMessages control:"Options_Box2_Other_Form_ReallyUseFixedPitch" default:YES]; [pref registerBool:"ShowFlagged" location:&EnhanceShowFlagged control:"Mailboxes_Box2_Mailboxes_Form_ShowFlagged" default:NO]; [pref registerInteger:"MailboxCheckInterval" location:&EnhanceMailboxCheckInterval control:0 default:0]; [pref registerString:"FlagSearch" location:&EnhanceFlagSearchString control:0 default:DEFAULT_FLAG_SEARCH]; [pref registerString:"PreSelExtra" location:&EnhancePreSelExtra control:0 default:"@<%!."]; [pref registerString:"PostSelExtra" location:&EnhancePostSelExtra control:0 default:"@>"]; loadPrefs(pref); return self; } - (void)downLoad { downloadPrefsFromPanel(prefPanel); savePrefs(self); [super downLoad]; } - (void)upLoad { loadPrefs(self); uploadPrefsIntoPanel(prefPanel); [super upLoad]; } - show { uploadPrefsIntoPanel(prefPanel); return [super show]; } - controlFor:(const void *)location { struct PrefDefault *pd; for(pd=prefroot; pd; pd=pd->next) { if ((const void *)(pd->location.string) == location) return pd->control; } return nil; } - addPanel:panel { id cell; id popuplist; int tag; if (panel==nil) return nil; popuplist=[[viewButton cell] target]; for(tag=0;[popuplist findCellWithTag:tag]!=nil;tag++); cell=[popuplist addItem:[[panel window] title]]; [cell setTarget:self]; [cell setAction:@selector(changeView:)]; [cell setTag:tag]; if (PanelHash==nil) PanelHash=[[HashTable alloc] initKeyDesc:"i" valueDesc:"@"]; [PanelHash insertKey:(const void *)tag value:panel]; return self; } - registerBool:(const char *)name location:(BOOL *)loc control:(const char *)con default:(BOOL)def { struct PrefDefault *pd=allocPrefDefault(self, name, con, bool); pd->location.bool=loc; *loc=def; return self; } - registerString:(const char *)name location:(const char **)loc control:(const char *)con default:(const char *)def { struct PrefDefault *pd=allocPrefDefault(self, name, con, string); pd->location.string=loc; *loc=def; return self; } - registerInteger:(const char *)name location:(int *)loc control:(const char *)con default:(int)def { struct PrefDefault *pd=allocPrefDefault(self, name, con, integer); pd->location.integer=loc; *loc=def; return self; } - registerColor:(const char *)name location:(NXColor *)loc control:(const char *)con default:(NXColor)def { struct PrefDefault *pd=allocPrefDefault(self, name, con, color); pd->location.color=loc; *loc=def; return self; } - changeView:sender { id ret,item,panel,ogeneralview; int tag; if (((item=[viewButton selectedPopUpItem])==nil) ||((tag=[item tag])==0) ||(PanelHash==nil) ||((panel=[PanelHash valueForKey:(const void *)tag])==nil)) return [super changeView:sender]; ogeneralview=generalView; generalView=panel; [item setTag:0]; ret=[super changeView:sender]; [item setTag:tag]; generalView=ogeneralview; return ret; } - noteChangePassPhraseTimeout:sender // slider action method, instead of direct -takeIntValueFrom:, // for -noteChange: { id textField = [self controlFor:&EnhancePGPPassTimeout]; [textField takeIntValueFrom:sender]; return [self noteChange:sender]; } - noteChangeXFace:sender { id XFace=[self controlFor:&EnhanceXFace]; const char *val; NXRect r; NXImage *image; if (!XFace || !XFaceButton) return nil; val=[XFace stringValue]; [XFaceButton getBounds:&r]; image=[[NXImage alloc] initFromFile:val xFaceSize:&r.size]; if (image==nil) image=delete_image; [XFaceButton setImage:image]; return [self noteChange:sender]; } - noteChangeXImageURL:sender { id XImageURL=[self controlFor:&EnhanceXImageURL]; NXRect r; NXSize size; NXImage *image; const char *val; if (!XImageURL || !XImageURLButton) return nil; val=[XImageURL stringValue]; [XImageURLButton getBounds:&r]; image=[[NXImage alloc] initURL:val]; if (image==nil) image=delete_image; // [TRH] Don't scale image if it isn't necessary, // and keep size/width proportions intact if it is. [image getSize:&size]; if (size.height > r.size.height || size.width > r.size.width) { NXSize newsize = r.size; if (size.height > size.width) newsize.width = newsize.width*size.width/size.height; else if (size.height < size.width) newsize.height = newsize.height*size.height/size.width; [image setScalable:YES]; [image setSize:&newsize]; } [XImageURLButton setImage:image]; return [self noteChange:sender]; } - setXFace:sender { id open; const char *const types[] = { "tiff", 0 }; id XFaceC=[self controlFor:&EnhanceXFace]; if (((XFaceC=[self controlFor:&EnhanceXFace])==nil) || ((open=[OpenPanel new])==nil) || ([open allowMultipleFiles:NO]==nil) || ([open runModalForDirectory:[XFaceC stringValue] file:0 types:types]!=NX_OKTAG) || ([open filename]==0)) return nil; [XFaceC setStringValue:[open filename]]; return [self noteChangeXFace:sender]; } @end // EnhancePreferences // PrefDefault manipulation support functions. static const char *stringValueOfPref(struct PrefDefault *pd, char *buf) { const char *s = ""; switch (pd->type) { case bool: s = (*(pd->location.bool) ? "YES" : "NO"); break; case string: s = *(pd->location.string); break; case integer: sprintf(buf, "%d", *(pd->location.integer)); s = buf; break; case color: if ((s = NXColorName(*(pd->location.color))) == NULL) { float red, green, blue; NXConvertColorToRGB(*(pd->location.color), &red, &green, &blue); sprintf(buf, "RGB%02x%02x%02x", (int)rint(red*0xff), (int)rint(green*0xff), (int)rint(blue*0xff)); s = buf; } break; } return s; } static void setPrefToStringValue(id self, struct PrefDefault *pd, const char *value) { int i; const char *c; switch (pd->type) { case bool: if (strcasecmp(value,"YES")==0) *(pd->location.bool)=YES; else if (strcasecmp(value,"NO")==0) *(pd->location.bool)=NO; else [self logWarning:"%s: Boolean default %s given bad value \"%s\".",[NXApp appName],pd->name,value]; break; case string: *(pd->location.string)=value; break; case integer: i=strtol(value,&c,0); while(isspace(*c)) c++; if (*c=='\0') *(pd->location.integer)=i; else [self logWarning:"%s: Integer default %s given bad value \"%s\".",[NXApp appName],pd->name,value]; break; case color: i=-1; if ((strncmp(value,"RGB",3)==0)&&(strlen(value)==9)) { for(c=value+3,i=0;*c;c++) { if (*c>='0' && *c<='9') i=16*i+*c-'0'; else if (*c>='a' && *c<='f') i=16*i+*c-('a'-10); else if (*c>='A' && *c<='F') i=16*i+*c-('A'-10); else break; } if (*c) i=-1; else { *(pd->location.color)=NXConvertRGBToColor(((i>>16)&0xff)/255.0,((i>>8)&0xff)/255.0,(i&0xff)/255.0); i=0; } } if (i<0) { id colorlistlist=[NXColorList availableColorLists]; for(i=[colorlistlist count]-1;i>=0;i--) { if (NXFindColorNamed([[colorlistlist objectAt:i] name],value,pd->location.color)) break; } } if (i<0) [self logWarning:"%s: Color default %s given bad value \"%s\".",[NXApp appName],pd->name,value]; break; } } /* keep score of the total number of existing PrefDefaults, and the number of these registered with NXRegisterDefaults -- this is done lazily registerNewPrefs() to allow batching. */ static int totalPrefs=0, registeredPrefs=0; static struct PrefDefault *allocPrefDefault(id self, const char *name, const char *con, enum PrefDefaultType type) { struct PrefDefault *pd=malloc(sizeof(*pd)+strlen(name)+1); strcpy(pd->name,name); pd->type=type; pd->control=con ? NXGetNamedObject(con,self) : nil; if (pd->control && [pd->control respondsTo:@selector(setEnabled:)]) { [pd->control setEnabled:YES]; } pd->next=prefroot; prefroot=pd; ++totalPrefs; return pd; } static void registerNewPrefs() { int n = (totalPrefs - registeredPrefs); if (n > 0) { char buf[100]; struct _NXDefault defaults[n+1]; // !!! using GNU C extension. struct PrefDefault *pd = prefroot; int i; for (i = 0; i < n; i++) { if (pd == NULL) break; defaults[i].name = pd->name; /* I'm not sure if NXRegisterDefaults make a private copy of these values, or it just stores the pointer. In any case, just to be on the safe side, keep the values laying around. */ defaults[i].value = (char *)NXUniqueString(stringValueOfPref(pd, buf)); pd = pd->next; } defaults[i].name = defaults[i].value = NULL; NXRegisterDefaults([NXApp appName], defaults); } registeredPrefs = totalPrefs; } static void savePrefs(id self) { int n; registerNewPrefs(); if ((n = totalPrefs) > 0) { char buf[100]; struct _NXDefault defaults[n+1]; // !!! using GNU C extension. struct PrefDefault *pd = prefroot; int i; for (i = 0; i < n; i++) { if (pd == NULL) break; /* shouldn't happen. */ defaults[i].name = pd->name; defaults[i].value = NXCopyStringBuffer(stringValueOfPref(pd, buf)); pd = pd->next; } defaults[i].name = defaults[i].value = NULL; NXWriteDefaults([NXApp appName], defaults); while (--i >= 0) free(defaults[i].value); // cleanup. } } static void loadPrefs(id self) { struct PrefDefault *pd; const char *value; const char *appname = [NXApp appName]; registerNewPrefs(); NXUpdateDefaults(); for(pd=prefroot; pd; pd=pd->next) { if ((value = NXGetDefaultValue(appname, pd->name)) != NULL) { setPrefToStringValue(self, pd, value); } } } static void downloadPrefsFromPanel(id prefPanel) { struct PrefDefault *pd; for(pd=prefroot; pd; pd=pd->next) { if (pd->control!=nil) { switch (pd->type) { case bool: *pd->location.bool=[pd->control state]; break; case string: *pd->location.string=[pd->control stringValue]; break; case integer: if ([pd->control isKindOf:[Matrix class]]) // Assume Radio buttons. *pd->location.integer=[[pd->control selectedCell] tag]; else *pd->location.integer=[pd->control intValue]; break; case color: *pd->location.color=[pd->control color]; break; } } } } static void uploadPrefsIntoPanel(id prefPanel) { SEL noteChangeSelector = @selector(noteChange:); SEL sendActionToSelector = @selector(sendAction:to:); SEL controlViewSelector = @selector(controlView); struct PrefDefault *pd; for(pd=prefroot; pd; pd=pd->next) { id con; if (pd->control != nil) { switch (pd->type) { case bool: [pd->control setState:*(pd->location.bool)]; break; case string: [pd->control setStringValue:*(pd->location.string)]; break; case integer: if ([pd->control isKindOf:[Matrix class]]) // Assume Radio buttons. [pd->control selectCellWithTag:*(pd->location.integer)]; else [pd->control setIntValue:*(pd->location.integer)]; break; case color: [pd->control setColor:*(pd->location.color)]; break; } con = pd->control; if ([con respondsTo:sendActionToSelector] || ([con respondsTo:controlViewSelector] && (con = [con controlView]) != nil && [con respondsTo:sendActionToSelector])) { SEL action = [pd->control action]; if (action != noteChangeSelector) { [con sendAction:action to:[pd->control target]]; } } } } [prefPanel setDocEdited:NO]; }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.