// ---------------------------------------------------------------------------
// CJavaApplicationService::IsSwInIdle
// ---------------------------------------------------------------------------
TBool CJavaApplicationService::IsSwInIdle(TInt aValue)
    {
    _DMEVNT_DEBUG(_L("CJavaApplicationService::IsSwInIdle, value = %d >> "), aValue);
    TBool ret (EFalse);

    TInt operation(aValue & KJavaOperationMask);
    TInt operationStatus(aValue & KJavaStatusMask);


    _DMEVNT_DEBUG(_L("operation %d, status %d"), operation, operationStatus);

    if (EJavaStatusSuccess == operationStatus) 
        {
        switch (operation)
            {
            case EJavaInstall:
                {
                _DMEVNT_DEBUG(_L("Uninstallation in progress"));
                iOperation = EOpnInstall;
                }
                break;
            case EJavaUninstall:
                {
                _DMEVNT_DEBUG(_L("Restore in progress"));
                iOperation = EOpnUninstall;
                }
                break;
            default:
                {
                _DMEVNT_DEBUG(_L("Unknown operation"));
                iOperation = EOpnUnknown;
                }
            }
        }

    ret = (operation != Swi::ESwisNone)? ETrue:EFalse;

    _DMEVNT_DEBUG(_L("CJavaApplicationService::IsSwInIdle, ret = %d << "),ret);
    return ret;
    }
/* expected hook, this is where custom stuff happens */
PAM_EXTERN int pam_sm_authenticate(pam_handle_t* pamh, int flags, int argc, const char **argv) {
    int ret = 0;

    const char *pUsername = NULL;
    const char *pAccountId = NULL;
    const char *pOperation = NULL;
    const char *pSecretKey = NULL;
    const char *pAppId = NULL;
    const char *pOperationId = NULL;
    const char *pAccounts = NULL;
    const char *pConfig = NULL;
    const char *pOtp = NULL;
    const char *pHost = NULL;
    const char *pTimeout = NULL;
    char *pDefaultOption = NULL;
    char *buffer;
    int timeout = 2;
    int default_option = PAM_SUCCESS;
    int res =  PAM_SUCCESS;
    char *otp = NULL;


    struct pam_message msg[1],*pmsg[1];
    struct pam_response *resp;

    // setting up conversation call prompting for one-time code
    pmsg[0] = &msg[0] ;
    msg[0].msg_style = PAM_PROMPT_ECHO_ON ;
    msg[0].msg = "One-time code: " ;
    resp = NULL ;


    if (pam_get_user(pamh, &pUsername, NULL) != PAM_SUCCESS) {
        return PAM_AUTH_ERR;
    }

    pAccounts = getArg("accounts", argc, argv);
    if (!pAccounts) {
        pAccounts = DEFAULT_LATCH_ACCOUNTS_FILE;
    }

    pAccountId = getAccountId(pUsername, pAccounts);
    if (pAccountId == NULL) {
        return PAM_SUCCESS;
    }

    pConfig = getArg("config", argc, argv);
    if (!pConfig) {
        pConfig = DEFAULT_LATCH_CONFIG_FILE;
    }

    pOperation = getArg("operation", argc, argv);
    if (!pOperation) {
        pOperationId = NULL;
    } else {
        pOperationId = getConfig(OPERATION_ID_LENGTH, pOperation, pConfig);
        if (pOperationId == NULL) {
            send_syslog_alert("PAM", "Latch-auth-pam error: Failed to find operation");
            perror("Failed to find operation");
            return PAM_SUCCESS;
        }
    }

    pOtp = getArg("otp", argc, argv);
    if (!pOtp) {
        pOtp = "no";
    }

    pDefaultOption = (char *)getConfig(DEFAULT_OPTION_MAX_LENGTH, "action", pConfig);
    if (pDefaultOption == NULL) {
        pDefaultOption = malloc(4 + 1);
        memset(pDefaultOption, 0, 4 + 1);
        strncpy(pDefaultOption, "open", 4);
    } else if (strcmp(pDefaultOption,"open") != 0 && strcmp(pDefaultOption,"close") != 0){
        pDefaultOption = realloc(pDefaultOption, 4 + 1);
        memset(pDefaultOption, 0, 4 + 1);
        strncpy(pDefaultOption, "open", 4);
    }

    if (strcmp(pDefaultOption,"open") == 0) {
        default_option = PAM_SUCCESS;
    } else {
        default_option = PAM_AUTH_ERR;
    }
    free(pDefaultOption);

    pAppId = getConfig(APP_ID_LENGTH, "app_id", pConfig);
    pSecretKey = getConfig(SECRET_KEY_LENGTH, "secret_key", pConfig);

    if(pAppId == NULL || pSecretKey == NULL || strcmp(pAppId, "") == 0 || strcmp(pSecretKey, "") == 0){
        send_syslog_alert("PAM", "Latch-auth-pam error: Failed to read \"latch.conf\"");
        perror("Failed to read \"latch.conf\"");
        free((char*)pAccountId);
        free((char*)pOperationId);
        return PAM_SUCCESS;
    }

    pHost = getConfig(MAX_SIZE, "latch_host", pConfig);
    if(pHost == NULL) {
        pHost = malloc(LATCH_API_HOST_LENGTH + 1);
        memset((char*)pHost, 0, LATCH_API_HOST_LENGTH + 1);
        strncpy((char*)pHost, LATCH_API_HOST, LATCH_API_HOST_LENGTH);
    }

    pTimeout = getConfig(TIMEOUT_MAX_LENGTH, "timeout", pConfig);
    if(pTimeout == NULL || ((timeout = atoi(pTimeout)) < TIMEOUT_MIN) || timeout > TIMEOUT_MAX) {
        timeout = 2;
    }
    free((char*)pTimeout);

    if (drop_privileges(0)) {
        send_syslog_alert("PAM", "Latch-auth-pam error: Couldn't drop privileges");
    }

    init(pAppId, pSecretKey);
    setHost(pHost);
    setTimeout(timeout);

    if (pOperationId != NULL) {
        buffer = operationStatus(pAccountId, pOperationId);
    } else {
        buffer = status(pAccountId);
    }
    free((char*)pAppId);
    free((char*)pSecretKey);
    free((char*)pAccountId);
    free((char*)pOperationId);
    free((char*)pHost);

    if (restore_privileges()) {
        send_syslog_alert("PAM", "Latch-auth-pam error: Couldn't restore privileges");
    }

    if(buffer == NULL || strcmp(buffer,"") == 0){
        free(buffer);
        return default_option;
    }

    if (strstr(buffer, "\"status\":\"off\"") != NULL){
        fprintf (stderr, "AUTH-PAM: latch locked\n");
        send_syslog_alert("PAM", "Latch-auth-pam warning: Someone tried to access. Latch locked");
        res = PAM_AUTH_ERR;

    }else if (strstr(buffer, "\"status\":\"on\"") != NULL) {

        if(strncmp(pOtp, "yes", 3) == 0){

            char *pch;
            if((pch = strstr(buffer, "\"two_factor\"")) != NULL){
                char code[OTP_LENGTH];
                memset(code, 0, OTP_LENGTH);

                strncpy (code, pch + strlen("\"two_factor\":{\"token\":\""), OTP_LENGTH);

                otp = get_response(pamh, "One-time password", 1);

                // comparing user input with known code
                if(strncmp(code, otp, OTP_LENGTH) != 0  || strlen(otp) != OTP_LENGTH){
                    send_syslog_alert("PAM", "Latch-auth-pam warning: Someone tried to access. Bad OTP");
                    res = PAM_AUTH_ERR;
                } else {
                    res = PAM_SUCCESS;
                }
            }

        }else{
            res = PAM_SUCCESS;
        }
    }

    free(buffer);
    return res;
}
void RegisterCommand::watcher()
{
	gg_pubdir* pubDir;

	if ( state == RegisterStateWaitingForToken  ) {
		disableNotifiers();
		if ( gg_token_watch_fd( session_ ) == -1 ) {
			deleteNotifiers();
			emit error( i18n( "Gadu-Gadu" ), i18n( "Unknown connection error while retrieving token." ) );
			gg_token_free( session_ );
			session_ = NULL;
			state = RegisterStateNoToken;
			return;
		}

		pubDir = (struct gg_pubdir *)session_->data;
		emit operationStatus( i18n( "Token retrieving status: %1", GaduSession::stateDescription( session_->state ) ) );
		switch ( session_->state ) {
			case GG_STATE_CONNECTING:
				kDebug( 14100 ) << "Recreating notifiers ";
				deleteNotifiers();
				checkSocket( session_->fd, 0);
				break;
			case GG_STATE_ERROR:
				deleteNotifiers();
				emit error( i18n( "Gadu-Gadu token retrieve problem" ), GaduSession::errorDescription(  session_->error )  );
				gg_token_free( session_ );
				session_ = NULL;
				state = RegisterStateNoToken;
				return;
				break;
			case GG_STATE_DONE:
				struct gg_token* sp = ( struct gg_token* )session_->data;
				tokenId = (char *)sp->tokenid;
				kDebug( 14100 ) << "got Token!, ID: " << tokenId;
				deleteNotifiers();
				if ( pubDir->success ) {
					QPixmap tokenImg;
					tokenImg.loadFromData( (const unsigned char *)session_->body, session_->body_size );
					state = RegisterStateGotToken;
					emit tokenRecieved( tokenImg, tokenId );
				}
				else {
					emit error( i18n( "Gadu-Gadu" ), i18n( "Unable to retrieve token." ) );
					state = RegisterStateNoToken;
					deleteLater();
				}
				gg_token_free( session_ );
				session_ = NULL;
				disconnect( this, SLOT(watcher()) );
				return;
				break;
		}
		enableNotifiers( session_->check );
	}
	if ( state == RegisterStateWaitingForNumber ) {
		disableNotifiers();
		if ( gg_register_watch_fd( session_ ) == -1 ) {
			deleteNotifiers();
			emit error( i18n( "Gadu-Gadu" ), i18n( "Unknown connection error while registering." ) );
			gg_free_register( session_ );
			session_ = NULL;
			state = RegisterStateGotToken;
			return;
		}
		pubDir = (gg_pubdir*) session_->data;
		emit operationStatus( i18n( "Registration status: %1", GaduSession::stateDescription( session_->state ) ) );
		switch ( session_->state ) {
			case GG_STATE_CONNECTING:
				kDebug( 14100 ) << "Recreating notifiers ";
				deleteNotifiers();
				checkSocket( session_->fd, 0);
				break;
			case GG_STATE_ERROR:
				deleteNotifiers();
				emit error( i18n( "Gadu-Gadu Registration Error" ), GaduSession::errorDescription(  session_->error ) );
				gg_free_register( session_ );
				session_ = NULL;
				state = RegisterStateGotToken;
				return;
				break;

			case GG_STATE_DONE:
				deleteNotifiers();
				if ( pubDir->success && pubDir->uin ) {
					uin= pubDir->uin;
					state = RegisterStateDone;
					emit done( i18n( "Registration Finished" ), i18n( "Registration has been completed successfully." ) );
				}
				else {
					emit error( i18n( "Registration Error" ), i18n( "Incorrect data sent to server." ) );
					state = RegisterStateGotToken;
				}
				gg_free_register( session_ );
				session_ = NULL;
				disconnect( this, SLOT(watcher()) );
				deleteLater();
				return;
				break;
		}
		enableNotifiers( session_->check );
		return;
	}
}
int latch_overlay_check_latch(latch_overlay_config_data *cfg, char *id) {

    int rc = LATCH_STATUS_UNKNOWN;
    char *account_id = NULL;
    char *response = NULL;
    json_object *json_response = NULL;
    json_object *json_data = NULL;
    json_object *json_operations = NULL;
    json_object *json_application = NULL;
    json_bool json_application_rc = FALSE;
    json_object *json_status = NULL;

    Log1(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, ">>> %s\n", __func__);

    if (latch_overlay_get_account_id(cfg, id, &account_id) != ERROR) {

        if (account_id != NULL) {

            Log2(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, "    %s: account_id %s\n", __func__, account_id);

            if (cfg->operation_id == NULL) {
                response = status(account_id);
            } else {
                response = operationStatus(account_id, cfg->operation_id);
            }

            if (response != NULL) {

                Log2(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, "    %s: response %s\n", __func__, response);

                json_response = json_tokener_parse(response);

                if (json_response != NULL) {

                    if ((json_object_object_get_ex(json_response, "data", &json_data) == TRUE) && (json_data != NULL)) {

                        if ((json_object_object_get_ex(json_data, "operations", &json_operations) == TRUE) && (json_operations != NULL)) {

                            if (cfg->operation_id == NULL) {
                                json_application_rc = json_object_object_get_ex(json_operations, cfg->application_id, &json_application);
                            } else {
                                json_application_rc = json_object_object_get_ex(json_operations, cfg->operation_id, &json_application);
                            }

                            if ((json_application_rc) == TRUE && (json_application != NULL)) {
                                if ((json_object_object_get_ex(json_application, "status", &json_status) == TRUE) && (json_status != NULL)) {
                                    if (json_object_get_string(json_status) != NULL && strcmp("off", json_object_get_string(json_status)) == 0) {
                                        rc = LATCH_STATUS_LOCKED;
                                    } else if (json_object_get_string(json_status) != NULL && strcmp("on", json_object_get_string(json_status)) == 0) {
                                        rc = LATCH_STATUS_UNLOCKED;
                                    }
                                }
                            }

                        }

                    }

                    json_object_put(json_response);

                }

                free(response);

            } else {
                Log1(LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, "    %s: There has been an error communicating with the backend\n", __func__);
            }

            free(account_id);

            if ((rc == LATCH_STATUS_UNKNOWN) && (cfg->sdk_stop_on_error == 1)) {
                Log1(LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, "    %s: No valid response from backend but is required. Returning LATCH_STATUS_LOCKED\n", __func__);
                rc = LATCH_STATUS_LOCKED;
            }

        } else {
            if (cfg->required == 1) {
                Log1(LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, "    %s: User is not paired but Latch is required. Returning LATCH_STATUS_LOCKED\n", __func__);
                rc = LATCH_STATUS_LOCKED;
            }
        }

    } else {
        if (cfg->ldap_stop_on_error == 1) {
            Log1(LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, "    %s: No valid response from the LDAP server but is required. Returning LATCH_STATUS_LOCKED\n", __func__);
            rc = LATCH_STATUS_LOCKED;
        }
    }

    Log1(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, "<<< %s\n", __func__);

    return rc;

}