/* Copyright (c) 2017, Computer History Museum All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted (subject to the limitations in the disclaimer below) provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Computer History Museum nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define FILE_NUM 131 /* Copyright (c) 1999 by QUALCOMM Incorporated */ #include "regcode_v2.h" #include "regcode_charsets.h" // Prototypes void MakeJumpPath(StringPtr s,short hostResID); Handle GenerateAdwareURLStr (UserStateType state, StringPtr host, short action, UInt32 query, long refcon); extern ModalFilterUPP DlgFilterUPP; // // OpenAdwareURL // // // Host is resource void OpenAdwareURL (UserStateType state, short hostResID, short action, UInt32 query, long refcon) { Str255 host; MakeJumpPath(host,hostResID); OpenAdwareURLStr (state,host,action,query,refcon); } // Host is string OSErr OpenAdwareURLStr (UserStateType state, StringPtr host, short action, UInt32 query, long refcon) { Handle url; Str255 protocol; short length; OSErr err; if (url = GenerateAdwareURLStr (state, host, action, query, refcon)) { length = GetHandleSize (url); if (length && (*url)[length]==0) length--; if (!ParseProtocolFromURLPtr (LDRef (url), length, protocol)) err = OpenOtherURLPtr (protocol, *url, length); ZapHandle (url); } return err; } // // GenerateAdwareURL // // 'state' - The state to be used when generating the URL (used by registration) // 'hostResID' - The host stuff... www.eudora.com // 'action' - The action to be taken. Pass in one of the constants from URLAction in StrnDefs // 'query' - A bit mask identifying the fields to be included in the query. Use the 'urlQueryParts' constants in adutil.h // 'refcon' - Paramater for special use of certain actions and query types. This mechanism is not entirely // swift since multiple query parts _could_ each require different refcons. This would break. Badly. // Don't do this. // // Host is resource Handle GenerateAdwareURL (UserStateType state, short hostResID, short action, UInt32 query, long refcon) { Str255 host; MakeJumpPath(host,hostResID); return GenerateAdwareURLStr (state,host,action,query,refcon); } // Host is string Handle GenerateAdwareURLStr (UserStateType state, StringPtr host, short action, UInt32 query, long refcon) { Accumulator urlAccumulator; AdURLStringsPtr urlStringPtrs; Str255 attribute, value; OSErr theError; // Initialize the accumulator into which we'll build the URL theError = AccuInit (&urlAccumulator); // Add the URL path, normally "http://www.eudora.com/jump.cgi" if (!theError) theError = AccuAddStr(&urlAccumulator, host); // Gimme a '?' if (!theError) theError = AccuAddChar (&urlAccumulator, '?'); // The query is built from the bit mask passed in 'query'. Each bit represents a attribute/value // pair that will be included in the query portion of the URL. See 'urlQueryParts' in adutil.h // for those parts that have been defined. See also 'URLQueryPartStrn' for the // attribute names if (!theError && (query & actionQueryPart)) theError = AccuAttributeValuePair (&urlAccumulator, GetRString (attribute, URLQueryPartStrn + queryAction), GetRString (value, URLActionStrn + action)); if (!theError && (query & realNameQueryPart)) theError = AccuAttributeValuePair (&urlAccumulator, GetRString (attribute, URLQueryPartStrn + queryRealname), GetDominantPref (PREF_REALNAME, value)); #ifdef I_HATE_THE_BOX if (!theError && (query & regFirstQueryPart) && !BoxUser (state)) #else if (!theError && (query & regFirstQueryPart)) #endif theError = AccuAttributeValuePair (&urlAccumulator, GetRString (attribute, URLQueryPartStrn + queryRegFirst), GetSomeHunkOfReg (state, value, action, GetRegFirst)); #ifdef I_HATE_THE_BOX if (!theError && (query & regLastQueryPart) && !BoxUser (state)) #else if (!theError && (query & regLastQueryPart)) #endif theError = AccuAttributeValuePair (&urlAccumulator, GetRString (attribute, URLQueryPartStrn + queryRegLast), GetSomeHunkOfReg (state, value, action, GetRegLast)); #ifdef I_HATE_THE_BOX if (!theError && (query & regCodeQueryPart) && BoxUser (state) && action == actionRegister50box) theError = AccuAttributeValuePair (&urlAccumulator, GetRString (attribute, URLQueryPartStrn + queryRegCode), GetDespisedBoxRegCode (state, value)); else theError = AccuAttributeValuePair (&urlAccumulator, GetRString (attribute, URLQueryPartStrn + queryRegCode), GetSomeHunkOfReg (state, value, action, GetRegCode)); #else if (!theError && (query & regCodeQueryPart)) theError = AccuAttributeValuePair (&urlAccumulator, GetRString (attribute, URLQueryPartStrn + queryRegCode), GetSomeHunkOfReg (state, value, action, GetRegCode)); #endif if (!theError && (query & regLevelQueryPart)) theError = AccuAttributeValuePair (&urlAccumulator, GetRString (attribute, URLQueryPartStrn + queryRegLevel), GetSomeHunkOfReg (state, value, action, GetRegLevel)); if (!theError && (query & oldRegQueryPart)) theError = AccuAttributeValuePair (&urlAccumulator, GetRString (attribute, URLQueryPartStrn + queryOldReg), GetOldRegCode (state, value)); if (!theError && (query & emailQueryPart)) theError = AccuAttributeValuePair (&urlAccumulator, GetRString (attribute, URLQueryPartStrn + queryEmail), GetShortReturnAddr (value)); if (!theError && (query & profileQueryPart)) theError = AccuAttributeValuePair (&urlAccumulator, GetRString (attribute, URLQueryPartStrn + queryProfile), GetProfileID (value)); if (!theError && (query & destinationQueryPart)) if (urlStringPtrs = (AdURLStringsPtr) refcon) if (urlStringPtrs->destination) theError = AccuAttributeValuePair (&urlAccumulator, GetRString (attribute, URLQueryPartStrn + queryDestination), urlStringPtrs->destination); if (!theError && (query & adIDQueryPart)) if (urlStringPtrs = (AdURLStringsPtr) refcon) if (urlStringPtrs->adID) theError = AccuAttributeValuePair (&urlAccumulator, GetRString (attribute, URLQueryPartStrn + queryAdID), urlStringPtrs->adID); if (!theError && (query & platformQueryPart)) theError = AccuAttributeValuePair (&urlAccumulator, GetRString (attribute, URLQueryPartStrn + queryPlatform), GetRString (value, REG_PLATFORM)); if (!theError && (query & productQueryPart)) theError = AccuAttributeValuePair (&urlAccumulator, GetRString (attribute, URLQueryPartStrn + queryProduct), GetRString (value, REG_PRODUCT)); if (!theError && (query & versionQueryPart)) theError = AccuAttributeValuePair (&urlAccumulator, GetRString (attribute, URLQueryPartStrn + queryVersion), GetVersionString (value)); if (!theError && (query & distributorIDQueryPart)) theError = AccuAttributeValuePairHandle (&urlAccumulator, GetRString (attribute, URLQueryPartStrn + queryDistributorID), GetDistributorID ()); if (!theError && (query & modeQueryPart)) theError = AccuAttributeValuePair (&urlAccumulator, GetRString (attribute, URLQueryPartStrn + queryMode), GetModeString (value)); if (!theError && (query & topicQueryPart)) theError = AccuAttributeValuePair (&urlAccumulator, GetRString (attribute, URLQueryPartStrn + queryTopic), GetRString (value, URLSupportTopicStrn + refcon)); if (!theError && (query & langQueryPart)) theError = AccuAttributeValuePair (&urlAccumulator, GetRString (attribute, URLQueryPartStrn + queryLang), GetRString (value, LOCALIZED_VERSION_LANG)); if (!theError && (query & queryQueryPart)) theError = AccuAttributeValuePair (&urlAccumulator, GetRString (attribute, URLQueryPartStrn + queryQuery), (PStr)refcon); if (!theError) { // If any query part was present, strip the '& off the end of the accumulator if (query & fullQuery) AccuStrip (&urlAccumulator, 1); // Tack a null at the end of the handle since DownloadURL expects a C string theError = AccuAddChar (&urlAccumulator, 0); } if (!theError) AccuTrim (&urlAccumulator); else AccuZap (urlAccumulator); return (urlAccumulator.data); } // MakeJumpPath - make path for jump URL void MakeJumpPath(StringPtr s,short hostResID) { // Get host GetRString(s,hostResID); // Slide in a slash '/' PCatC(s,'/'); // Tack on the command portion "jump.cgi" PCatR(s,URL_JUMP_COMMAND); } OSErr AccuAttributeValuePair (AccuPtr a, PStr attribute, PStr value) { OSErr theError; Str255 localValue; PCopy(localValue,value); TransLitRes(localValue+1,*localValue,ktFlatten); TransLitRes(localValue+1,*localValue,ktMacISO); URLQueryEscape(localValue); theError = noErr; if (attribute[0] && value[0]) { theError = AccuAddStr (a, attribute); if (!theError) theError = AccuAddChar (a, '='); if (!theError && value[0]) theError = AccuAddStr (a, localValue); if (!theError) theError = AccuAddChar (a, '&'); } return (theError); } OSErr AccuAttributeValuePairHandle (AccuPtr a, PStr attribute, Handle value) { Str255 scratch; OSErr theError; UPtr from, end; theError = noErr; if (attribute[0] && value) { theError = AccuAddStr (a, attribute); if (!theError) theError = AccuAddChar (a, '='); if (!theError && value) { // Old unescaped way... // theError = AccuAddHandle (a, value); end = *value + GetHandleSize (value); for (from = *value; !theError && from < end; from++) switch (*from) { case '%': case '&': case '?': case ':': case ' ': theError = AccuAddChar (a, '%'); if (!theError) theError = AccuAddPtr (a, Bytes2Hex (from, 1, scratch), 1); break; default: if (*from & 0x80) { theError = AccuAddChar (a, '%'); if (!theError) theError = AccuAddPtr (a, Bytes2Hex (from, 1, scratch), 1); } else theError = AccuAddChar (a, *from); break; } } if (!theError) theError = AccuAddChar (a, '&'); } return (theError); } // // ChooseInitialUserState // // Choose the initial state for a user very, very carefully... We need to be // able to recognize the difference between a new user, an old user and a box // user. // UserStateType ChooseInitialUserState (UserStateType state, Boolean foundRegFile, Boolean needsRegistration, int pnPolicyCode, InitNagResultType *result) { int regMonth; Boolean regValid; *result = noDialogPending; // If we've found a more recent RegCode file, set the state to that indicated by the policy code if (foundRegFile) state = PolicyCodeToRegisteredNagState (pnPolicyCode); // Don't trust anything or anyone... Now that we think we have a state, make darn sure if (!ValidUser (state)) { ComposeStdAlert (Note, STATE_INVALID_AT_STARTUP); *result = paymentRegPending; state = adwareUser; } // Do we suddenly have an invalid registration code? regValid = ValidRegCode (state, &pnPolicyCode, ®Month); if (RegisteredUser (state) && !regValid) { if (PayUser (state) && foundRegFile) { ComposeStdAlert (Note, REG_INVALID_AT_STARTUP); *result = codeEntryPending; } state = PolicyCodeToUnregisteredNagState (pnPolicyCode); } #ifdef I_HATE_THE_BOX // If the user has a valid regcode and is in Paid mode -- check the policy code // to verify that this is actually a regcode that applies to a box build if (regValid && PayUser (state) && !PolicyCheck (pnPolicyCode, regMonth)) state = boxUser; #else // If the user had previously been changed to a repay user, we make them sponsored here because they have relaunched if (RepayUser (state)) { *result = gracelessRepayPending; return (state = RegisteredUser (paidUser) ? regAdwareUser : adwareUser); } // If the registration code is valid, but the user is not entitled to this update, give them the Repay dialog if (IsPayUser () && *result == noDialogPending && regValid && !PolicyCheck (pnPolicyCode, regMonth)) *result = repayPending; #endif return (state); } Boolean PolicyCheck (int pnPolicyCode, int regMonth) { Boolean entitledToFreeUpgrade; entitledToFreeUpgrade = false; switch (pnPolicyCode) { case REG_EUD_AD_WARE: break; case REG_EUD_LIGHT: break; case REG_EUD_PAID: #ifndef I_HATE_THE_BOX // Never honor REG_EUD_PAID when using the box. The user is expected to // re-register and recieve back a policy code of REG_EUD_50_PAID_BOX_ESD (or higher) // when using the 5.0 box. entitledToFreeUpgrade = (regMonth < REG_EUD_CLIENT_34_DEFUNCT_MONTH) && (regMonth + 12 >= CLIENT_BUILD_MONTH); #endif break; case REG_EUD_50_PAID_TRIMODE: case REG_EUD_50_PAID_BOX_ESD: case REG_EUD_50_PAID_37_RSRV: case REG_EUD_50_PAID_38_RSRV: case REG_EUD_50_PAID_39_RSRV: case REG_EUD_50_PAID_40_RSRV: case REG_EUD_50_PAID_EN_ONLY: case REG_EUD_50_PAID_EN_NOT_X1: #ifdef DONT_CHECK_REGMONTH return true; #endif entitledToFreeUpgrade = (regMonth + 12 >= CLIENT_BUILD_MONTH); break; } return (entitledToFreeUpgrade); } // // CheckForRegCodeFile // // Checks to see if there is a RegCode file (with valid data, hopefully), returning // true or false. We pass in the date of the last known use of the RegCode file and // reparse the file if the current RegCode file is newer than the old one. // Boolean CheckForRegCodeFile (Boolean *needsRegistration, uLong *regDate, int *pnPolicyCode) { FSSpec spec; Str31 folderName; uLong curRegDate; *pnPolicyCode = regInvalidPolicyCode; if (!GetFileByRef (AppResFile, &spec)) if (!FSMakeFSSpec (spec.vRefNum, spec.parID, GetRString (folderName, STUFF_FOLDER), &spec)) { IsAlias (&spec, &spec); spec.parID = SpecDirId (&spec); GetRString (spec.name, REG_CODE_FILE); if ((curRegDate = FSpModDate (&spec)) > *regDate) if (!ParseRegFile (&spec, parseSilent, needsRegistration, pnPolicyCode)) { *regDate = curRegDate; return (true); } } return (false); } UserStateType PolicyCodeToRegisteredNagState (int policyCode) { switch (policyCode) { case REG_EUD_PAID: case REG_EUD_50_PAID_TRIMODE: case REG_EUD_50_PAID_BOX_ESD: case REG_EUD_50_PAID_37_RSRV: case REG_EUD_50_PAID_38_RSRV: case REG_EUD_50_PAID_39_RSRV: case REG_EUD_50_PAID_40_RSRV: case REG_EUD_50_PAID_EN_ONLY: case REG_EUD_50_PAID_EN_NOT_X1: return (paidUser); break; case REG_EUD_LIGHT: return (regFreeUser); break; case REG_EUD_AD_WARE: return (regAdwareUser); break; } return (regAdwareUser); } UserStateType PolicyCodeToUnregisteredNagState (int policyCode) { switch (policyCode) { case REG_EUD_PAID: case REG_EUD_50_PAID_TRIMODE: case REG_EUD_50_PAID_BOX_ESD: case REG_EUD_50_PAID_37_RSRV: case REG_EUD_50_PAID_38_RSRV: case REG_EUD_50_PAID_39_RSRV: case REG_EUD_50_PAID_40_RSRV: case REG_EUD_50_PAID_EN_ONLY: case REG_EUD_50_PAID_EN_NOT_X1: return (adwareUser); break; case REG_EUD_LIGHT: return (freeUser); break; case REG_EUD_AD_WARE: return (adwareUser); break; } return (adwareUser); } PStr GetDominantPref (short prefNumber, PStr string) { PushPers (PersList); GetPref (string, prefNumber); PopPers (); return (string); } PStr GetSomeHunkOfReg (UserStateType state, PStr string, short action, GetSomeHunkOfRegProcPtr getRegProc) { if (action == actionUpdate || action == actionArchived || action == actionPay) { (*getRegProc) (paidUser, string); if (!*string && state != paidUser) (*getRegProc) (state, string); } else (*getRegProc) (state, string); return (string); } PStr GetRegFirst (UserStateType state, PStr string) { Handle regInfo; short resID; resID = PayMode (state) ? REG_PREF_PAID : (AdwareMode (state) ? REG_PREF_SPONSORED : REG_PREF_LIGHT); regInfo = GetResourceFromFile (REG_PREF_TYPE, resID, SettingsRefN); if(regInfo == nil || GetHandleSize (regInfo) < 3) string[0] = 0; else CtoPPtrCpy(string,*regInfo); if (regInfo) ReleaseResource (regInfo); return (string); } PStr GetRegLast (UserStateType state, PStr string) { Handle regInfo; short resID; resID = PayMode (state) ? REG_PREF_PAID : (AdwareMode (state) ? REG_PREF_SPONSORED : REG_PREF_LIGHT); regInfo = GetResourceFromFile (REG_PREF_TYPE, resID, SettingsRefN); if(regInfo == nil || GetHandleSize (regInfo) < 3) string[0] = 0; else { Ptr c = *regInfo; c += strlen(c) + 1; CtoPPtrCpy(string,c); } if (regInfo) ReleaseResource (regInfo); return (string); } PStr GetRegCode (UserStateType state, PStr string) { Handle regInfo; short resID; resID = PayMode (state) ? REG_PREF_PAID : (AdwareMode (state) ? REG_PREF_SPONSORED : REG_PREF_LIGHT); regInfo = GetResourceFromFile (REG_PREF_TYPE, resID, SettingsRefN); if(regInfo == nil || GetHandleSize (regInfo) < 3) string[0] = 0; else { Ptr c = *regInfo; c += strlen(c) + 1; c += strlen(c) + 1; CtoPPtrCpy(string,c); } if (regInfo) ReleaseResource (regInfo); return (string); } #ifdef I_HATE_THE_BOX // // GetDespisedBoxRegCode // // Generate a registration code for box users, using: // // PolicyCode = 41 // Month = current minute // Name = Ihate Thebox // PStr GetDespisedBoxRegCode (UserStateType state, PStr string) { DateTimeRec dateTime; Str255 szName, szResult; GetRString (szName, THE_DAVE_AND_CHUCK_LOVE_CONNECTION); szName[++szName[0]] = 0; SecondsToDate (GMTDateTime(), &dateTime); *string = 0; if (!regcode_v2_encode (&szName[1], dateTime.minute, REG_EUD_50_TEMP_BOX_ESD, Random (), szResult)) CtoPPtrCpy (string, szResult); return (string); } #endif PStr GetRegLevel (UserStateType state, PStr string) { Str255 regName, regCode; int policyCode, regMonth; // grab name GetRegFirst(state,regName); GetRegLast(state,regCode); // reformat PSCatC(regName,' '); PSCat(regName,regCode); // grab code GetRegCode(state,regCode); *regName = MIN(*regName,254); *regCode = MIN(*regCode,254); regName[*regName+1] = 0; regCode[*regCode+1] = 0; // Grab month by verifying code if (RegCodeVerifies(regCode+1,regName+1,&policyCode,®Month)) NumToString(19*(((((Random()&0xff)<<8)|policyCode)<<8)|regMonth),string); else #ifdef I_HATE_THE_BOX { DateTimeRec dateTime; SecondsToDate (GMTDateTime(), &dateTime); NumToString(19*(((((Random()&0xff)<<8)|REG_EUD_50_TEMP_BOX_ESD)<<8)|dateTime.minute),string); } #else *string = 0; #endif return string; } PStr GetOldRegCode (UserStateType state, PStr string) { return (GetPref (string, PREF_SITE)); } PStr GetVersionString (PStr string) { VersRecHndl versInfo; string[0] = 0; if (versInfo = (VersRecHndl) GetResourceFromFile ('vers', 1, AppResFile)) { ComposeRString (string, REG_VERSION_FORMAT, (*versInfo)->numericVersion.majorRev, ((*versInfo)->numericVersion.minorAndBugRev & 0xF0) >> 4, (*versInfo)->numericVersion.minorAndBugRev & 0x0F, (*versInfo)->numericVersion.nonRelRev); ReleaseResource (versInfo); } return (string); } PStr GetModeString (PStr string) { return (GetRString (string, URLModeStrn + (IsPayMode () ? modePaid : (IsAdwareMode () ? modeAd : modeFree)))); } Handle GetDistributorID (void) { return (GetTextFromAppFolderFile (STUFF_FOLDER, DIST_ID)); } PStr GetProfileID (PStr string) { Handle profileID; string[0] = 0; if (profileID = GetProfileData ()) { string[0] = MIN (255, GetHandleSize (profileID)); BMD (*profileID, &string[1], string[0]); ReleaseResource (profileID); } return (string); } Handle GetProfileData (void) { Handle theData = GetResourceFromFile (USER_PROFILE_TYPE, USER_PROFILE_ID, SettingsRefN); if (!theData) { TOCType inTOC, outTOC; FSSpec spec; Str63 s; // Try to fetch from In/Out toc's if (!FSMakeFSSpec(MailRoot.vRef,MailRoot.dirId,GetRString(s,IN),&spec)) if (!PeekTOC(&spec,&inTOC)) if (!FSMakeFSSpec(MailRoot.vRef,MailRoot.dirId,GetRString(s,OUT),&spec)) if (!PeekTOC(&spec,&outTOC)) if (outTOC.profile[0] || outTOC.profile[1] || inTOC.profile[0] || inTOC.profile[1]) { // Got something. Format & save ComposeString(s,"\p%8x%8x%8x%8x",inTOC.profile[0],inTOC.profile[1],outTOC.profile[0],outTOC.profile[1]); SettingsPtr(USER_PROFILE_TYPE, nil, USER_PROFILE_ID, s+1, *s); // refetch theData = GetResourceFromFile (USER_PROFILE_TYPE, USER_PROFILE_ID, SettingsRefN); } } return theData; } OSErr SetProfileID(PStr profile) { TOCHandle inTOCH, outTOCH; long profileAsLongs[4]; OSErr err = noErr; if (*profile) err = SettingsPtr(USER_PROFILE_TYPE, nil, USER_PROFILE_ID, profile+1, *profile); else ZapResource(USER_PROFILE_TYPE, USER_PROFILE_ID); ASSERT(*profile==0 || *profile==32); if (*profile) Hex2Bytes(profile+1,32,(Ptr)profileAsLongs); else WriteZero(profileAsLongs,16); if (!err) { err = memFullErr; if (inTOCH=GetSpecialTOC(IN)) if (outTOCH=GetSpecialTOC(OUT)) { (*inTOCH)->profile[0] = profileAsLongs[0]; (*inTOCH)->profile[1] = profileAsLongs[1]; (*outTOCH)->profile[0] = profileAsLongs[2]; (*outTOCH)->profile[1] = profileAsLongs[3]; (*inTOCH)->reallyDirty = true; (*outTOCH)->reallyDirty = true; err = noErr; } } return err; } Handle GetTextFromEudoraFolderFile (short fileResID) { FSSpec spec; Str255 fileName; Handle text; OSErr theError; text = nil; theError = FSMakeFSSpec (Root.vRef, Root.dirId, GetRString (fileName, fileResID), &spec); if (!theError) { IsAlias (&spec, &spec); theError = Snarf (&spec, &text, 0); } if (theError) ZapHandle (text); return (text); } Handle GetTextFromAppFolderFile (short folderResID, short fileResID) { FSSpec spec; Str255 folderName; Handle text; OSErr theError; text = nil; theError = GetFileByRef (AppResFile, &spec); if (!theError) theError = FSMakeFSSpec (spec.vRefNum, spec.parID, GetRString (folderName, folderResID), &spec); if (!theError) { IsAlias (&spec, &spec); spec.parID = SpecDirId (&spec); GetRString (spec.name, fileResID); theError = Snarf (&spec, &text, 0); } if (theError) ZapHandle (text); return (text); } // // GetResourceFromFile // // Get a resource, but make sure we're doing so only from a specifc // file. We do this for the registration resources because we want // to make sure that certain information comes from the app and // certain information comes from the settings file -- without // interference from resource plug-ins // Handle GetResourceFromFile (ResType theType, short theID, short refNum) { Handle resHandle; OSErr theError; short oldResFile; oldResFile = CurResFile (); UseResFile (refNum); resHandle = Get1Resource (theType, theID); theError = ResError (); UseResFile (oldResFile); if (theError == resNotFound) // Uh oh... a resource isn't where it was supposed to be. :( ; return (resHandle); } // // ValidRegCode // Boolean ValidRegCode (UserStateType state, int *policyCode, int *regMonth) { Str255 regCode, regName; short len; GetRegCode (state, regCode); *regCode = MIN(*regCode,254); regCode[regCode[0] + 1] = 0; GetRegFirst (state, regName); GetRegLast (state, ®Name[regName[0] + 1]); len = regName[regName[0] + 1]; regName[regName[0] + 1] = ' '; regName[0] += (len + 1); *regName = MIN(*regName,254); regName[regName[0] + 1] = 0; return RegCodeVerifies (®Code[1], ®Name[1], policyCode, regMonth); } Boolean RegCodeVerifies(const char *szCode, const char *szName, int *outProduct, int *outMonth) { int pnMonth; int pnProduct; Boolean verified = true; //char mapName[REG_CODE_MAX_NAME]; // So... University of California, Berkeley is one pretty darn long name... Reg codes have been generated // on the server and from the installer without imposing the 20 character limit originally intended for these // things. When validating, we're overflowing the buffer and crunching the stack when a really long name // is input. Truncation won't help since we'd be validating a different key. Str255 mapName; // So, some idiot thinks that the Code Entry dialog is a "security risk" because he's able to type 255 characters // into the first name field and crash the reg code verifier. He further believes that this is a "risk" because // Eudora has the capability of automatically processing registration information -- never mind that the only // regcodes we'll be automatically processing are those we've generated ourselves... // // We'll combat such stupidity by not even calling the verifier and making sure that the policy code fails. if (strlen (szCode) > REG_CODE_LEN - 1 || strlen (szName) > sizeof (mapName) - 1) { if (outProduct) *outProduct = regInvalidPolicyCode; return (false); } regcode_map_macroman(szName, mapName); verified = !regcode_v2_verify(szCode, mapName, &pnMonth, &pnProduct); if(outProduct) { *outProduct = verified ? pnProduct : regInvalidPolicyCode; } if(outMonth) { *outMonth = verified ? pnMonth : 0; } return verified; }