This is Controller.m in view mode; [Download] [Up]
/* Controller.m -- Controller object for MailHelper application. Copyright 1991, Izumi Ohzawa and Manuel Alberto Ricart, All rights reserved. 3-17-91 V1.0 (IO) * Starting project. * Some codes are borrowed from AtYourService NeXT demo application. 4-6-91 V1.0 (IO) * Bug fix: fclose(fpin); was missing in method insertSignature. 9-18-91 V1.1 (MAR) * Preferences panel and use of default database to store them. Joint venture with Izumi? Perhaps. Izumi sent me his code for MailHelper. I told him I implement some basic prefs for him. 9-22-91 V1.1 (IO) * Defaults now written out as soon as OK button in Pref panel is pressed. * Signature insertion now adds a separator '---' within the code to remove requirement of having it in signature file itself (to make MailHelper conform with other programs which use .signature). * RTF signature insertion added. 10-9-91 V1.2 (Mitsuhiro Kishimoto) * Japanese re-format routine: needed to handle mixed ASCII and 2-byte EUC code. Original "Kin-soku" (forbidden line break) code was written by Masatoshi Kurihara. 9-10-93 V1.3 Mike O'Neill (emo@mitre.org) added .rtfd support, grayed rtf selection, and 3.0 colorized icon and compiled FAT To implement: User selectable command keys for various functions. */ #import "Controller.h" #import <appkit/appkit.h> @implementation Controller /* Modified Izumi's code to load the defaults at startup. * It also sets up the default values on the prefs panel. */ - appDidInit:sender { static NXDefaultsVector MailHelperDefaults = { {WIDTH,"62"}, {QUOTE,"> "}, {SIGFILE,SIGFILENAME}, {RTFSIGFILE,RTFSIGFILENAME}, {RTFDSIGFILE,RTFDSIGFILENAME}, {NULL} }; myListener = [NXApp appListener]; [myListener setServicesDelegate: self]; NXRegisterDefaults(APPNAME, MailHelperDefaults); wrapWidth = atoi(NXGetDefaultValue(APPNAME, WIDTH)); [gWrapWidth setIntValue:wrapWidth]; [gWrapScroller setIntValue:wrapWidth]; quoteString =(char *) NXGetDefaultValue(APPNAME, QUOTE); [gQuoteString setStringValue:quoteString]; sigFile =(char *) NXGetDefaultValue(APPNAME, SIGFILE); [gSigFileName setStringValue:sigFile]; rtfSigFile =(char *) NXGetDefaultValue(APPNAME, RTFSIGFILE); [gRtfSigFileName setStringValue:rtfSigFile]; rtfdSigFile =(char *) NXGetDefaultValue(APPNAME, RTFDSIGFILE); [gRtfdSigFileName setStringValue:rtfdSigFile]; // [gRtfdText setGraphicsImportEnabled:YES]; return self; } /* Brings up the Info panel. Not done on startup because it's in a separate * interface file. Saves startup time for the user if we do this when they ask * for it, and not before. * "infoPanel" and "helpPanel" are defined in "Info.nib". */ - infoPanel:sender { if( ! infoPanel ){ [NXApp loadNibSection:"Info.nib" owner:self]; } [infoPanel makeKeyAndOrderFront:sender]; return self; } // Records the prefsPanel values into the global variables /* [izumi] Moved from delegate method -appWillTerminate:, because it is * not apparently called if user is logging out from Workspace -- * this is how MailHelper gets terminated (MailHelper is almost never * exited via Quit from menu.). */ - prefsOK:sender { char buf[20]; wrapWidth = (int)[gWrapWidth intValue]; quoteString = (char *)[gQuoteString stringValue]; sigFile = (char *)[gSigFileName stringValue]; rtfSigFile = (char *)[gRtfSigFileName stringValue]; sprintf(buf, "%d", wrapWidth); NXWriteDefault(APPNAME, WIDTH, buf); NXWriteDefault(APPNAME, QUOTE, quoteString); NXWriteDefault(APPNAME, SIGFILE, sigFile); NXWriteDefault(APPNAME, RTFSIGFILE, rtfSigFile); return self; } - prefsCancel:sender { [gWrapWidth setIntValue:wrapWidth]; [gWrapWidth display]; [gWrapScroller setIntValue:wrapWidth]; [gWrapScroller display]; [gQuoteString setStringValue:quoteString]; [gQuoteString display]; [gSigFileName setStringValue:sigFile]; [gSigFileName display]; [gRtfSigFileName setStringValue:rtfSigFile]; [gRtfSigFileName display]; return self; } /* * Brings up the Help panel (as above) */ - helpPanel:sender { if( ! helpPanel ){ [NXApp loadNibSection:"Info.nib" owner:self]; } [helpPanel makeKeyAndOrderFront:sender]; return self; } /* Reformats selected text so that it fits into a specified column width. * Alberto's Modifications: * initialized colLimit to wrapWidth global variable. */ - reformatSelection:(id)pbid userData:(const char *)udata error:(char **)errmsg { char *data; int length; const char *const *types; int hasAscii, i; types = [pbid types]; /* get a list of pasteboard types */ hasAscii = 0; for(i=0; !hasAscii && types[i]; i++) if(!strcmp(types[i], NXAsciiPboardType)) hasAscii = 1; if(hasAscii) { [pbid readType:NXAsciiPboardType data:&data length:&length]; if(data && length) { char *returnData, *dataptr, *endptr; char *retptr; int col; unsigned char c1, c2; col = 0; returnData=malloc(length+10); dataptr = data; endptr = dataptr+length; retptr = returnData; while (dataptr < endptr) { c1 = *dataptr++; c2 = (iskanji (c1) ? *dataptr++ : *dataptr); switch (c1) { case '\n': if ( c2 == '\n') col = 0; else if (iskanji (c2)) goto skip_char; else c1 = ' '; break; case '\t': col = (col + 8) &~ 7; break; case '\b': col = col ? col - 1 : 0; break; default: col = col + (iskanji (c1) ? 2 : 1); } if (col > wrapWidth) { if ( ! iskanji (c1)) { for (i = 1; 0 < col - i; i++) { c2 = *(retptr - i); if ( iskanji (c2) ) { dataptr -= i; retptr -= (i - 1); *retptr++ = '\n'; col = 0; goto skip_char; } else if ( isspace (c2) ) { dataptr -= i; retptr -= i; *retptr++ = '\n'; col = 0; goto skip_char; } } *retptr++ = '\n'; col = 1; } else if (iskanji (c1) && ! KINSOKU (c1, c2)) { *retptr++ = '\n'; col = 2; } } *retptr++= c1; if (iskanji (c1)) *retptr++= c2; else if (c1 == '\n' && c2 == '\n') { *retptr++= c2; dataptr++; } skip_char: ; } *retptr++= '\n'; *retptr = '\0'; [pbid declareTypes:&NXAsciiPboardType num:1 owner:self]; [pbid writeType:NXAsciiPboardType data:returnData length:strlen(returnData)]; free(returnData); } /* end if(data && length) */ else *errmsg = "Selection is empty."; } /* end if(hasAscii) */ else *errmsg = "No ASCII text found in your selection."; return self; } /* Adds quotation marks "> " to the head of each line of selected text. * Alberto's Modification: * Only changed the definition of quotestr to point to the quoteString global. */ - quoteSelection:(id)pbid userData:(const char *)udata error:(char **)errmsg { char *data; int length; const char *const *types; char *quotestr = quoteString; int hasAscii, i, quotelen; quotelen = strlen(quotestr); types = [pbid types]; /* get a list of pasteboard types */ hasAscii = 0; for(i=0; !hasAscii && types[i]; i++) if(!strcmp(types[i], NXAsciiPboardType)) hasAscii = 1; if(hasAscii) { [pbid readType:NXAsciiPboardType data:&data length:&length]; if(data && length) { int numlines; char ch; char *returnData, *dataptr, *endptr, *outptr; numlines = 1; dataptr = data; /* ptr to original data */ endptr = data+length; /* ptr to end of data */ while(dataptr < endptr) /* count the number of lines */ if(*dataptr++ == '\n') numlines++; returnData=malloc(length+numlines*quotelen+10); dataptr = data; /* reinitialize ptr to orig data */ outptr = returnData; for(i=0;i<quotelen;i++) *outptr++ = quotestr[i]; while(dataptr < endptr) { if((ch = *dataptr++) == '\n') { *outptr++ = ch; for(i=0;i<quotelen;i++) *outptr++ = quotestr[i]; } else *outptr++ = ch; } *outptr = '\n'; *(outptr+1) = '\0'; [pbid declareTypes:&NXAsciiPboardType num:1 owner:self]; [pbid writeType:NXAsciiPboardType data:returnData length:strlen(returnData)]; free(returnData); } /* end if(data && length) */ else *errmsg = "Selection is empty."; } /* end if(hasAscii) */ else *errmsg = "No ASCII text found in your selection."; return self; } // Adds the content of ~/.signature at the current cursor location. - insertSignature:(id)pbid userData:(const char *)udata error:(char **)errmsg { char *data, *dataptr; char *signaturefile = sigFile; char signaturepath[256]; int length, i; struct stat filestat; FILE *fpin; sprintf(signaturepath, "%s/%s", NXHomeDirectory(), signaturefile); if(stat(signaturepath, &filestat)) { data = ""; length = 0; *errmsg = "No signature file found in your home directory."; } else { length = filestat.st_size; if((fpin = fopen(signaturepath, "r")) != NULL) { dataptr = data = malloc(length+NUMSIGDASH+10); /* data remains unchanged */ for(i=0; i<NUMSIGDASH; i++) /* Add '---' signature separator here */ *dataptr++ = '-'; *dataptr++ = '\n'; fread((void *)dataptr, 1, length, fpin); fclose(fpin); /* This was missing in V1.0 release */ *(dataptr+length) = '\0'; [pbid declareTypes:&NXAsciiPboardType num:1 owner:self]; [pbid writeType:NXAsciiPboardType data:data length:strlen(data)]; free(data); } else *errmsg = "Cannot open signature file."; } return self; } // Adds the content of ~/.signature.rtf at the current cursor location. // RTF signature insertion method. - insertRtfSignature:(id)pbid userData:(const char *)udata error:(char **)errmsg { char *data; char *signaturefile = rtfSigFile; char signaturepath[256]; int length; struct stat filestat; FILE *fpin; sprintf(signaturepath, "%s/%s", NXHomeDirectory(), signaturefile); if(stat(signaturepath, &filestat)) { data = ""; length = 0; *errmsg = "No RTF signature file found in your home directory."; } else { length = filestat.st_size; if((fpin = fopen(signaturepath, "r")) != NULL) { data = malloc(length+10); fread((void *)data, 1, length, fpin); fclose(fpin); *(data+length) = '\0'; [pbid declareTypes:&NXRTFPboardType num:1 owner:self]; [pbid writeType:NXRTFPboardType data:data length:strlen(data)]; free(data); } else *errmsg = "Cannot open RTF signature file."; } return self; } // Adds the content of ~/.signature.rtfd at the current cursor location. // RTFD signature insertion method. - insertRtfdSignature:(id)pbid userData:(const char *)udata error:(char **)errmsg { char *data; char *signaturefile = rtfdSigFile; char signaturepath[256]; int length; struct stat filestat; sprintf(signaturepath, "%s/%s", NXHomeDirectory(), signaturefile); if(stat(signaturepath, &filestat)) { data = ""; length = 0; *errmsg = "No RTFD signature found in your home directory."; } else { if(![gRtfdText openRTFDFrom:signaturepath]) { [tempText selectAll:self]; // This bit of code is necessary because [tempText paste:self]; // while Edit, Mail and Text all support RTFD [gRtfdText selectAll:self]; // there is as yet no proper NXAtom for the [gRtfdText copy:self]; // pasteboard type. So I use the copy and [gRtfdText writeSelectionToPasteboard:pbid types:(NXAtom *)[[Pasteboard newName:NXGeneralPboard] types]]; [tempText selectAll:self]; // to put the text on the general pboard, [tempText copy:self]; //from whence I then get the types! } else *errmsg = "Cannot open RTFD signature."; } return self; } // quote an RTF selection by graying it out - grayRTFSelection:(id)pbid userData:(const char *)udata error:(char **)errmsg { NXAtom pbtype[] = {NXRTFPboardType, 0}; [tempText selectAll:self]; [tempText readSelectionFromPasteboard:pbid]; [tempText setSelGray:NX_DKGRAY]; [tempText writeSelectionToPasteboard:pbid types:pbtype]; return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.