@@ -53,6 +53,9 @@ typedef void (*MCExternalThreadOptionalCallback)(void *state);
5353typedef void (*MCExternalThreadRequiredCallback)(void *state, int flags);
5454
5555// MW-2013-06-14: [[ ExternalsApiV5 ]] Update the interface version.
56+ // MW-2016-02-25: [[ LicenseCheck ]] We cannot bump the interface version without
57+ // breaking existing built externals. Instead, we keep the version at 5 for 6.7
58+ // and add a HasLicenseCheck tag to the Query call.
5659#define kMCExternalInterfaceVersion 5
5760
5861enum
@@ -162,6 +165,8 @@ enum MCExternalError
162165 kMCExternalErrorNoObjectPropertyValue = 35 ,
163166
164167 kMCExternalErrorInvalidInterfaceQuery = 36 ,
168+
169+ kMCExternalErrorUnlicensed = 42 ,
165170};
166171
167172enum MCExternalContextQueryTag
@@ -185,6 +190,17 @@ enum MCExternalContextQueryTag
185190
186191 // MW-2013-06-14: [[ ExternalsApiV5 ]] Accessor to fetch 'the wholeMatches'.
187192 kMCExternalContextQueryWholeMatches ,
193+
194+ // SN-2014-07-01: [[ ExternalsApiV6 ]] These return a UTF16CString.
195+ // These are unimplemented in 6.7.
196+ kMCExternalContextQueryUnicodeItemDelimiter ,
197+ kMCExternalContextQueryUnicodeLineDelimiter ,
198+ kMCExternalContextQueryUnicodeColumnDelimiter ,
199+ kMCExternalContextQueryUnicodeRowDelimiter ,
200+
201+ // If fetching this accessor works, and it returns true then
202+ // the license check API is present.
203+ kMCExternalContextQueryHasLicenseCheck ,
188204};
189205
190206enum MCExternalVariableQueryTag
@@ -245,6 +261,14 @@ enum MCExternalDispatchStatus
245261 kMCExternalDispatchStatusAbort ,
246262};
247263
264+ enum MCExternalLicenseType
265+ {
266+ kMCExternalLicenseTypeNone = 0 ,
267+ kMCExternalLicenseTypeCommunity = 1000 ,
268+ kMCExternalLicenseTypeIndy = 2000 ,
269+ kMCExternalLicenseTypeBusiness = 3000 ,
270+ };
271+
248272enum MCExternalHandlerType
249273{
250274 kMCExternalHandlerTypeNone ,
@@ -277,7 +301,7 @@ struct MCExternalInterface
277301
278302 // ////////
279303
280- MCExternalError (*context_query )(MCExternalContextQueryTag op, void *result);
304+ MCExternalError (*context_query_legacy )(MCExternalContextQueryTag op, void *result);
281305
282306 // ////////
283307
@@ -338,6 +362,14 @@ struct MCExternalInterface
338362 // in the current context.
339363 // MW-2013-06-21: [[ ExternalsApiV5 ]] Added binds parameters for future extension.
340364 MCExternalError (*context_execute)(const char *p_expression, unsigned int options, MCExternalVariableRef *binds, unsigned int bind_count); // V5
365+
366+ // SN-2015-01-26: [[ Bug 14057 ]] Update context query, to allow the user to set the return type
367+ MCExternalError (*context_query)(MCExternalContextQueryTag op, MCExternalValueOptions p_options, void *r_result); // V6
368+
369+ // MW-2016-02-17: [[ LicenseCheck ]] Method to check the licensing of the engine. This is
370+ // present either if interface version is V7, or the HasLicenseCheck query call returns
371+ // true.
372+ MCExternalError (*license_check_edition)(unsigned int options, unsigned int min_edition); // V7
341373};
342374
343375typedef MCExternalInfo *(*MCExternalDescribeProc)(void );
@@ -360,20 +392,39 @@ class MCExternalV1: public MCExternal
360392 virtual Handler_type GetHandlerType (uint32_t index) const ;
361393 virtual bool ListHandlers (MCExternalListHandlersCallback callback, void *state);
362394 virtual Exec_stat Handle (MCObject *p_context, Handler_type p_type, uint32_t p_index, MCParameter *p_parameters);
363-
395+
396+ void SetWasLicensed (bool p_value);
397+
364398private:
365399 virtual bool Prepare (void );
366400 virtual bool Initialize (void );
367401 virtual void Finalize (void );
368402
369403 MCExternalInfo *m_info;
404+
405+ // This is true if startup succeeded (returned true) and license_fail was
406+ // not called.
407+ bool m_licensed : 1 ;
408+
409+ // This is set to true if the last external handler call on this external
410+ // did not call license_fail.
411+ bool m_was_licensed : 1 ;
370412};
371413
372414// //////////////////////////////////////////////////////////////////////////////
373415
416+ // This static variable is set to the currently executing external during
417+ // any calls to its exported functions (startup, shutdown etc.). It is used by
418+ // the license fail API to mark the external's was_licensed member as false.
419+ static MCExternalV1 *s_current_external = nil;
420+
421+ // //////////////////////////////////////////////////////////////////////////////
422+
374423MCExternalV1::MCExternalV1 (void )
375424{
376425 m_info = nil;
426+ m_licensed = false ;
427+ m_was_licensed = false ;
377428}
378429
379430MCExternalV1::~MCExternalV1 (void )
@@ -387,8 +438,15 @@ bool MCExternalV1::Prepare(void)
387438 MCExternalDescribeProc t_describe;
388439 t_describe = (MCExternalDescribeProc)MCS_resolvemodulesymbol (m_module, " MCExternalDescribe" );
389440
441+ // Update the current external var.
442+ s_current_external = this ;
443+
390444 // Query the info record - if this returns nil something odd is going on!
391445 m_info = t_describe ();
446+
447+ // Unset the current external var.
448+ s_current_external = nil;
449+
392450 if (m_info == nil)
393451 return false ;
394452
@@ -402,11 +460,28 @@ bool MCExternalV1::Initialize(void)
402460 t_initialize = (MCExternalInitializeProc)MCS_resolvemodulesymbol (m_module, " MCExternalInitialize" );
403461 if (t_initialize == nil)
404462 return true ;
405-
463+
464+ // Make sure the 'was_licensed' instance var is true. A call to LicenseFail
465+ // during startup will set it to false.
466+ m_was_licensed = true ;
467+
468+ // Update the current external var.
469+ s_current_external = this ;
470+
406471 // See if initialization succeeds.
407- if (!t_initialize (&g_external_interface))
472+ bool t_success;
473+ t_success = t_initialize (&g_external_interface);
474+
475+ // Unset the current external var.
476+ s_current_external = nil;
477+
478+ if (!t_success)
408479 return false ;
409-
480+
481+ // If license fail was invoked during startup, we mark the whole external
482+ // as unlicensed which means all calls to it will throw an error.
483+ m_licensed = m_was_licensed;
484+
410485 return true ;
411486}
412487
@@ -417,8 +492,14 @@ void MCExternalV1::Finalize(void)
417492 t_finalize = (MCExternalFinalizeProc)MCS_resolvemodulesymbol (m_module, " MCExternalFinalize" );
418493 if (t_finalize == nil)
419494 return ;
420-
495+
496+ // Update the current external var.
497+ s_current_external = this ;
498+
421499 t_finalize ();
500+
501+ // Unset the current external var.
502+ s_current_external = nil;
422503}
423504
424505const char *MCExternalV1::GetName (void ) const
@@ -454,7 +535,14 @@ Exec_stat MCExternalV1::Handle(MCObject *p_context, Handler_type p_type, uint32_
454535 t_handler = &m_info -> handlers[p_index];
455536 if (t_handler -> type != t_type)
456537 return ES_NOT_HANDLED;
457-
538+
539+ // If the external is not licensed (as a whole) then we throw the unlicensed error.
540+ if (!m_licensed)
541+ {
542+ MCeerror -> add (EE_EXTERNAL_UNLICENSED, 0 , 0 , m_info -> name);
543+ return ES_ERROR;
544+ }
545+
458546 Exec_stat t_stat;
459547 t_stat = ES_NORMAL;
460548
@@ -508,10 +596,25 @@ Exec_stat MCExternalV1::Handle(MCObject *p_context, Handler_type p_type, uint32_
508596 MCVariableValue t_result;
509597 t_result . set_temporary ();
510598 t_result . assign_empty ();
511-
599+
600+ // Update the current external var.
601+ s_current_external = this ;
602+
512603 // Invoke the external handler. If 'false' is returned, treat the result as a
513604 // string value containing an error hint.
514- if ((t_handler -> handler)(t_parameter_vars, t_parameter_count, &t_result))
605+ bool t_success;
606+ t_success = (t_handler -> handler)(t_parameter_vars, t_parameter_count, &t_result);
607+
608+ // Unset the current external var.
609+ s_current_external = nil;
610+
611+ // If a license check failed during the call, then we always throw an error.
612+ if (!m_was_licensed)
613+ {
614+ MCeerror -> add (EE_EXTERNAL_UNLICENSED, 0 , 0 , m_info -> name);
615+ t_stat = ES_ERROR;
616+ }
617+ else if (t_success)
515618 MCresult -> getvalue () . exchange (t_result);
516619 else
517620 {
@@ -530,6 +633,11 @@ Exec_stat MCExternalV1::Handle(MCObject *p_context, Handler_type p_type, uint32_
530633 return t_stat;
531634 }
532635
636+ void MCExternalV1::SetWasLicensed (bool p_value)
637+ {
638+ m_was_licensed = p_value;
639+ }
640+
533641// //////////////////////////////////////////////////////////////////////////////
534642
535643MCExternal *MCExternalCreateV1 (void )
@@ -1033,6 +1141,9 @@ static MCExternalError MCExternalContextQuery(MCExternalContextQueryTag op, void
10331141 *(MCObjectHandle **)result = t_handle;
10341142 }
10351143 break ;
1144+ case kMCExternalContextQueryHasLicenseCheck :
1145+ *(bool *)result = true ;
1146+ break ;
10361147 default :
10371148 return kMCExternalErrorInvalidContextQuery ;
10381149 }
@@ -2046,6 +2157,44 @@ static MCExternalError MCExternalInterfaceQuery(MCExternalInterfaceQueryTag op,
20462157 return kMCExternalErrorNone ;
20472158}
20482159
2160+
2161+ // //////////////////////////////////////////////////////////////////////////////
2162+
2163+ MCExternalError MCExternalLicenseCheckEdition (unsigned int p_options, unsigned int p_min_edition)
2164+ {
2165+ unsigned int t_current_edition;
2166+ switch (MClicenseparameters . license_class)
2167+ {
2168+ case kMCLicenseClassNone :
2169+ t_current_edition = kMCExternalLicenseTypeNone ;
2170+ break ;
2171+
2172+ case kMCLicenseClassCommunity :
2173+ t_current_edition = kMCExternalLicenseTypeCommunity ;
2174+ break ;
2175+
2176+ case kMCLicenseClassCommercial :
2177+ t_current_edition = kMCExternalLicenseTypeIndy ;
2178+ break ;
2179+
2180+ case kMCLicenseClassProfessional :
2181+ t_current_edition = kMCExternalLicenseTypeBusiness ;
2182+ break ;
2183+
2184+ default :
2185+ abort ();
2186+ break ;
2187+ }
2188+
2189+ if (t_current_edition < p_min_edition)
2190+ {
2191+ s_current_external -> SetWasLicensed (false );
2192+ return kMCExternalErrorUnlicensed ;
2193+ }
2194+
2195+ return kMCExternalErrorNone ;
2196+ }
2197+
20492198// //////////////////////////////////////////////////////////////////////////////
20502199
20512200MCExternalInterface g_external_interface =
@@ -2092,6 +2241,12 @@ MCExternalInterface g_external_interface =
20922241 // for the outside world.
20932242 MCExternalContextEvaluate,
20942243 MCExternalContextExecute,
2244+
2245+ // This is the new 'ContextQuery' call in 7+, it is unimplemented in 6.7.
2246+ nil,
2247+
2248+ // MW-2016-02-17: [[ LicenseCheck ]] Declare the check call.
2249+ MCExternalLicenseCheckEdition,
20952250};
20962251
20972252// //////////////////////////////////////////////////////////////////////////////
0 commit comments