meetingui/meetingrequestviewers/src/CMRHandler.cpp
changeset 0 f979ecb2b13e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/meetingui/meetingrequestviewers/src/CMRHandler.cpp	Tue Feb 02 10:12:19 2010 +0200
@@ -0,0 +1,693 @@
+/*
+* Copyright (c) 2005 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: Implementation for meeting request handler   
+*
+*/
+
+
+
+
+// INCLUDE FILES
+#include "CMRHandler.h"
+#include "MMRModelInterface.h"		
+#include "MREntryConsultant.h"	
+#include "CMRObjectFactory.h"			
+#include "CMRCmdHandler.h"
+#include "mrdatalog.h"
+#include "ICalUILog.h"
+#include "meetingrequestviewers.hrh" 	//constants for meeting request viewers
+#include <CAttendeeView.h>				//attendees view
+#include <MAgnEntryUi.h>				//TAgnEntryUiInParams & entry ui callback
+#include "CMRUtilsInternal.h"			//Meeting request utilities library
+#include <MRCommands.hrh> 				//common commands for attendee, editor and meeting request views
+#include <AknGlobalNote.h>
+#include <CalenEditorsPlugin.h> 		//calendar editors ecom plugin
+#include <stringloader.h>				//resource string loading
+#include <cmrmailboxutils.h>
+#include <AknQueryDialog.h>
+#include "ICalUILog.h"
+#include "MRViewersPanic.h"
+
+// CONSTANTS
+/// Unnamed namespace for local definitions
+namespace {
+
+_LIT( KPanicMsg, "CMRHandler" );
+
+void Panic( TPanicCode aReason )
+    {
+    User::Panic( KPanicMsg, aReason );
+    }
+
+}  // namespace
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CMRHandler::CMRHandler
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CMRHandler::CMRHandler(
+    RPointerArray<CCalEntry>& aEntries,
+    const MAgnEntryUi::TAgnEntryUiInParams& aParams,
+	MAgnEntryUi::TAgnEntryUiOutParams& aOutParams,
+    MAgnEntryUiCallback& aCallback )
+    : iEntries( aEntries ),
+      iInParams( aParams ),
+      iOutParams( aOutParams ),
+      iCallback( aCallback )
+    {
+    LOG("CMRHandler::CMRHandler()");
+    iStatus = EInitialView;
+    }
+
+// -----------------------------------------------------------------------------
+// CMRHandler::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+
+void CMRHandler::ConstructL()
+    {	                           
+    LOG("CMRHandler::ConstructL");
+    //calling app is calendar, create calendar editor ecom plugin
+    if (iInParams.iCallingApp.iUid == KUidCalendarApplication )
+    	{
+    	iCalendarEditorsPlugin = CCalenEditorsPlugin::NewL();
+    	}
+    LOG("CMRHandler::ConstructL -> End");
+    }
+
+// -----------------------------------------------------------------------------
+// CMRHandler::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CMRHandler* CMRHandler::NewL(
+    RPointerArray<CCalEntry>& aEntries,
+    const MAgnEntryUi::TAgnEntryUiInParams& aParams,
+    MAgnEntryUi::TAgnEntryUiOutParams& aOutParams,
+    MAgnEntryUiCallback& aCallback )
+    {
+    CMRHandler* self = new( ELeave ) CMRHandler( aEntries,
+                                                 aParams,
+                                                 aOutParams,
+                                                 aCallback );
+
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop();
+
+    return self;
+    }
+
+
+// Destructor
+CMRHandler::~CMRHandler()
+    {
+    LOG("CMRHandler::~CMRHandler");
+	delete iModel;
+	delete iCalendarEditorsPlugin;
+	delete iCmdHandler;
+    // entry arrray only referenced so iEntries mustn't be closed
+    LOG("CMRHandler::~CMRHandler -> End");
+    }
+
+// -----------------------------------------------------------------------------
+// CMRHandler::IsCommandAvailable
+// -----------------------------------------------------------------------------
+//
+TBool CMRHandler::IsCommandAvailable( TInt aCommandId )
+    {
+    if ( aCommandId == EMRCommandRetrieve ||
+         aCommandId == EMRCommandAttachments ||
+         aCommandId == EMRCommandUnreadOpeningNote )
+        {
+        return iCallback.IsCommandAvailable( aCommandId );
+        }
+    else
+        {        
+        // otherwise caller knows the availability
+        return ETrue;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CMRHandler::ProcessCommandWithResultL
+// -----------------------------------------------------------------------------
+//
+TInt CMRHandler::ProcessCommandWithResultL( TInt aCommandId )
+	{
+	TInt retVal( KErrNone );
+	
+	switch( aCommandId )
+		{				
+		case EMRCommandExitDialogs:
+	    case EAknCmdExit:
+	    case EEikCmdExit:		
+			{
+			iStatus = ECloseMeetingRequestViews;
+			break;
+			}
+		case EMRCommandReplyToSender:   // fall through
+		case EMRCommandReplyToOrganiser:// fall through
+		case EMRCommandReplyToAll:      
+			{
+			//do reply
+			iCmdHandler->CreateReplyL( aCommandId );
+			iStatus = ECloseMeetingRequestViews;
+			break;
+			}			
+		case EMRCommandShowDescriptionView:
+			{
+			if ( iInParams.iCallingApp.iUid == KUidCalendarApplication &&
+			     iInParams.iEditorMode != MAgnEntryUi::EViewEntry )
+				{ // ECreateNewEntry, EEditExistingEntry
+				iStatus = ELaunchMeetingEditorView;
+                }
+            else
+				{
+				iStatus = ELaunchMeetingDescriptionView;
+				}
+            break;
+			}
+		case EMRCommandShowAttendeesView:
+			{
+			//set status to launch attendee view
+			iStatus = ELaunchAttendeeView;
+			break;
+			}
+		case EMRCommandShowSummaryView:
+			{
+			//set status to launch summary view;
+			iStatus = ELaunchMeetingRequestView;
+			break;
+			}			
+        // forward actually closes MR Viewer (mail framework does that)			
+		case EMRCommandForward:
+		case EMRCommandAttachments:
+		case EMRCommandMessageDetails:
+        case EMRCommandRetrieve:
+			{
+			retVal = iCallback.ProcessCommandWithResultL( aCommandId );
+			break;
+			}
+		case EMRCommandNavigateBackward:
+		case EMRCommandNavigateForward:
+			{
+			// check if mailbox has other entries so that navigation is possible
+			if ( iCallback.IsCommandAvailable( aCommandId ) )
+				{
+				TBool allowExit( ETrue );
+				
+				// TODO: check exit condition for MR, present user a dialog with
+				//  saving & sending options... same as when closing the view
+
+				
+				// pass command to callback, framework takes care of the rest
+				if ( allowExit )
+					{
+					iStatus = ECloseMeetingRequestViews;
+					retVal = iCallback.ProcessCommandWithResultL( aCommandId );
+					}
+				else
+					{
+					// user cancelled navigation
+					retVal = KErrCancel;
+					}
+				}
+			else
+				{
+				retVal = KErrNotSupported;
+				}
+            break;
+			}	
+			
+		// commands which modify or might possibly modify entry(s), and which
+		// cause exit mr viewer if completed succesfully:
+		case EMRCommandSend:            // fall through
+		case EMRCommandSendUpdate:      // fall through
+		case EMRCommandCancelMR:        // fall through
+		case EMRCommandDeleteMR:        // fall through
+		case EMRCommandRespondAccept:   // fall through
+		case EMRCommandRespondTentative:// fall through
+		case EMRCommandRespondDecline:  // fall through		
+		case EMRCommandSaveAndExit:	
+            {
+            TRAPD( err, retVal = ProcessTrappedModifCmdL( aCommandId ) );
+            if ( err != KErrNone || retVal != KErrNone )
+                { // error result or leave occurred, don't exit viewer but 
+                  // ensure data integrity
+                // TODO: show error note possibly?
+                RefreshViewL();
+                User::LeaveIfError( err );
+                }
+            else
+                {
+                iStatus = ECloseMeetingRequestViews;
+                }
+            break;
+            }
+				
+        // commands which modify or might possibly modify entry(s), and which
+        // do not exit mr viewer:
+		case EMRCommandSave:               // fall through
+		case EMRCommandDisableAlarm:       // fall through
+		case EMRCommandRemoveFromCalendar: // fall through
+		case EMRCommandSaveFromFile:
+		    {
+		    // trap leaves to ensure data integrity
+            TRAPD( err, retVal = ProcessTrappedModifCmdL( aCommandId ) );
+            RefreshViewL();
+            User::LeaveIfError( err );
+            break;
+		    }
+		    			
+			/*
+		case EMRCommandHelpMeetingDescriptionView:
+			{
+			//do help showing of currently displayed view
+			break;
+			}
+		case EMRCommandHelpMeetingRequestView:
+			{
+			//do showing of help for meeting request view
+			break;
+			}*/
+		}
+        
+	return retVal;
+	}
+
+// -----------------------------------------------------------------------------
+// CMRHandler::ProcessCommandL
+// -----------------------------------------------------------------------------
+//
+void CMRHandler::ProcessCommandL( TInt aCommandId )
+	{
+	ProcessCommandWithResultL( aCommandId );
+	}
+
+// -----------------------------------------------------------------------------
+// CMRHandler::ProcessTrappedModifCmdL
+// Commands which may modify entry(s) and should be placed inside a TRAP to
+// ensure that data gets refreshed also in case a leave occurs when processing
+// command.
+// -----------------------------------------------------------------------------
+//
+TInt CMRHandler::ProcessTrappedModifCmdL( TInt aCommandId )
+    {
+    LOG("CMRHandler::ProcessTrappedModifCmdL");
+    TInt retVal( KErrNone );
+    
+	switch( aCommandId )
+		{    
+		case EMRCommandSend:
+		case EMRCommandSendUpdate:
+		    { // do send request or update
+		    retVal = iCmdHandler->SendL( aCommandId );
+			break;
+		    }
+		case EMRCommandCancelMR:
+		    { // do cancel request
+		    retVal = iCmdHandler->CancelMRL();
+			break;
+		    }
+		case EMRCommandDeleteMR:
+		    { // do delete request
+            retVal = iCmdHandler->DeleteMRL();
+			break;
+		    }		    
+		case EMRCommandRespondAccept:
+		case EMRCommandRespondTentative: // fall through
+		case EMRCommandRespondDecline:   // fall through
+			{
+			//do respond to organiser
+			iCmdHandler->CreateResponseL( iEntries, aCommandId );
+			break;
+			}
+		case EMRCommandSaveAndExit:
+		    {
+		    iCmdHandler->SaveL();
+		    break;
+		    }		    
+		case EMRCommandSave:
+		    {
+		    iCmdHandler->SaveL();
+		    break;
+		    }		    				    
+		case EMRCommandDisableAlarm:
+			{
+			iCmdHandler->DisableAlarmL( iEntries );
+			break;
+			}
+		case EMRCommandRemoveFromCalendar:
+			{
+			iCmdHandler->RemoveFromCalendarL( iEntries );
+			break;
+			}
+		case EMRCommandSaveFromFile:
+		    {
+		    iCmdHandler->SaveFromFileL( iEntries );
+		    break;
+		    }
+        default:
+            {
+            User::Leave( KErrNotSupported );
+            }
+		}
+    LOG("CMRHandler::ProcessTrappedModifCmdL -> End");		
+    return retVal;
+    }
+
+// -----------------------------------------------------------------------------
+// CMRHandler::SetHelpContext
+// -----------------------------------------------------------------------------
+//
+void CMRHandler::SetHelpContext( const TCoeHelpContext& /*aContext*/ )
+	{
+	}
+
+// -----------------------------------------------------------------------------
+// CMRHandler::ShowOpeningNoteL
+// -----------------------------------------------------------------------------
+//
+void CMRHandler::ShowOpeningNoteL()
+	{
+	HBufC* openingNote = NULL;
+
+	if ( !iModel )
+	    { // error has occurred since model hasn't been created
+	    // TODO: implement error note or other way of handling the error
+	    }
+    else
+        {
+    	openingNote = iModel->MailboxOpeningNoteL();
+        }
+
+	if ( openingNote )
+		{
+		CleanupStack::PushL( openingNote );
+		CAknGlobalNote* globalNote = CAknGlobalNote::NewLC();
+		globalNote->ShowNoteL( EAknGlobalInformationNote, *openingNote );
+		CleanupStack::PopAndDestroy( globalNote );
+		CleanupStack::PopAndDestroy( openingNote );
+		}
+	}
+
+// -----------------------------------------------------------------------------
+// CMRHandler::HandleEngReadyL
+// -----------------------------------------------------------------------------
+//
+void CMRHandler::HandleEngReadyL(
+    const TDesC8& /*aMtmUid*/,
+    CMRUtilsInternal& aMRUtils,
+    CMRMailboxUtils& aMRMailboxUtils )
+    {
+    // this method should only get called once
+    __ASSERT_DEBUG( !iCmdHandler && !iModel, Panic( EUnexpectedNonNull ) );
+                    
+    LOG("CMRHandler::HandleEngReadyL, creating iModel");
+    iModel = CMRObjectFactory::CreateMRModelL( iEntries, 
+                                               iInParams, 
+                                               aMRMailboxUtils,
+                                               aMRUtils );
+
+    #ifdef ICALUI_ENABLE_MRDATA_LOGGING
+        LogAvailableFunctionsL();
+    #endif
+
+    LOG("CMRHandler::HandleEngReadyL, creating iCmdHandler");
+    iCmdHandler = CMRCmdHandler::NewL( *iModel,
+                                       iInParams,
+                                       aMRMailboxUtils,
+                                       aMRUtils );
+
+    iCurrentDialog->SetModel( *iModel );
+
+    if ( IsCommandAvailable( EMRCommandUnreadOpeningNote ) )
+        {            
+    	// TODO: if combinedEntry is NULL, then there was some error.
+    	// ShowOpeningNoteL() should take care of notifying user in this case.
+    	ShowOpeningNoteL();
+        }
+	}
+
+// -----------------------------------------------------------------------------
+// CMRHandler::ExecuteViewL
+// -----------------------------------------------------------------------------
+//
+TInt CMRHandler::ExecuteViewL()
+	{
+    LOG("CMRHandler::ExecuteViewL");
+	// Even if there are multiple entries, method is the same for all:
+	CCalEntry::TMethod method = iEntries[0]->MethodL();
+
+    // for returning from attendee view or calendar editor
+    TMRViewStatus previousView( EInitialView ); 
+
+	TInt returnCode( KErrNone );
+	while ( iStatus != ECloseMeetingRequestViews )
+		{
+		if ( iStatus == EInitialView ||
+		     iStatus == ELaunchMeetingRequestView ||
+		     iStatus == ELaunchMeetingDescriptionView )
+		    {
+		    previousView = iStatus;
+		    
+            LOG("CMRHandler::ExecuteViewL, creating dialog");
+			iCurrentDialog = CMRObjectFactory::CreateMRDialogL( method,
+			                                                    iInParams,
+			                                                    *this,
+			                                                    iStatus );
+		    if ( iModel )
+		        { // Set model if it is already available
+		            LOG("CMRHandler::ExecuteViewL, setting model");
+		        iCurrentDialog->SetModel( *iModel );
+		        }
+		    LOG("CMRHandler::ExecuteViewL, executing dialog");
+			returnCode = iCurrentDialog->ExecuteLD();
+			iCurrentDialog = NULL;
+		    }		
+		else if ( iStatus == ELaunchAttendeeView )
+		    {
+			returnCode = ExecuteAttendeeViewL();
+			//return to the view the attendee view was launched from
+			iStatus = previousView;		    
+		    }
+        else if ( iStatus == ELaunchMeetingEditorView )
+            {
+			returnCode = ExecuteEditorViewL();
+			//return to the view the editor was launched from
+			iStatus = previousView;            
+            }
+		}
+    LOG("CMRHandler::ExecuteViewL -> End");
+	return returnCode;
+	}
+
+// -----------------------------------------------------------------------------
+// CMRHandler::ExecuteEditorViewL
+// -----------------------------------------------------------------------------
+//
+TInt CMRHandler::ExecuteEditorViewL()
+    {
+    QueryAndSetEditingModeL();    
+    
+    RPointerArray<CCalEntry> tmpArray( 1 );
+    CleanupClosePushL( tmpArray ); // only close, doesn't own it's entry
+    tmpArray.AppendL( iModel->CombinedEntry() );
+    TInt retVal = iCalendarEditorsPlugin->ExecuteViewL( tmpArray,
+                                                        iInParams, 
+                                                        iOutParams, 
+                                                        *this );
+    if ( retVal == KErrNone &&
+         iOutParams.iAction == MAgnEntryUi::EMeetingSaved )
+        {
+        iModel->SetEntryEdited();
+        }
+    CleanupStack::PopAndDestroy(); // tmpArray
+    return retVal;
+    }
+
+// -----------------------------------------------------------------------------
+// CMRHandler::ExecuteAttendeeViewL
+// -----------------------------------------------------------------------------
+//
+TInt CMRHandler::ExecuteAttendeeViewL()
+	{
+	User::Leave( KErrNotSupported );
+	return KErrNotSupported;
+	
+	/*
+	QueryAndSetEditingModeL();	
+	CAttendeeView::TAttendeeViewMode mode( CAttendeeView::EViewer );
+	if ( iModel->EditingMode() != MMRModelInterface::EViewOnly )
+		{
+        mode = CAttendeeView::EEditor;
+		}
+	
+	// TODO: we may get into trouble if combined entry changes while
+	// attendee view is still running -> we might need to use another
+	// copy with attendee view
+	
+    CCalEntry* entry = iModel->CombinedEntry();
+    
+    // TODO: currently we don't resolve phone owner addr, when
+	// attendee view API has been changed we might instantiate attendee
+	// view already e.g. in HandleEngReadyL(). Fix this then...
+	const TDesC& address = KNullDesC;
+	    //MREntryConsultant::PhoneOwnerAddrL( *entry, *iMRMailboxUtils );
+
+	TInt filters( 0 );
+	// TODO: Attendee view should support individual Accept/Tentative/Decline cmds
+	if ( iModel->IsCmdAvailable( EMRCommandRespondAccept ) )
+		{
+		filters =+ CAttendeeView::ERespond;
+		}
+	if ( iInParams.iCallingApp.iUid == KUidCalendarApplication )
+		{
+		if ( iModel->IsCmdAvailable( EMRCommandSend ) )
+		    {
+		    filters =+ CAttendeeView::ESend;
+		    }
+		if ( iModel->IsCmdAvailable( EMRCommandSendUpdate ) )
+		    {
+		    filters =+ CAttendeeView::ESendUpdate;
+		    }
+		if ( iModel->IsCmdAvailable( EMRCommandCancelMR ) )
+		    {
+		    filters =+ CAttendeeView::ECancelation;
+		    }
+		}
+	CAttendeeView::TMenuFilterFlags menuFilter(
+	    static_cast<CAttendeeView::TMenuFilterFlags>( filters ) );
+	    
+    // Unfortunately we need to create initParams in heap since
+    // attendee view wants to take it's ownership
+	CAttendeeView::TAttendeeViewInit* initParams =
+	    new( ELeave ) CAttendeeView::TAttendeeViewInit(
+	        *entry, mode, CONST_CAST( TDesC&, address ), *this );
+    CleanupStack::PushL( initParams );
+	initParams->SetMenuFilter( menuFilter );
+	
+	CAttendeeView* attendeeView = CAttendeeView::NewL( initParams );
+	CleanupStack::Pop(); // initParams, ownership transferred
+    CleanupStack::PushL( attendeeView );
+	
+	TInt retVal = attendeeView->ExecuteL();
+	
+	// Note: without calling IsEntryEditedL() attendee view
+	// wouldn't update the input entry!
+    if ( attendeeView->IsEntryEditedL() )
+        {
+        iModel->SetEntryEdited();
+        }
+    CleanupStack::PopAndDestroy( attendeeView );
+    
+    return retVal;
+    */
+	}
+
+// -----------------------------------------------------------------------------
+// CMRHandler::RefreshViewL
+// -----------------------------------------------------------------------------
+//
+void CMRHandler::RefreshViewL()
+    {
+    if ( iCurrentDialog )
+        {
+        iModel->RefreshViewableEntryL();
+        iCurrentDialog->RefreshData();
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CMRHandler::QueryAndSetEditingModeL
+// -----------------------------------------------------------------------------
+//
+void CMRHandler::QueryAndSetEditingModeL()
+    {
+    if ( iModel->EditingMode() == MMRModelInterface::EModeNotSet )
+        {
+        CAknQueryDialog* dlg = CAknQueryDialog::NewL();
+        // TODO: replace this with Calendar Utils query when available
+        _LIT(KQueryText,"Edit series instead of instance?");
+        CleanupStack::PushL( dlg );
+        dlg->SetPromptL( KQueryText );
+        CleanupStack::Pop( dlg );
+        if ( dlg->ExecuteLD( R_GENERAL_CONFIRMATION_QUERY ) )
+            {
+            iModel->SetEditingModeL( MMRModelInterface::EEditMeeting );
+            }
+        else
+            {
+            iModel->SetEditingModeL( MMRModelInterface::EEditInstance );
+            }
+        }
+    }
+    
+// -----------------------------------------------------------------------------
+// CMRHandler::LogAvailableFunctionsL
+// This method is for testing purposes only, and should not be called in real
+// builds to avoid caused overhead.
+// Not all commands listed in MRCommands.hrh are checked here, only the ones
+// that are feasible. Furthermore, this may not correspond 100% to the items
+// visible in the options menu, these results reflect only model's opinion.
+// -----------------------------------------------------------------------------
+//
+void CMRHandler::LogAvailableFunctionsL() const
+    {
+    TBool res( EFalse );    
+    MRDATA_LOG("# start function availability check #");    
+    res = iModel->IsCmdAvailable( EMRCommandRespondAccept );
+    MRDATA_LOG1("can EMRCommandRespondAccept: %d", res );
+    res = iModel->IsCmdAvailable( EMRCommandRespondTentative );
+    MRDATA_LOG1("can EMRCommandRespondTentative: %d", res );
+    res = iModel->IsCmdAvailable( EMRCommandRespondDecline );
+    MRDATA_LOG1("can EMRCommandRespondDecline: %d", res );
+    res = iModel->IsCmdAvailable( EMRCommandReplyToSender );
+    MRDATA_LOG1("can EMRCommandReplyToSender: %d", res );
+    res = iModel->IsCmdAvailable( EMRCommandReplyToOrganiser );
+    MRDATA_LOG1("can EMRCommandReplyToOrganiser: %d", res );
+    res = iModel->IsCmdAvailable( EMRCommandReplyToAll );
+    MRDATA_LOG1("can EMRCommandReplyToAll: %d", res );
+    res = iModel->IsCmdAvailable( EMRCommandForward );
+    MRDATA_LOG1("can EMRCommandForward: %d", res );
+    res = iModel->IsCmdAvailable( EMRCommandRetrieve );
+    MRDATA_LOG1("can EMRCommandRetrieve: %d", res );
+    res = iModel->IsCmdAvailable( EMRCommandRemoveFromCalendar );
+    MRDATA_LOG1("can EMRCommandRemoveFromCalendar: %d", res );
+    res = iModel->IsCmdAvailable( EMRCommandShowCalendar );
+    MRDATA_LOG1("can EMRCommandShowCalendar: %d", res );
+    res = iModel->IsCmdAvailable( EMRCommandAttachments );
+    MRDATA_LOG1("can EMRCommandAttachments: %d", res );
+    res = iModel->IsCmdAvailable( EMRCommandMessageDetails );
+    MRDATA_LOG1("can EMRCommandMessageDetails: %d", res );
+    res = iModel->IsCmdAvailable( EMRCommandDisableAlarm );
+    MRDATA_LOG1("can EMRCommandDisableAlarm: %d", res );    
+    res = iModel->IsCmdAvailable( EMRCommandSaveFromFile );
+    MRDATA_LOG1("can EMRCommandSaveFromFile: %d", res );    
+    res = iModel->IsCmdAvailable( EMRCommandSend );
+    MRDATA_LOG1("can EMRCommandSend: %d", res );    
+    res = iModel->IsCmdAvailable( EMRCommandSendUpdate );
+    MRDATA_LOG1("can EMRCommandSendUpdate: %d", res );
+    res = iModel->IsCmdAvailable( EMRCommandDeleteMR );
+    MRDATA_LOG1("can EMRCommandDeleteMR: %d", res );       
+    MRDATA_LOG("# end function availability check #");        
+    }
+    
+//  End of File